[rhq] modules/enterprise
by ips
modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java | 32 +++++++---
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java | 32 +++-------
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java | 29 ++++-----
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java | 21 +++---
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LogoutCommand.java | 4 -
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java | 4 -
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java | 7 +-
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ScriptCommand.java | 6 -
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java | 6 +
9 files changed, 75 insertions(+), 66 deletions(-)
New commits:
commit 48eab9a4fc98505c845f2c8d695312b7cc6a6674
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Wed Feb 1 14:31:11 2012 -0500
when a commands are passed invalid options, print an error message and the command's usage - do not print a stack trace
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
index 94a4d05..1809e39 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
@@ -64,6 +64,7 @@ public class TabularWriter {
private CSVWriter csvWriter;
private SummaryFilter summaryFilter = new SummaryFilter();
boolean exportMode;
+ boolean hideRowCount;
static Set<String> IGNORED_PROPS = new HashSet<String>();
@@ -115,6 +116,10 @@ public class TabularWriter {
}
}
+ public void setHideRowCount(boolean hideRowCount) {
+ this.hideRowCount = hideRowCount;
+ }
+
public void print(Object object) {
if (object instanceof Map) {
@@ -305,15 +310,18 @@ public class TabularWriter {
public void print(Collection list) {
// List of arbitrary objects
- if (list == null || list.size() == 0)
- out.println("no data");
- else if (list.size() == 1 && !CSV.equals(format)) {
- out.println("one row");
+ if (list == null || list.size() == 0) {
+ if (!hideRowCount) {
+ out.println("0 rows");
+ }
+ } else if (list.size() == 1 && !CSV.equals(format)) {
+ if (!hideRowCount) {
+ out.println("one row");
+ }
print(list.iterator().next());
} else {
-
- String[][] data = null;
+ String[][] data;
if (!allOneType(list)) {
printStrings(list);
@@ -550,7 +558,9 @@ public class TabularWriter {
public void print(Object[] data) {
if (data == null || data.length == 0) {
- out.println("0 rows");
+ if (!hideRowCount) {
+ out.println("0 rows");
+ }
return;
}
out.println("Array of " + (data.getClass().getComponentType().getName()));
@@ -592,7 +602,9 @@ public class TabularWriter {
public void print(String[][] data) {
if (data == null || data.length == 0) {
- out.println("0 rows");
+ if (!hideRowCount) {
+ out.println("0 rows");
+ }
return;
}
@@ -661,7 +673,9 @@ public class TabularWriter {
}
}
- out.print(data.length + " rows\n");
+ if (!hideRowCount) {
+ out.print(data.length + " rows\n");
+ }
}
private void printSpaced(PrintWriter out, String data, int length) {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
index d42fc6d..7323ecd 100755
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
@@ -45,6 +45,7 @@ import mazz.i18n.Msg;
import org.rhq.core.domain.auth.Subject;
import org.rhq.enterprise.client.commands.ClientCommand;
import org.rhq.enterprise.client.commands.ScriptCommand;
+import org.rhq.enterprise.client.script.CommandLineParseException;
import org.rhq.enterprise.clientapi.RemoteClient;
/**
@@ -273,14 +274,8 @@ public class ClientMain {
ClientCommand command = commands.get(cmd);
if (shouldDisplayHelp(args)) {
- outputWriter.println("syntax: " + command.getSyntax());
- outputWriter.println("description: " + command.getHelp() + "\n");
- return true;
- }
-
- if (shouldDisplayDetailedHelp(args)) {
- outputWriter.println("syntax: " + command.getSyntax());
- outputWriter.println("description: " + command.getDetailedHelp() + "\n");
+ outputWriter.println("Usage: " + command.getSyntax());
+ outputWriter.println(command.getDetailedHelp());
return true;
}
@@ -289,9 +284,12 @@ public class ClientMain {
processNotes(outputWriter);
outputWriter.println("");
return response;
+ } catch (CommandLineParseException e) {
+ outputWriter.println(command.getPromptCommandString() + ": " + e.getMessage());
+ outputWriter.println("Usage: " + command.getSyntax());
} catch (ArrayIndexOutOfBoundsException e) {
- outputWriter.println("An incorrect number of arguments was specified.");
- outputWriter.println("Expected syntax: " + command.getSyntax());
+ outputWriter.println(command.getPromptCommandString() + ": An incorrect number of arguments was specified.");
+ outputWriter.println("Usage: " + command.getSyntax());
}
} else {
boolean result = commands.get("exec").execute(this, args);
@@ -309,15 +307,7 @@ public class ClientMain {
return false;
}
- return args[1].equals("-h");
- }
-
- private boolean shouldDisplayDetailedHelp(String[] args) {
- if (args.length < 2) {
- return false;
- }
-
- return args[1].equals("--help");
+ return args[1].equals("-h") || args[1].equals("--help");
}
/**
@@ -585,8 +575,8 @@ public class ClientMain {
*
* These notes are meant to be terse, and pasted/purged at the end of every command execution.
*
- * @param note
- * String. Ex."There were errors retrieving some data from the server objects. See System Admin."
+ * @param note the note to be displayed, e.g. "There were errors retrieving some data from the server objects. See
+ * System Admin."
*/
public void addMenuNote(String note) {
if ((note != null) && (note.trim().length() > 0)) {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
index 6366b6e..4676730 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
@@ -55,9 +55,10 @@ public class HelpCommand implements ClientCommand {
data[i][0] = name;
data[i++][1] = command.getHelp();
}
+
TabularWriter tw = new TabularWriter(client.getPrintWriter(), "Command", "Description");
tw.setWidth(client.getConsoleWidth());
-
+ tw.setHideRowCount(true);
tw.print(data);
} else if ("api".equals(args[1])) {
Map<String, Object> services = client.getRemoteClient().getManagers();
@@ -131,18 +132,18 @@ public class HelpCommand implements ClientCommand {
tw.print(data);
} else {
client.getPrintWriter().println(
- "Unknown service [" + args[2] + "] try 'help api' for a listing of services");
+ "Unknown service [" + args[2] + "] - try 'help api' for a listing of services");
}
}
} else {
- ClientCommand cmd = commands.get(args[1]);
- if (cmd == null) {
- client.getPrintWriter().println("Uknown command [" + args[1] + "]");
+ String commandName = args[1];
+ ClientCommand command = commands.get(commandName);
+ if (command == null) {
+ client.getPrintWriter().println(getPromptCommandString() + ": Unknown command: " + commandName);
} else {
- client.getPrintWriter().println("Help [" + args[1] + "]");
- client.getPrintWriter().println("Syntax [" + cmd.getSyntax() + "]");
- client.getPrintWriter().println(cmd.getDetailedHelp());
+ client.getPrintWriter().println("Usage: " + command.getSyntax());
+ client.getPrintWriter().println(command.getDetailedHelp());
}
}
@@ -150,16 +151,16 @@ public class HelpCommand implements ClientCommand {
}
public String getSyntax() {
- return "help [command] | [api [service]]";
+ return getPromptCommandString() + " [command] | [api [service]]";
}
public String getHelp() {
- return "Help on the client and its commands";
+ return "Display help on CLI commands or services";
}
public String getDetailedHelp() {
- return "Use help [command] to get detailed help\n"
- + "help api will return the list of service apis available for script execs\n"
- + "help api [service] will display the methods and signatures of a specific api";
+ return "Use \"help [command]\" to get detailed help for a command\n"
+ + "\"help api\" will return the list of service APIs available for script execs\n"
+ + "\"help api [service]\" will list the methods provided by the specified service API";
}
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
index 2e3dbed..72bd8e1 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
@@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.common.ProductInfo;
import org.rhq.enterprise.client.ClientMain;
+import org.rhq.enterprise.client.script.CommandLineParseException;
import org.rhq.enterprise.clientapi.RemoteClient;
/**
@@ -44,22 +45,22 @@ public class LoginCommand implements ClientCommand {
}
public boolean execute(ClientMain client, String[] args) {
- String user = null;
- String pass = null;
+ if (args.length < 3) {
+ throw new CommandLineParseException("Too few arguments");
+ }
+ if (args.length > 7) {
+ throw new CommandLineParseException("Too many arguments");
+ }
+
+ String user = args[1];
+ String pass = args[2];
String host = "localhost";
String transport = null;
int port = 7080;
PrintWriter printWriter = client.getPrintWriter();
- if (args.length<3) {
- printWriter.println(usage());
- return true;
- }
try {
- user = args[1];
- pass = args[2];
-
if (args.length == 5) {
host = args[3];
port = Integer.parseInt(args[4]);
@@ -133,7 +134,7 @@ public class LoginCommand implements ClientCommand {
}
public String getSyntax() {
- return "login username password [host port [transport]]";
+ return getPromptCommandString() + " username password [host port [transport]]";
}
public String getHelp() {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LogoutCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LogoutCommand.java
index c764bab..6966508 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LogoutCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LogoutCommand.java
@@ -48,11 +48,11 @@ public class LogoutCommand implements ClientCommand {
}
public String getSyntax() {
- return "logout";
+ return getPromptCommandString();
}
public String getHelp() {
- return "Logout and disconnect from the server but does not exit the CLI interpreter";
+ return "Logout and disconnect from the server but do not exit the CLI";
}
public String getDetailedHelp() {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
index 8640599..1aa3b90 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
@@ -34,11 +34,11 @@ public class QuitCommand implements ClientCommand {
}
public String getSyntax() {
- return "quit";
+ return getPromptCommandString();
}
public String getHelp() {
- return "Exit the CLI interpreter";
+ return "Exit the CLI";
}
public String getDetailedHelp() {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
index 468076e..1e32092 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
@@ -64,7 +64,8 @@ public class RecordCommand implements ClientCommand {
new LongOpt("start", LongOpt.OPTIONAL_ARGUMENT, null, 'b'),
new LongOpt("end", LongOpt.OPTIONAL_ARGUMENT, null, 'e')
};
- Getopt getopt = new Getopt("exec", args, shortOpts, longOpts);
+ Getopt getopt = new Getopt(getPromptCommandString(), args, shortOpts, longOpts);
+ getopt.setOpterr(false);
RecordArgs recordArgs = new RecordArgs();
@@ -73,7 +74,7 @@ public class RecordCommand implements ClientCommand {
switch (code) {
case ':':
case '?':
- throw new IllegalArgumentException("Invalid options");
+ throw new CommandLineParseException("Invalid option");
case 1:
break;
case 'f':
@@ -128,7 +129,7 @@ public class RecordCommand implements ClientCommand {
}
public String getSyntax() {
- return "record [[-b | --start] | [-e | --end]] [-a | --append] -f <file>";
+ return getPromptCommandString() + " [[-b | --start] | [-e | --end]] [-a | --append] -f <file>";
}
public String getHelp() {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ScriptCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ScriptCommand.java
index 7b8c37f..4a99316 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ScriptCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ScriptCommand.java
@@ -274,7 +274,7 @@ public class ScriptCommand implements ClientCommand {
}
public String getSyntax() {
- return "exec <statement> | [-s<indexed|named>] -f <file> [args]";
+ return getPromptCommandString() + " <statement> | [-s<indexed|named>] -f <file> [args]";
}
public String getHelp() {
@@ -282,8 +282,8 @@ public class ScriptCommand implements ClientCommand {
}
public String getDetailedHelp() {
- return "Execute a statement or a script. The following services managers are available: "
- + RhqManagers.values();
+ return "Execute a statement or a script. The following service managers are available: "
+ + Arrays.toString(RhqManagers.values());
}
public ScriptContext getContext() {
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
index 2df0b72..802ac4c 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
@@ -25,6 +25,7 @@ import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import org.rhq.enterprise.client.ClientMain;
import org.rhq.enterprise.client.Version;
+import org.rhq.enterprise.client.script.CommandLineParseException;
/**
* Command to show the user the version information of the CLI.
@@ -68,7 +69,8 @@ public class VersionCommand implements ClientCommand {
LongOpt[] longOpts = {
new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v')
};
- Getopt getopt = new Getopt("exec", args, shortOpts, longOpts);
+ Getopt getopt = new Getopt(getPromptCommandString(), args, shortOpts, longOpts);
+ getopt.setOpterr(false);
VersionArgs versionArgs = new VersionArgs();
@@ -76,7 +78,7 @@ public class VersionCommand implements ClientCommand {
while (code != -1) {
switch (code) {
case ':':
- throw new IllegalArgumentException("Illegal option.");
+ throw new CommandLineParseException("Invalid option");
case 'v':
versionArgs.verbose = true;
break;
12 years, 3 months
[rhq] Branch 'rc/jon3.0.1.GA' - 23 commits - modules/core modules/enterprise modules/plugins
by Simeon Pinder
modules/core/dbutils/pom.xml | 8
modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java | 23
modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml | 197 ++++-
modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java | 12
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java | 7
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java | 61 +
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java | 160 ++--
modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java | 3
modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java | 7
modules/core/plugin-container/src/main/java/org/rhq/core/pc/measurement/MeasurementSenderRunner.java | 27
modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java | 4
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java | 7
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java | 388 +++++-----
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java | 4
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java | 45 -
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java | 34
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java | 15
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java | 11
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java | 10
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java | 26
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java | 9
modules/enterprise/remoting/cli/pom.xml | 8
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java | 26
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java | 8
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java | 49 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java | 34
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java | 38
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java | 10
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java | 41 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java | 43 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java | 18
modules/plugins/platform/src/main/java/org/rhq/plugins/platform/FileSystemComponent.java | 46 -
34 files changed, 837 insertions(+), 546 deletions(-)
New commits:
commit 6aa861d99b836c576370ad1b0695b95d53eb0faf
Merge: dc1deaf 20221ed
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Wed Feb 1 13:48:04 2012 -0500
Merge branch 'release/jon3.0.x' into rc/jon3.0.1.GA
commit 20221edea965c18481e54b97d2b60ceb50bb1cea
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 17:12:36 2012 -0500
[BZ 784678] prevent NPE from occurring if -f option is not passed to CLI record command - instead throw a command line
parse exception with an informative error message (https://bugzilla.redhat.com/show_bug.cgi?id=784678)
(cherry picked from commit 55a89fae4b11ca5a8fecb668b87dbcef2bc04cf9)
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
index e1244ae..f3363aa 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -98,8 +98,12 @@ public class RecordCommand implements ClientCommand {
code = getopt.getopt();
}
+ if (recordArgs.file == null) {
+ throw new CommandLineParseException("The file option must be specified.");
+ }
+
if (recordArgs.recordState == null) {
- throw new CommandLineParseException("Either the start or stop option must be specified");
+ throw new CommandLineParseException("Either the start or stop option must be specified.");
}
return recordArgs;
commit 05fa50e1833a66f2e12dd59bd55839c2b258e765
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:43:11 2012 -0500
[BZ 785218] fix so -v/--version option does not print redundant info
(https://bugzilla.redhat.com/show_bug.cgi?id=785218)
(cherry picked from commit 3c0e9542e0ddfa60828ea44c37af715a79bfcc6b)
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
index 191c537..d4444fe 100755
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2009 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -82,6 +82,7 @@ public class ClientMain {
private String user;
private String pass;
private ArrayList<String> notes = new ArrayList<String>();
+ private boolean showDetailedVersion;
// reference to the webservice reference factory
private RemoteClient remoteClient;
@@ -403,7 +404,7 @@ public class ClientMain {
}
private void displayUsage() {
- outputWriter.println("rhq-cli.sh [-h] [-u user] [-p pass] [-P] [-s host] [-t port] [-f file]|[-c command]");
+ outputWriter.println("rhq-cli.sh [-h] [-u user] [-p pass] [-P] [-s host] [-t port] [-v] [-f file]|[-c command]");
}
void processArguments(String[] args) throws IllegalArgumentException, IOException {
@@ -478,10 +479,10 @@ public class ClientMain {
setHost(getopt.getOptarg());
break;
}
- case 'r': {
- setTransport(getopt.getOptarg());
- break;
- }
+ case 'r': {
+ setTransport(getopt.getOptarg());
+ break;
+ }
case 't': {
String portArg = getopt.getOptarg();
try {
@@ -492,15 +493,20 @@ public class ClientMain {
break;
}
case 'v': {
- String versionString = Version.getProductNameAndVersionBuildInfo();
- outputWriter.println(versionString);
+ showDetailedVersion = true;
break;
}
}
}
if (interactiveMode) {
- outputWriter.println(Version.getProductNameAndVersion());
+ String version = (showDetailedVersion) ? Version.getProductNameAndVersionBuildInfo() :
+ Version.getProductNameAndVersion();
+ outputWriter.println(version);
+ if (showDetailedVersion && args.length == 1) {
+ // If -v was the only option specified, exit after printing the version.
+ System.exit(0);
+ }
}
if (user != null && pass != null) {
@@ -516,7 +522,7 @@ public class ClientMain {
}
if (!interactiveMode) {
- commands.get("exec").execute(this, execCmdLine.toArray(new String[] {}));
+ commands.get("exec").execute(this, execCmdLine.toArray(new String[execCmdLine.size()]));
}
}
commit a4a6b535f5431652372af02cf77483e8d5f6ae03
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:08:05 2012 -0500
[BZ 784983] fix output of CLI version command (https://bugzilla.redhat.com/show_bug.cgi?id=784983)
(cherry picked from commit 43f016c9d9da95d2f5ea1bed4d1ee7fdbf9e07c3)
diff --git a/modules/enterprise/remoting/cli/pom.xml b/modules/enterprise/remoting/cli/pom.xml
index d94c40b..8ed89b5 100644
--- a/modules/enterprise/remoting/cli/pom.xml
+++ b/modules/enterprise/remoting/cli/pom.xml
@@ -178,14 +178,6 @@
</includes>
<archive>
<index>true</index>
- <manifestEntries>
- <Implementation-Title>${rhq.product.name} - ${project.name}</Implementation-Title>
- <Implementation-Version>${project.version}</Implementation-Version>
- <Specification-Vendor>org.jboss</Specification-Vendor>
- <Specification-Title>JBossWS</Specification-Title>
- <Specification-Version>${jbossws-native-dist.version}</Specification-Version>
- <Build-Number>${buildNumber}</Build-Number>
- </manifestEntries>
</archive>
</configuration>
</plugin>
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
index d27c3f3..2df0b72 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,10 @@
package org.rhq.enterprise.client.commands;
import java.util.Properties;
+import java.util.jar.Attributes;
+import gnu.getopt.Getopt;
+import gnu.getopt.LongOpt;
import org.rhq.enterprise.client.ClientMain;
import org.rhq.enterprise.client.Version;
@@ -35,26 +38,56 @@ public class VersionCommand implements ClientCommand {
}
public boolean execute(ClientMain client, String[] args) {
- if (args.length <= 1) {
+ VersionArgs versionArgs = parseArgs(args);
+ if (versionArgs.verbose) {
client.getPrintWriter().println(Version.getVersionPropertiesAsString());
} else {
Properties props = Version.getVersionProperties();
- for (int i = 1; i < args.length; i++) {
- client.getPrintWriter().println(args[i] + "=" + props.getProperty(args[i], "<unknown>"));
- }
+ String version = props.getProperty(Attributes.Name.IMPLEMENTATION_VERSION.toString());
+ client.getPrintWriter().println(version);
}
+
return true;
}
public String getSyntax() {
- return "version [prop name]...";
+ return getPromptCommandString() + " [-v | --verbose]";
}
public String getHelp() {
- return "Show version information and properties";
+ return "Show CLI version information";
}
public String getDetailedHelp() {
- return getHelp();
+ return getHelp() + ". If no arguments are specified, the CLI's version is printed. If the verbose option is "
+ + "specified, the values of the main attributes from the CLI jar's MANIFEST.MF are printed.";
+ }
+
+ private VersionArgs parseArgs(String[] args) {
+ String shortOpts = "-:v";
+ LongOpt[] longOpts = {
+ new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v')
+ };
+ Getopt getopt = new Getopt("exec", args, shortOpts, longOpts);
+
+ VersionArgs versionArgs = new VersionArgs();
+
+ int code = getopt.getopt();
+ while (code != -1) {
+ switch (code) {
+ case ':':
+ throw new IllegalArgumentException("Illegal option.");
+ case 'v':
+ versionArgs.verbose = true;
+ break;
+ }
+ code = getopt.getopt();
+ }
+
+ return versionArgs;
+ }
+
+ private static class VersionArgs {
+ boolean verbose;
}
}
\ No newline at end of file
commit d44638c22a94b4997fd3a5af9f27b642bed97ef0
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 15:20:14 2012 -0500
[Bug 773435 - Enabled event sources cause initial resource component start to time out]
lazily access sigar on the first polling, which happens after container
initialization.
Conflicts:
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
index bcc42de..30cd3e5 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
@@ -46,28 +46,21 @@ import org.rhq.core.pluginapi.event.EventPoller;
*
* @author Ian Springer
*/
-public class LogFileEventPoller implements EventPoller {
+public class LogFileEventPoller implements EventPoller {
private final Log log = LogFactory.getLog(this.getClass());
private String eventType;
private File logFile;
private FileInfo logFileInfo;
private LogEntryProcessor entryProcessor;
+ private EventContext eventContext;
- public LogFileEventPoller(EventContext eventContext, String eventType, File logFile, LogEntryProcessor entryProcessor) {
- SigarProxy sigar = eventContext.getSigar();
+ public LogFileEventPoller(EventContext eventContext, String eventType, File logFile,
+ LogEntryProcessor entryProcessor) {
this.eventType = eventType;
this.logFile = logFile;
- if (sigar != null) {
- try {
- this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
- } catch (SigarException e) {
- throw new RuntimeException("Failed to obtain file info for log file [" + this.logFile + "].", e);
- }
- } else {
- log.warn("SIGAR is unavailable - cannot poll log file [" + this.logFile + "] for events.");
- }
this.entryProcessor = entryProcessor;
+ this.eventContext = eventContext;
}
@NotNull
@@ -80,11 +73,26 @@ public class LogFileEventPoller implements EventPoller {
return this.logFile.getPath();
}
+ // we can't get the FileInfo in the constructor because pollers are constructed during pc initialization, and
+ // at that time the eventManager is not available (and so we can't get sigar).
+ private FileInfo getFileInfo() {
+ if (null == this.logFileInfo) {
+ try {
+ SigarProxy sigar = eventContext.getSigar();
+ this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
+ // once we have the file info we can let go of the event context, just in case that's useful
+ this.eventContext = null;
+
+ } catch (SigarException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ return this.logFileInfo;
+ }
+
@Nullable
public Set<Event> poll() {
- if (this.logFileInfo == null) {
- return null;
- }
if (!this.logFile.exists()) {
log.warn("Log file [" + this.logFile + "] being polled does not exist.");
return null;
@@ -93,23 +101,25 @@ public class LogFileEventPoller implements EventPoller {
log.error("Log file [" + this.logFile + "] being polled is a directory, not a regular file.");
return null;
}
+ FileInfo fileInfo;
try {
- if (!this.logFileInfo.changed()) {
+ fileInfo = getFileInfo();
+ if (!fileInfo.changed()) {
return null;
}
} catch (SigarException e) {
throw new RuntimeException(e);
}
- return processNewLines();
+ return processNewLines(fileInfo);
}
- private Set<Event> processNewLines() {
+ private Set<Event> processNewLines(FileInfo fileInfo) {
Set<Event> events = null;
Reader reader = null;
try {
reader = new FileReader(this.logFile);
- long offset = getOffset();
+ long offset = getOffset(fileInfo);
if (offset > 0) {
reader.skip(offset);
@@ -130,24 +140,24 @@ public class LogFileEventPoller implements EventPoller {
return events;
}
- private long getOffset() {
- FileInfo previousFileInfo = this.logFileInfo.getPreviousInfo();
+ private long getOffset(FileInfo fileInfo) {
+ FileInfo previousFileInfo = fileInfo.getPreviousInfo();
if (previousFileInfo == null) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": first stat");
}
- return this.logFileInfo.getSize();
+ return fileInfo.getSize();
}
- if (this.logFileInfo.getInode() != previousFileInfo.getInode()) {
+ if (fileInfo.getInode() != previousFileInfo.getInode()) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": file inode changed");
}
return -1;
}
- if (this.logFileInfo.getSize() < previousFileInfo.getSize()) {
+ if (fileInfo.getSize() < previousFileInfo.getSize()) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": file truncated");
}
@@ -155,7 +165,7 @@ public class LogFileEventPoller implements EventPoller {
}
if (log.isDebugEnabled()) {
- long diff = this.logFileInfo.getSize() - previousFileInfo.getSize();
+ long diff = fileInfo.getSize() - previousFileInfo.getSize();
log.debug(this.logFile + ": " + diff + " new bytes");
}
commit db02533c122d00f11bcfdda3531db5567558a144
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 15:05:24 2012 -0500
[Bug 785022 - Server upgrade fails if db-uprade.xml task is unable to created index when index already exists]
Applying suggested fix from loleary. Could not apply patch successfully
so manually reapplied the fix, which is to protect create/drop index
stmts with ignoreErrors="true".
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index 7dd68d4..2ffdfe5 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -296,7 +296,7 @@
</schema-directSQL>
<schema-alterColumn table="RHQ_SERVER" column="OPERATION_MODE" nullable="FALSE" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_SERVER unique constraint on NAME">
CREATE UNIQUE INDEX rhq_server_name_unique ON rhq_server (name)
</statement>
@@ -853,7 +853,7 @@
</schemaSpec>
<schemaSpec version="2.24">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_MEASUREMENT_BLINE index on SCHEDULE_ID">
CREATE INDEX rhq_meas_baseline_sid_idx ON rhq_measurement_bline (schedule_id)
</statement>
@@ -1078,7 +1078,7 @@
</schemaSpec>
<schemaSpec version="2.36">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique constraint on RHQ_MEASUREMENT_DEF">
DROP INDEX RHQ_METRIC_DEF_KEY_IDX
</statement>
@@ -1093,7 +1093,7 @@
WHERE NUMERIC_TYPE = 0
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RHQ_MEASUREMENT_DEF (RESOURCE_TYPE_ID, NAME, RAW_NUMERIC_TYPE)">
CREATE UNIQUE INDEX RHQ_METRIC_DEF_KEY_IDX ON RHQ_MEASUREMENT_DEF (RESOURCE_TYPE_ID, NAME, RAW_NUMERIC_TYPE)
</statement>
@@ -1193,49 +1193,77 @@
<!-- RHQ 1448 -->
<schemaSpec version="2.44">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R00 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R00_SID_IDX ON RHQ_MEAS_DATA_NUM_R00 (schedule_id)
- </statement>
+ </statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R01 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R01_SID_IDX ON RHQ_MEAS_DATA_NUM_R01 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R02 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R02_SID_IDX ON RHQ_MEAS_DATA_NUM_R02 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R03 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R03_SID_IDX ON RHQ_MEAS_DATA_NUM_R03 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R04 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R04_SID_IDX ON RHQ_MEAS_DATA_NUM_R04 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R05 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R05_SID_IDX ON RHQ_MEAS_DATA_NUM_R05 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R06 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R06_SID_IDX ON RHQ_MEAS_DATA_NUM_R06 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R07 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R07_SID_IDX ON RHQ_MEAS_DATA_NUM_R07 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R08 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R08_SID_IDX ON RHQ_MEAS_DATA_NUM_R08 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R09 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R09_SID_IDX ON RHQ_MEAS_DATA_NUM_R09 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R10 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R10_SID_IDX ON RHQ_MEAS_DATA_NUM_R10 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R11 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R11_SID_IDX ON RHQ_MEAS_DATA_NUM_R11 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R12 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R12_SID_IDX ON RHQ_MEAS_DATA_NUM_R12 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R13 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R13_SID_IDX ON RHQ_MEAS_DATA_NUM_R13 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R14 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R14_SID_IDX ON RHQ_MEAS_DATA_NUM_R14 (schedule_id)
</statement>
@@ -1300,7 +1328,7 @@
</schemaSpec>
<schemaSpec version="2.50">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_RESOURCE_ERROR.RESOURCE_ID">
CREATE INDEX RHQ_RES_ERROR_IDX_RES_ID ON RHQ_RESOURCE_ERROR (RESOURCE_ID)
</statement>
@@ -1313,12 +1341,12 @@
</schemaSpec>
<schemaSpec version="2.52">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique name constraint on RHQ_RESOURCE_GROUP">
DROP INDEX RHQ_RES_GROUP_NAME
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique name constraint on RHQ_RESOURCE_GROUP">
CREATE INDEX RHQ_RES_GROUP_NAME ON RHQ_RESOURCE_GROUP (name)
</statement>
@@ -1348,57 +1376,87 @@
</schemaSpec>
<schemaSpec version="2.55">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on TIME_STAMP column of RHQ_MEASUREMENT_DATA_NUM_1H">
CREATE INDEX RHQ_MEAS_DATA_1H_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_1H(TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on TIME_STAMP column of RHQ_MEASUREMENT_DATA_NUM_6H">
CREATE INDEX RHQ_MEAS_DATA_6H_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_6H(TIME_STAMP)
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R00 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R00_TS_IDX ON RHQ_MEAS_DATA_NUM_R00 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R01 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R01_TS_IDX ON RHQ_MEAS_DATA_NUM_R01 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R02 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R02_TS_IDX ON RHQ_MEAS_DATA_NUM_R02 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R03 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R03_TS_IDX ON RHQ_MEAS_DATA_NUM_R03 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R04 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R04_TS_IDX ON RHQ_MEAS_DATA_NUM_R04 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R05 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R05_TS_IDX ON RHQ_MEAS_DATA_NUM_R05 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R06 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R06_TS_IDX ON RHQ_MEAS_DATA_NUM_R06 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R07 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R07_TS_IDX ON RHQ_MEAS_DATA_NUM_R07 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R08 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R08_TS_IDX ON RHQ_MEAS_DATA_NUM_R08 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R09 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R09_TS_IDX ON RHQ_MEAS_DATA_NUM_R09 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R10 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R10_TS_IDX ON RHQ_MEAS_DATA_NUM_R10 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R11 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R11_TS_IDX ON RHQ_MEAS_DATA_NUM_R11 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R12 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R12_TS_IDX ON RHQ_MEAS_DATA_NUM_R12 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R13 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R13_TS_IDX ON RHQ_MEAS_DATA_NUM_R13 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R14 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R14_TS_IDX ON RHQ_MEAS_DATA_NUM_R14 (TIME_STAMP)
</statement>
@@ -1406,49 +1464,77 @@
</schemaSpec>
<schemaSpec version="2.56">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R00_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R00_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R01_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R01_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R02_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R02_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R03_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R03_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R04_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R04_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R05_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R05_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R06_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R06_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R07_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R07_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R08_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R08_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R09_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R09_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R10_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R10_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R11_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R11_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R12_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R12_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R13_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R13_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R14_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R14_SID_IDX
</statement>
@@ -1456,7 +1542,7 @@
</schemaSpec>
<schemaSpec version="2.57">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Create index on RHQ_CONFIG_PROPERTY(PARENT_LIST_ID)">
CREATE INDEX RHQ_CONFIG_PROP_idx_list_key ON RHQ_CONFIG_PROPERTY(PARENT_LIST_ID)
</statement>
@@ -1683,6 +1769,8 @@
FOREIGN KEY ( REPO_GROUP_TYPE_ID )
REFERENCES RHQ_REPO_GROUP_TYPE ( ID )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_REPO_GROUP_IDX
ON RHQ_REPO_GROUP ( NAME, REPO_GROUP_TYPE_ID )
@@ -1842,7 +1930,7 @@
<schema-alterColumn table="RHQ_DISTRIBUTION" column="BASE_PATH" nullable="false" />
<schema-addColumn table="RHQ_DISTRIBUTION" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_DISTRIBUTION" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_DISTRIBUTION_IDX ON RHQ_DISTRIBUTION ( LABEL, BASE_PATH )
</statement>
@@ -1947,6 +2035,8 @@
FOREIGN KEY (DISTRIBUTION_ID)
REFERENCES RHQ_DISTRIBUTION ( ID )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_DISTRIBUTION_FILE_IDX
ON RHQ_DISTRIBUTION_FILE ( DISTRIBUTION_ID, RELATIVE_FILENAME )
@@ -2019,7 +2109,7 @@
</schema-directSQL>
<!-- Fix bug:538157 -->
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE INDEX RHQ_REPO_PKG_VER_MAP_IDX
ON RHQ_REPO_PKG_VERSION_MAP ( PACKAGE_VERSION_ID )
@@ -2040,10 +2130,12 @@
<schemaSpec version="2.69.2">
<!-- plugin names must be unique only if they are deployed on the same side (agent vs. server) -->
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping unique index on RHQ_PLUGIN (NAME)">
DROP INDEX RHQ_PLUGIN_NAME_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RHQ_PLUGIN (NAME, DEPLOYMENT) so server plugin names need not be unique with agent plugins">
CREATE UNIQUE INDEX RHQ_PLUGIN_NAME_DEPLOY_IDX ON RHQ_PLUGIN (NAME, DEPLOYMENT)
</statement>
@@ -2086,7 +2178,7 @@
<schema-addColumn table="RHQ_ALERT_NOTIF_LOG" column="MESSAGE" columnType="VARCHAR2" precision="4000" />
</schemaSpec>
<schemaSpec version="2.70.3">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping unique index RHQ_ALERT_IDX_ALERT">
DROP INDEX RHQ_ALERT_IDX_ALERT
</statement>
@@ -2127,7 +2219,7 @@
<schema-deleteColumn table="RHQ_ALERT" column="triggered_operation" />
</schemaSpec>
<schemaSpec version="2.70.7">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Recreating RHQ_ALERT_IDX_ALERT as non-unique index">
CREATE INDEX RHQ_ALERT_IDX_ALERT ON RHQ_ALERT_NOTIF_LOG (alert_id)
</statement>
@@ -2168,13 +2260,17 @@
<schema-addColumn table="RHQ_ADVISORY" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_NAME_UQ ON RHQ_ADVISORY ( ADVISORY_NAME )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_UQ ON RHQ_ADVISORY ( ADVISORY )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE INDEX RHQ_ADVISORY_UDATE_IDX ON RHQ_ADVISORY (UPDATE_DATE )
</statement>
@@ -2193,7 +2289,7 @@
<schema-alterColumn table="RHQ_ADVISORY_PACKAGE" column="PACKAGE_VERSION_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_PACKAGE" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_PACKAGE" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_PACKAGE_IDX ON RHQ_ADVISORY_PACKAGE ( ADVISORY_ID, PACKAGE_VERSION_ID )
</statement>
@@ -2234,7 +2330,7 @@
<schema-alterColumn table="RHQ_ADVISORY_CVE" column="CVE_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_CVE" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_CVE" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_CVE_IDX ON RHQ_ADVISORY_CVE ( ADVISORY_ID, CVE_ID )
</statement>
@@ -2266,7 +2362,7 @@
<schema-alterColumn table="RHQ_ADVISORY_BUGLIST" column="BUG_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_BUGLIST" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_BUGLIST" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_BUG_IDX ON RHQ_ADVISORY_BUGLIST ( ADVISORY_ID, BUG_ID )
</statement>
@@ -2365,6 +2461,8 @@
FOREIGN KEY (RESOURCE_TYPE_ID)
REFERENCES RHQ_RESOURCE_TYPE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_TYPE unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_TYPE_UNIQUE ON RHQ_BUNDLE_TYPE (name)
</statement>
@@ -2406,6 +2504,8 @@
FOREIGN KEY (PACKAGE_TYPE_ID)
REFERENCES RHQ_PACKAGE_TYPE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_UNIQUE ON RHQ_BUNDLE (bundle_type_id, name)
</statement>
@@ -2444,6 +2544,8 @@
FOREIGN KEY (CONFIG_DEF_ID)
REFERENCES RHQ_CONFIG_DEF (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_VERSION unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_VERSION_UNIQUE ON RHQ_BUNDLE_VERSION (bundle_id, name, version)
</statement>
@@ -2539,6 +2641,8 @@
FOREIGN KEY (GROUP_ID)
REFERENCES RHQ_RESOURCE_GROUP (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_DESTINATION unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_DESTINATION_UNIQUE
ON RHQ_BUNDLE_DESTINATION (bundle_id, group_id, deploy_dir)
@@ -2630,6 +2734,8 @@
FOREIGN KEY (RESOURCE_ID)
REFERENCES RHQ_RESOURCE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_RES_DEPLOY unique constraint on dep-resource mapping">
CREATE UNIQUE INDEX RHQ_BUNDLE_RES_DEPLOY_IDX
ON RHQ_BUNDLE_RES_DEPLOY (BUNDLE_DEPLOYMENT_ID, RESOURCE_ID)
@@ -2788,6 +2894,8 @@
FOREIGN KEY ( ROLE_ID )
REFERENCES RHQ_ROLE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ROLE_LDAP_GROUP_IDX
ON RHQ_ROLE_LDAP_GROUP ( ROLE_ID, LDAP_GROUP_NAME )
@@ -2996,10 +3104,12 @@
</schemaSpec>
<schemaSpec version="2.87">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Drop non-unique RHQ_RES_TYPE_IDX_PLG_NAME index">
DROP INDEX RHQ_RES_TYPE_IDX_PLG_NAME
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Recreate RHQ_RES_TYPE_IDX_PLG_NAME index as unique">
CREATE UNIQUE INDEX RHQ_RES_TYPE_IDX_PLG_NAME ON RHQ_RESOURCE_TYPE (name, plugin)
</statement>
@@ -3007,10 +3117,12 @@
</schemaSpec>
<schemaSpec version="2.88">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add end time index on call time data to speed up purges">
CREATE INDEX RHQ_CT_DA_VA_END_TIM_IDX ON RHQ_CALLTIME_DATA_VALUE (end_time)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add index on measurement definition numeric type">
CREATE INDEX RHQ_METRIC_DEF_NT_IDX ON RHQ_MEASUREMENT_DEF (numeric_type)
</statement>
@@ -3131,7 +3243,7 @@
</schemaSpec>
<schemaSpec version="2.92.4">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add index on measurement data 1d table timestamp">
CREATE INDEX RHQ_MEAS_DATA_1D_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_1D (time_stamp)
</statement>
@@ -3294,6 +3406,8 @@
<statement desc="Changing primary key of RHQ_OPERATION_SCHEDULE to ID. Step2/3...">
ALTER TABLE RHQ_OPERATION_SCHEDULE ADD PRIMARY KEY (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Changing primary key of RHQ_OPERATION_SCHEDULE to ID. Step3/3...">
CREATE UNIQUE INDEX RHQ_OPERATION_SCHEDULE_KEY_IDX ON RHQ_OPERATION_SCHEDULE (JOB_NAME, JOB_GROUP)
</statement>
@@ -3607,10 +3721,12 @@
</schemaSpec>
<schemaSpec version="2.113">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_ALERT_CONDITION_LOG index on CONDITION_ID">
CREATE INDEX RHQ_ALERT_COND_LOG_COND_IDX ON RHQ_ALERT_CONDITION_LOG (CONDITION_ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_MEASUREMENT_SCHED index on RESOURCE_ID">
CREATE INDEX RHQ_MEAS_SCHED_RESID_IDX ON RHQ_MEASUREMENT_SCHED (RESOURCE_ID)
</statement>
@@ -3667,7 +3783,7 @@
REFERENCES RHQ_CONFIG (ID)
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RESOURCE_TYPE_ID and NAME columns">
CREATE UNIQUE INDEX RHQ_TYPE_DEF_NAME ON RHQ_DRIFT_DEF_TEMPLATE ( RESOURCE_TYPE_ID, NAME )
</statement>
commit 72bb3d37c84b3af4250c5daee87438be9d9fbb26
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Nov 11 10:57:33 2011 -0500
log message reporting invalid numeric metrics at DEBUG, rather than WARN,
to avoid flooding the agent log with repetitive messages
(cherry picked from commit 542a30ca6d0eaebbee5365c756955255ba367e4e)
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/measurement/MeasurementSenderRunner.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/measurement/MeasurementSenderRunner.java
index 5cee6a6..a9136d1 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/measurement/MeasurementSenderRunner.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/measurement/MeasurementSenderRunner.java
@@ -90,15 +90,34 @@ public class MeasurementSenderRunner implements Callable<MeasurementReport>, Run
Iterator<MeasurementDataNumeric> iter = report.getNumericData().iterator();
while (iter.hasNext()) {
MeasurementDataNumeric numeric = iter.next();
- Double v = numeric.getValue();
- if (v == null || v.isInfinite() || v.isNaN()) {
- LOG.warn("Numeric " + numeric.getName() + " with id " + numeric.getScheduleId()
- + " is invalid, value was '" + v + "'");
+ Double value = numeric.getValue();
+ if (value == null || value.isInfinite() || value.isNaN()) {
+ if (LOG.isDebugEnabled()) {
+ String stringValue = getStringValue(value);
+ LOG.debug("Numeric metric [" + numeric.getName() + "] with schedule id [" + numeric.getScheduleId()
+ + "] is invalid - value is [" + stringValue + "].");
+ }
iter.remove();
}
}
}
+ private String getStringValue(Double value) {
+ String stringValue;
+ if (value == null) {
+ stringValue = "null";
+ } else if (value.isNaN()) {
+ stringValue = "Double.NaN";
+ } else if (value == Double.POSITIVE_INFINITY) {
+ stringValue = "Double.POSITIVE_INFINITY";
+ } else if (value == Double.NEGATIVE_INFINITY) {
+ stringValue = "Double.NEGATIVE_INFINITY";
+ } else {
+ stringValue = value.toString();
+ }
+ return stringValue;
+ }
+
public void run() {
try {
call();
commit b9ccebed287c8cc86ad4e601b3ceb23ec0520770
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 13:32:08 2012 -0500
[Bug 772771 - Agent not syncing updated plugin config at startup]
The resource mtime was not being properly updated when completing the
plugin config sync. If the agent was down at update time it would not
know to sync the resource on startup, or at any point until perhaps
the resource was modified in some other way, or the plugin config was
changed when the agent was up.
Also, in general Resource.setAgentSynchronizationNeeded() should be called
by any code performing an update that requires agent sync. The
Resource.setMtime() method should not be called for this purpose, but
rather only when manual mtime manipulation is required.
- fixed plugin config update
- converted setMtime calls to be setAgentSynchronizationNeeded() where appropriate
- added a missing call to setAgentSynchronizationNeeded() in DiscoveryBossBean
- trivial
-- fixed a method name typo
-- fixed some compiler warnings
-- removed some dead code
Conflicts:
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
index dd5da1b..c90ed4e 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
@@ -83,7 +83,7 @@ import org.rhq.core.domain.util.Summary;
* Represents an RHQ managed resource (i.e. a platform, server, or service).
*/
@Entity
-@NamedQueries( {
+@NamedQueries({
@NamedQuery(name = Resource.QUERY_FIND_PROBLEM_RESOURCES_ALERT_ADMIN, query = "" //
+ " SELECT DISTINCT new org.rhq.core.domain.resource.composite.ProblemResourceComposite"
+ " ( "
@@ -1302,6 +1302,12 @@ public class Resource implements Comparable<Resource>, Serializable {
return this.mtime;
}
+ /**
+ * Call this directly only when needing manual manipulation of the mtime. Otherwise, you probably want to
+ * call {@link #setAgentSynchronizationNeeded()}.
+ *
+ * @param mtime
+ */
public void setMtime(long mtime) {
this.mtime = mtime;
}
@@ -1336,8 +1342,6 @@ public class Resource implements Comparable<Resource>, Serializable {
*
* For a list of changes that the agent cares about, see InventoryManager.mergeResource(Resource, Resource)
*/
-
- // @PreUpdate
public void setAgentSynchronizationNeeded() {
this.mtime = System.currentTimeMillis();
}
@@ -1434,7 +1438,7 @@ public class Resource implements Comparable<Resource>, Serializable {
return schedules;
}
- public void setSchendules(Set<MeasurementSchedule> schedules) {
+ public void setSchedules(Set<MeasurementSchedule> schedules) {
this.schedules = schedules;
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
index 5b88fe5..60550be 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
@@ -136,7 +136,6 @@ import org.rhq.enterprise.server.util.QuartzUtil;
* @author John Mazzitelli
* @author Ian Springer
*/
-@SuppressWarnings({ "UnnecessaryLocalVariable", "UnnecessaryReturnStatement" })
@Stateless
@XmlType(namespace = ServerVersion.namespace)
public class ConfigurationManagerBean implements ConfigurationManagerLocal, ConfigurationManagerRemote {
@@ -220,6 +219,7 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
Resource resource = update.getResource();
// link to the newer, persisted configuration object -- regardless of errors
+ resource.setAgentSynchronizationNeeded();
resource.setPluginConfiguration(update.getConfiguration());
if (response.getStatus() == ConfigurationUpdateStatus.SUCCESS) {
@@ -1242,17 +1242,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return configService.validate(configuration, resourceId, isStructured);
}
- private boolean isRawSupported(int resourceId) {
- Resource resource = entityManager.find(Resource.class, resourceId);
- ConfigurationDefinition configDef = resource.getResourceType().getResourceConfigurationDefinition();
- if (configDef == null) {
- return false;
- }
-
- return (ConfigurationFormat.STRUCTURED_AND_RAW == configDef.getConfigurationFormat() || (ConfigurationFormat.RAW == configDef
- .getConfigurationFormat()));
- }
-
private boolean isStructuredAndRawSupported(int resourceId) {
Resource resource = entityManager.find(Resource.class, resourceId);
ConfigurationDefinition configDef = resource.getResourceType().getResourceConfigurationDefinition();
@@ -1691,7 +1680,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
}
public Configuration getConfiguration(Subject subject, int configurationId) {
- @SuppressWarnings({ "UnnecessaryLocalVariable" })
Configuration configuration = getConfigurationById(configurationId);
return configuration;
}
@@ -2337,7 +2325,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return out;
}
- @SuppressWarnings("unchecked")
public PageList<ResourceConfigurationUpdate> findResourceConfigurationUpdatesByCriteria(Subject subject,
ResourceConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2346,8 +2333,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
"resource", subject.getId());
}
- CriteriaQueryRunner<ResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<ResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner<ResourceConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<ResourceConfigurationUpdate> updates = queryRunner.execute();
@@ -2371,7 +2358,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<PluginConfigurationUpdate> findPluginConfigurationUpdatesByCriteria(Subject subject,
PluginConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2380,8 +2366,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
"resource", subject.getId());
}
- CriteriaQueryRunner<PluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<PluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner<PluginConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<PluginConfigurationUpdate> updates = queryRunner.execute();
@@ -2405,7 +2391,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<GroupResourceConfigurationUpdate> findGroupResourceConfigurationUpdatesByCriteria(Subject subject,
GroupResourceConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2414,8 +2399,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
subject.getId());
}
- CriteriaQueryRunner<GroupResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria,
- generator, entityManager);
+ CriteriaQueryRunner<GroupResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner<GroupResourceConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<GroupResourceConfigurationUpdate> updates = queryRunner.execute();
@@ -2438,7 +2423,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<GroupPluginConfigurationUpdate> findGroupPluginConfigurationUpdatesByCriteria(Subject subject,
GroupPluginConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2447,8 +2431,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
subject.getId());
}
- CriteriaQueryRunner<GroupPluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<GroupPluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner<GroupPluginConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<GroupPluginConfigurationUpdate> updates = queryRunner.execute();
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index 2ea6234..7609492 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -21,6 +21,7 @@ package org.rhq.enterprise.server.discovery;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -29,7 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateless;
@@ -44,12 +44,12 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
+
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.discovery.InvalidPluginConfigurationClientException;
import org.rhq.core.clientapi.agent.upgrade.ResourceUpgradeRequest;
@@ -314,16 +314,15 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
final String randomSuffix = UUID.randomUUID().toString();
final String triggerName = TRIGGER_PREFIX + " - " + randomSuffix;
- SimpleTrigger trigger = new SimpleTrigger(triggerName, DEFAULT_JOB_GROUP,
- new Date());
+ SimpleTrigger trigger = new SimpleTrigger(triggerName, DEFAULT_JOB_GROUP, new Date());
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(AgentInventoryStatusUpdateJob.KEY_TRIGGER_NAME, triggerName);
jobDataMap.put(AgentInventoryStatusUpdateJob.KEY_TRIGGER_GROUP_NAME, DEFAULT_JOB_GROUP);
AgentInventoryStatusUpdateJob.externalizeJobValues(jobDataMap,
- AgentInventoryStatusUpdateJob.PLATFORMS_COMMA_LIST, platforms);
+ AgentInventoryStatusUpdateJob.PLATFORMS_COMMA_LIST, platforms);
AgentInventoryStatusUpdateJob.externalizeJobValues(jobDataMap,
- AgentInventoryStatusUpdateJob.SERVERS_COMMA_LIST, servers);
+ AgentInventoryStatusUpdateJob.SERVERS_COMMA_LIST, servers);
trigger.setJobName(DEFAULT_JOB_NAME);
trigger.setJobGroup(DEFAULT_JOB_GROUP);
@@ -333,7 +332,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
scheduler.scheduleJob(trigger);
} else {
JobDetail jobDetail = new JobDetail(DEFAULT_JOB_NAME, DEFAULT_JOB_GROUP,
- AgentInventoryStatusUpdateJob.class);
+ AgentInventoryStatusUpdateJob.class);
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (SchedulerException e) {
@@ -357,10 +356,10 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
AgentClient agentClient = agentManager.getAgentClient(platform.getAgent());
try {
agentClient.getDiscoveryAgentService().synchronizeInventory(
- entityManager.find(ResourceSyncInfo.class, platform.getId()));
+ entityManager.find(ResourceSyncInfo.class, platform.getId()));
} catch (Exception e) {
log.warn("Could not perform commit synchronization with agent for platform [" + platform.getName()
- + "]", e);
+ + "]", e);
}
}
for (Resource server : servers) {
@@ -369,10 +368,10 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
AgentClient agentClient = agentManager.getAgentClient(server.getAgent());
try {
agentClient.getDiscoveryAgentService().synchronizeInventory(
- entityManager.find(ResourceSyncInfo.class, server.getId()));
+ entityManager.find(ResourceSyncInfo.class, server.getId()));
} catch (Exception e) {
log.warn("Could not perform commit synchronization with agent for server [" + server.getName()
- + "]", e);
+ + "]", e);
}
}
}
@@ -511,6 +510,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
}
}
+ @SuppressWarnings("deprecation")
public Set<ResourceUpgradeResponse> upgradeResources(Set<ResourceUpgradeRequest> upgradeRequests) {
Set<ResourceUpgradeResponse> result = new HashSet<ResourceUpgradeResponse>();
@@ -588,8 +588,9 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
private ResourceUpgradeResponse upgradeResource(@NotNull Resource resource, ResourceUpgradeRequest upgradeRequest,
boolean allowGenericPropertiesUpgrade) {
if (upgradeRequest.getUpgradeErrorMessage() != null) {
- ResourceError error = new ResourceError(resource, ResourceErrorType.UPGRADE, upgradeRequest
- .getUpgradeErrorMessage(), upgradeRequest.getUpgradeErrorStackTrace(), upgradeRequest.getTimestamp());
+ ResourceError error = new ResourceError(resource, ResourceErrorType.UPGRADE,
+ upgradeRequest.getUpgradeErrorMessage(), upgradeRequest.getUpgradeErrorStackTrace(),
+ upgradeRequest.getTimestamp());
resourceManager.addResourceError(error);
return null;
}
@@ -767,8 +768,8 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
continue;
}
}
- existingResource = resourceManager.getResourceByParentAndKey(overlord, existingParent, resource
- .getResourceKey(), resourceType.getPlugin(), resourceType.getName());
+ existingResource = resourceManager.getResourceByParentAndKey(overlord, existingParent,
+ resource.getResourceKey(), resourceType.getPlugin(), resourceType.getName());
}
if (existingResource != null) {
@@ -871,6 +872,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
if (existingResource.getInventoryStatus() == InventoryStatus.DELETED) {
existingResource.setInventoryStatus(InventoryStatus.COMMITTED);
existingResource.setPluginConfiguration(updatedResource.getPluginConfiguration());
+ existingResource.setAgentSynchronizationNeeded();
}
for (Resource childResource : updatedResource.getChildResources()) {
@@ -1021,14 +1023,14 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
// Do one query per 1000 Resource id's to prevent Oracle from failing because of an IN clause with more
// than 1000 items.
- List<Resource> resources = new ArrayList(resourceIds.length);
+ List<Resource> resources = new ArrayList<Resource>(resourceIds.length);
fromIndex = 0;
while (fromIndex < resourceIds.length) {
int toIndex = (resourceIds.length < (fromIndex + 1000)) ? resourceIds.length : (fromIndex + 1000);
int[] resourceIdSubArray = Arrays.copyOfRange(resourceIds, fromIndex, toIndex);
PageList<Resource> batchResources = resourceManager.findResourceByIds(subject, resourceIdSubArray, false,
- PageControl.getUnlimitedInstance());
+ PageControl.getUnlimitedInstance());
resources.addAll(batchResources);
fromIndex = toIndex;
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
index c899487..964d84c 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
@@ -160,7 +160,7 @@ class WsResourceListWrapper extends Resource {
destination.setProductVersion(source.getProductVersion());
destination.setResourceConfiguration(source.getResourceConfiguration());
destination.setResourceConfigurationUpdates(source.getResourceConfigurationUpdates());
- destination.setSchendules(source.getSchedules());
+ destination.setSchedules(source.getSchedules());
destination.setUuid(source.getUuid());
//handle the problematic references that would cause cycles if used by storing only ids.
if (source.getParentResource() != null) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
index 20d1c95..3c74f06 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
@@ -116,7 +116,7 @@ class WsResource extends Resource {
destination.setProductVersion(source.getProductVersion());
destination.setResourceConfiguration(source.getResourceConfiguration());
destination.setResourceConfigurationUpdates(source.getResourceConfigurationUpdates());
- destination.setSchendules(source.getSchedules());
+ destination.setSchedules(source.getSchedules());
destination.setUuid(source.getUuid());
//handle the problematic references that would cause cycles if used by storing only ids.
if (source.getParentResource() != null) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
index 8a21886..fba8a68 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
@@ -74,8 +74,6 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
* @param def the MeasuremendDefinition to delete
*/
public void removeMeasurementDefinition(MeasurementDefinition def) {
- long now = System.currentTimeMillis();
-
// First remove the schedules and associated OOBs.
List<MeasurementSchedule> schedules = def.getSchedules();
Iterator<MeasurementSchedule> schedIter = schedules.iterator();
@@ -86,8 +84,7 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
sched.setBaseline(null);
}
oobManager.removeOOBsForSchedule(subjectManager.getOverlord(), sched);
- // IMPORTANT: Update the mtime to tell the Agent this Resource needs to be synced.
- sched.getResource().setMtime(now);
+ sched.getResource().setAgentSynchronizationNeeded();
entityManager.remove(sched);
schedIter.remove();
}
@@ -134,14 +131,13 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
return results;
}
- @SuppressWarnings("unchecked")
public PageList<MeasurementDefinition> findMeasurementDefinitionsByCriteria(Subject subject,
MeasurementDefinitionCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
;
- CriteriaQueryRunner<MeasurementDefinition> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<MeasurementDefinition> queryRunner = new CriteriaQueryRunner<MeasurementDefinition>(
+ criteria, generator, entityManager);
return queryRunner.execute();
}
}
\ No newline at end of file
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 e5df592..bbc2a1d 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
@@ -23,21 +23,14 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.Date;
import java.util.UUID;
-import org.quartz.Trigger;
-import org.quartz.Scheduler;
-import org.quartz.JobDetail;
-import org.quartz.JobDataMap;
-import org.quartz.SimpleTrigger;
-import org.quartz.SchedulerException;
-
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
@@ -51,6 +44,12 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.SimpleTrigger;
+import org.quartz.Trigger;
import org.jboss.annotation.IgnoreDependency;
@@ -317,13 +316,13 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
return;
}
- @RequiredPermissions( { @RequiredPermission(Permission.MANAGE_INVENTORY),
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_INVENTORY),
@RequiredPermission(Permission.MANAGE_SETTINGS) })
public void disableAllDefaultCollections(Subject subject) {
entityManager.createNamedQuery(MeasurementDefinition.DISABLE_ALL).executeUpdate();
}
- @RequiredPermissions( { @RequiredPermission(Permission.MANAGE_INVENTORY),
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_INVENTORY),
@RequiredPermission(Permission.MANAGE_SETTINGS) })
public void disableAllSchedules(Subject subject) {
entityManager.createNamedQuery(MeasurementSchedule.DISABLE_ALL).executeUpdate();
@@ -331,11 +330,10 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
}
public void createSchedulesForExistingResources(ResourceType type, MeasurementDefinition newDefinition) {
- long now = System.currentTimeMillis();
List<Resource> resources = type.getResources();
if (resources != null) {
for (Resource res : resources) {
- res.setMtime(now); // changing MTime tells the agent this resource needs to be synced
+ res.setAgentSynchronizationNeeded();
MeasurementSchedule sched = new MeasurementSchedule(newDefinition, res);
sched.setInterval(newDefinition.getDefaultInterval());
entityManager.persist(sched);
@@ -648,16 +646,10 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
final String randomSuffix = UUID.randomUUID().toString();
final String jobName = DEFAULT_AGENT_JOB + " - " + randomSuffix;
- JobDetail jobDetail = new JobDetail(
- jobName,
- DEFAULT_AGENT_GROUP,
- NotifyAgentsOfScheduleUpdatesJob.class);
+ JobDetail jobDetail = new JobDetail(jobName, DEFAULT_AGENT_GROUP, NotifyAgentsOfScheduleUpdatesJob.class);
final String triggerName = DEFAULT_AGENT_TRIGGER + " - " + randomSuffix;
- SimpleTrigger simpleTrigger = new SimpleTrigger(
- triggerName,
- DEFAULT_AGENT_GROUP,
- new Date());
+ SimpleTrigger simpleTrigger = new SimpleTrigger(triggerName, DEFAULT_AGENT_GROUP, new Date());
JobDataMap jobDataMap = simpleTrigger.getJobDataMap();
jobDataMap.put(TRIGGER_NAME, triggerName);
@@ -1235,8 +1227,8 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// first get all the resources, which is needed to get the agent mappings
Subject overlord = subjectManager.getOverlord();
- PageList<Resource> resources = resourceManager.findResourceByIds(overlord, resourceIds, false, PageControl
- .getUnlimitedInstance());
+ PageList<Resource> resources = resourceManager.findResourceByIds(overlord, resourceIds, false,
+ PageControl.getUnlimitedInstance());
// then get all the requests
Set<ResourceMeasurementScheduleRequest> requests = findSchedulesForResourceAndItsDescendants(resourceIds, false);
@@ -1482,8 +1474,8 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
;
if (authorizationManager.isInventoryManager(subject) == false) {
- generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.RESOURCE, subject
- .getId());
+ generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.RESOURCE,
+ subject.getId());
}
CriteriaQueryRunner<MeasurementSchedule> queryRunner = new CriteriaQueryRunner(criteria, generator,
@@ -1522,4 +1514,3 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// }
}
-
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
index 4cbc3d1..fcc6638 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
@@ -238,8 +238,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
persistedResource.setLocation(resource.getLocation());
persistedResource.setDescription(resource.getDescription());
- // NOTE: Updating the mtime will tell the Agent it needs to sync this Resource.
- persistedResource.setMtime(System.currentTimeMillis());
+ persistedResource.setAgentSynchronizationNeeded();
persistedResource.setModifiedBy(user.getName());
return entityManager.merge(persistedResource);
@@ -614,7 +613,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
private void updateInventoryStatus(Resource resource, InventoryStatus newStatus, long now) {
resource.setInventoryStatus(newStatus);
resource.setItime(now);
- resource.setMtime(now);
+ resource.setAgentSynchronizationNeeded();
}
@SuppressWarnings("unchecked")
@@ -757,8 +756,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
// Build up a list of composite Resources for the ancestry that includes which ancestors, if any, should be
// locked from view.
boolean isInventoryManager = authorizationManager.isInventoryManager(subject);
- List<ResourceLineageComposite> resourceLineage = new ArrayList<ResourceLineageComposite>(rawResourceLineage
- .size());
+ List<ResourceLineageComposite> resourceLineage = new ArrayList<ResourceLineageComposite>(
+ rawResourceLineage.size());
for (Resource resource : rawResourceLineage) {
boolean isLocked = !(isInventoryManager || authorizationManager.canViewResource(subject, resource.getId()));
ResourceLineageComposite composite = new ResourceLineageComposite(resource, isLocked);
@@ -776,8 +775,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
// If the ancestor is not locked, include viewable children.
if (!ancestor.isLocked() || ancestor.getResource() == parent) {
// Get all viewable committed children.
- PageList<Resource> children = findChildResourcesByCategoryAndInventoryStatus(subject, ancestor
- .getResource(), null, InventoryStatus.COMMITTED, PageControl.getUnlimitedInstance());
+ PageList<Resource> children = findChildResourcesByCategoryAndInventoryStatus(subject,
+ ancestor.getResource(), null, InventoryStatus.COMMITTED, PageControl.getUnlimitedInstance());
// Remove any that are in the lineage to avoid repeated handling.
children.removeAll(rawResourceLineage);
for (Resource child : children) {
@@ -1384,7 +1383,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return result;
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public List<AutoGroupComposite> findResourcesAutoGroups(Subject subject, int[] resourceIds) {
List<AutoGroupComposite> results = new ArrayList<AutoGroupComposite>();
List<Integer> ids = ArrayUtils.wrapInList(resourceIds);
@@ -1484,6 +1483,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
query.setParameter("inventoryStatus", InventoryStatus.COMMITTED);
List<Object[]> objs = query.getResultList();
+ @SuppressWarnings("rawtypes")
List results = new ArrayList<ResourceWithAvailability>(objs.size());
for (Object[] ob : objs) {
Resource r = (Resource) ob[0];
@@ -1814,7 +1814,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -1847,7 +1847,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -1890,7 +1890,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -2396,7 +2396,6 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return results;
}
- @SuppressWarnings("unchecked")
public PageList<ResourceComposite> findResourceCompositesByCriteria(Subject subject, ResourceCriteria criteria) {
boolean isInventoryManager = authorizationManager.isInventoryManager(subject);
@@ -2440,8 +2439,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
subject.getId());
}
- CriteriaQueryRunner<ResourceComposite> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager, false); // don't auto-init bags, we're returning composites not entities
+ CriteriaQueryRunner<ResourceComposite> queryRunner = new CriteriaQueryRunner<ResourceComposite>(criteria,
+ generator, entityManager, false); // don't auto-init bags, we're returning composites not entities
PageList<ResourceComposite> results = queryRunner.execute();
for (ResourceComposite nextComposite : results) {
@@ -2456,7 +2455,6 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return results;
}
- @SuppressWarnings("unchecked")
public PageList<Resource> findResourcesByCriteria(Subject subject, ResourceCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2470,7 +2468,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
subject.getId());
}
- CriteriaQueryRunner<Resource> queryRunner = new CriteriaQueryRunner(criteria, generator, entityManager);
+ CriteriaQueryRunner<Resource> queryRunner = new CriteriaQueryRunner<Resource>(criteria, generator,
+ entityManager);
PageList<Resource> results = queryRunner.execute();
return results;
}
@@ -2521,8 +2520,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
public <T> List<DisambiguationReport<T>> disambiguate(List<T> results, IntExtractor<? super T> extractor,
DisambiguationUpdateStrategy updateStrategy) {
- return Disambiguator.disambiguate(results, updateStrategy, extractor, entityManager, typeManager
- .getDuplicateTypeNames());
+ return Disambiguator.disambiguate(results, updateStrategy, extractor, entityManager,
+ typeManager.getDuplicateTypeNames());
}
public void updateAncestry(Subject subject, int resourceId) {
@@ -2545,13 +2544,13 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
@SuppressWarnings("unchecked")
public List<Integer> findIdsByTypeIds(List<Integer> resourceTypeIds) {
- return entityManager.createNamedQuery(Resource.QUERY_FIND_IDS_BY_TYPE_IDS).setParameter("resourceTypeIds",
- resourceTypeIds).getResultList();
+ return entityManager.createNamedQuery(Resource.QUERY_FIND_IDS_BY_TYPE_IDS)
+ .setParameter("resourceTypeIds", resourceTypeIds).getResultList();
}
@Override
public Integer getResourceCount(List<Integer> resourceTypeIds) {
- return (Integer) entityManager.createNamedQuery(Resource.QUERY_FIND_COUNT_BY_TYPES).setParameter(
- "resourceTypeIds", resourceTypeIds).getSingleResult();
+ return (Integer) entityManager.createNamedQuery(Resource.QUERY_FIND_COUNT_BY_TYPES)
+ .setParameter("resourceTypeIds", resourceTypeIds).getSingleResult();
}
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
index 3963f9d..841fe03 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
@@ -1,6 +1,5 @@
package org.rhq.enterprise.server.resource.metadata;
-import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
@@ -58,8 +57,8 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
// all new
if (existingConfigurationDefinition == null) {
if (log.isDebugEnabled()) {
- log.debug(existingType + " currently does not have a plugin configuration definition. Adding " +
- "new plugin configuration.");
+ log.debug(existingType + " currently does not have a plugin configuration definition. Adding "
+ + "new plugin configuration.");
}
entityMgr.persist(newType.getPluginConfigurationDefinition());
existingType.setPluginConfigurationDefinition(newType.getPluginConfigurationDefinition());
@@ -72,8 +71,8 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
.updateConfigurationDefinition(newType.getPluginConfigurationDefinition(),
existingConfigurationDefinition);
- if (updateReport.getNewPropertyDefinitions().size() > 0 ||
- updateReport.getUpdatedPropertyDefinitions().size() > 0) {
+ if (updateReport.getNewPropertyDefinitions().size() > 0
+ || updateReport.getUpdatedPropertyDefinitions().size() > 0) {
Subject overlord = subjectMgr.getOverlord();
ResourceCriteria criteria = new ResourceCriteria();
criteria.addFilterResourceTypeId(existingType.getId());
@@ -99,6 +98,7 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
private void updateResourcePluginConfiguration(Resource resource, ConfigurationDefinitionUpdateReport updateReport) {
Configuration pluginConfiguration = resource.getPluginConfiguration();
boolean modified = false;
+ @SuppressWarnings("unused")
int numberOfProperties = pluginConfiguration.getProperties().size();
ConfigurationTemplate template = updateReport.getConfigurationDefinition().getDefaultTemplate();
Configuration templateConfiguration = template.getConfiguration();
@@ -106,10 +106,10 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
for (PropertyDefinition propertyDef : updateReport.getNewPropertyDefinitions()) {
if (propertyDef.isRequired()) {
Property templateProperty = templateConfiguration.get(propertyDef.getName());
- if (templateProperty==null) {
+ if (templateProperty == null) {
throw new IllegalArgumentException("The property [" + propertyDef.getName()
- + "] marked as required in the configuration definition of [" + propertyDef.getConfigurationDefinition().getName()
- + "] has no attribute 'default'");
+ + "] marked as required in the configuration definition of ["
+ + propertyDef.getConfigurationDefinition().getName() + "] has no attribute 'default'");
} else {
pluginConfiguration.put(templateProperty.deepCopy(false));
modified = true;
@@ -129,7 +129,7 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
}
if (modified) {
- resource.setMtime(new Date().getTime());
+ resource.setAgentSynchronizationNeeded();
}
}
}
commit e80294f5775b38e4e99c242aef4cbfcc01fd2c45
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 13:15:04 2012 -0500
Add a demarcation comment for JON 3.0.1
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index f005ff0..7dd68d4 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -3828,6 +3828,8 @@
</schema-directSQL>
</schemaSpec>
+<!-- JON 3.0.1 RELEASE uses DB Schema 2.118 -->
+
</dbupgrade>
</target>
</project>
commit b7faba1d8d376f32407fa306db7c0a5df4d63585
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Dec 15 13:16:59 2011 -0500
Supporting check-in for [Bug 768031 - Pin template failure on upgraded dbs]
- Fix a long standing issue in dbupgrade due to Oracle throwing exceptions
when trying to set nullable to the current value. In other words, the
upgrade would fail on oracle if you tried to set nullable false on a
column that was already nullable false. (same for nullable true). This
caused issues when you can't guarantee the current state, you just know
what you need it to be. Now, catch the relevant exceptions and toss
them as needed.
diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java
index afd9ed9..ad038b0 100644
--- a/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java
+++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/OracleDatabaseType.java
@@ -25,6 +25,8 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
+import mazz.i18n.Logger;
+
/**
* Superclass of all versions of the Oracle database.
*
@@ -32,6 +34,8 @@ import java.util.List;
*
*/
public abstract class OracleDatabaseType extends DatabaseType {
+ private static final Logger LOG = DbUtilsI18NFactory.getLogger(OracleDatabaseType.class);
+
/**
* The vendor name for all Oracle databases.
*/
@@ -156,7 +160,24 @@ public abstract class OracleDatabaseType extends DatabaseType {
sql += ")";
- executeSql(conn, sql);
+ try {
+ executeSql(conn, sql);
+ } catch (SQLException e) {
+ // Oracle throws an exception if you try to set nullable to its current setting. Ignore errors
+ // generated when a nullable setting is already the way we want it to be.
+ // ORA-01442: column to be modified to NOT NULL is already NOT NULL
+ // ORA-01451: column to be modified to NULL cannot be modified to NULL
+ if (nullable != null) {
+ String msg = e.getMessage();
+ if (msg.contains("ORA-01442") || msg.contains("ORA-01451")) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Ignoring exception, column already set to nullable=" + nullable, e);
+ }
+ } else {
+ throw e;
+ }
+ }
+ }
if ((reindex != null) && reindex.booleanValue()) {
reindexTable(conn, table);
commit 8667a4c591e4ef6f803d0b485e3e7cfda76f3440
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Dec 15 13:18:32 2011 -0500
[Bug 768031 - Pin template failure on upgraded dbs]
Set RHQ_DRIFT_CHANGE_SET.DRIFT_DEFINITION_ID nullable in the db upgrade.
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index b77d98a..f005ff0 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -3813,7 +3813,10 @@
<schemaSpec version="2.117">
<!-- Remove an obsolete drift table that may be hanging around -->
- <schema-dropTable table="RHQ_DRIFT_TEMPLATE_MAP" />
+ <schema-dropTable table="RHQ_DRIFT_TEMPLATE_MAP" />
+
+ <!-- Remove an unwanted null consraint -->
+ <schema-alterColumn table="RHQ_DRIFT_CHANGE_SET" column="DRIFT_DEFINITION_ID" nullable="TRUE" />
</schemaSpec>
<schemaSpec version="2.118">
commit 8b8ce32cf7bc2ab04c28d9717911007878ba895a
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 9 15:45:21 2012 -0500
[Bug 772742 - DB upgrade gives "All Resources Role" an unintended permission]
Fix the upgrade step that grants the bad permission. And add a new
step to revoke it if it exists.
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml
index f08d22d..f58d07d 100644
--- a/modules/core/dbutils/pom.xml
+++ b/modules/core/dbutils/pom.xml
@@ -15,7 +15,7 @@
<description>Database schema setup, upgrade and other utilities</description>
<properties>
- <db.schema.version>2.117</db.schema.version>
+ <db.schema.version>2.118</db.schema.version>
<rhq.ds.type-mapping>${rhq.test.ds.type-mapping}</rhq.ds.type-mapping>
<rhq.ds.db-name>${rhq.test.ds.db-name}</rhq.ds.db-name>
<rhq.ds.connection-url>${rhq.test.ds.connection-url}</rhq.ds.connection-url>
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index c690317..b77d98a 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -3370,12 +3370,12 @@
</statement>
</schema-directSQL>
- <!-- Now add modify the permissions to give all the roles with MANAGE_INVENTORY
- the new MANAGE_REPOSITORIES privilege so that people's privs remain unchanged. -->
+ <!-- Now modify the permissions to give all the roles with MANAGE_INVENTORY, except for
+ all-resources-role, the new MANAGE_REPOSITORIES privilege so that privs remain unchanged. -->
<schema-directSQL>
<statement>
INSERT INTO RHQ_PERMISSION (role_id, operation)
- SELECT role_id, 15 FROM RHQ_PERMISSION WHERE operation = 1
+ SELECT role_id, 15 FROM RHQ_PERMISSION WHERE operation = 1 AND NOT role_id = 2
</statement>
</schema-directSQL>
</schemaSpec>
@@ -3815,6 +3815,15 @@
<!-- Remove an obsolete drift table that may be hanging around -->
<schema-dropTable table="RHQ_DRIFT_TEMPLATE_MAP" />
</schemaSpec>
+
+ <schemaSpec version="2.118">
+ <!-- Correct an earlier upgrade issue where 'All Resources Role' was granted MANAGE_REPOSITORIES. -->
+ <schema-directSQL>
+ <statement>
+ DELETE FROM RHQ_PERMISSION WHERE role_id = 2 AND operation = 15
+ </statement>
+ </schema-directSQL>
+ </schemaSpec>
</dbupgrade>
</target>
commit fb7177edccdd59a8f33cdc1253d6d02428ea51b5
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 12:21:44 2012 -0500
Add 2.117 to remove an obsolete drift table that may exist after upgrades.
Conflicts:
modules/core/dbutils/pom.xml
modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml
index b298636..f08d22d 100644
--- a/modules/core/dbutils/pom.xml
+++ b/modules/core/dbutils/pom.xml
@@ -14,14 +14,8 @@
<name>RHQ Database Utilities</name>
<description>Database schema setup, upgrade and other utilities</description>
- <scm>
- <connection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/core/dbutils</connection>
- <developerConnection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/core/dbutils</developerConnection>
- </scm>
-
<properties>
- <scm.module.path>modules/core/dbutils/</scm.module.path>
- <db.schema.version>2.116</db.schema.version>
+ <db.schema.version>2.117</db.schema.version>
<rhq.ds.type-mapping>${rhq.test.ds.type-mapping}</rhq.ds.type-mapping>
<rhq.ds.db-name>${rhq.test.ds.db-name}</rhq.ds.db-name>
<rhq.ds.connection-url>${rhq.test.ds.connection-url}</rhq.ds.connection-url>
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index fb2ed85..c690317 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -3809,6 +3809,13 @@
<schema-alterColumn table="RHQ_PRD_VER" column="VERSION" columnType="VARCHAR2" precision="100" />
</schemaSpec>
+<!-- JON 3.0 RELEASE uses DB Schema 2.116 -->
+
+ <schemaSpec version="2.117">
+ <!-- Remove an obsolete drift table that may be hanging around -->
+ <schema-dropTable table="RHQ_DRIFT_TEMPLATE_MAP" />
+ </schemaSpec>
+
</dbupgrade>
</target>
</project>
commit 22da9591737868d71ccc70474fe3701434ec8385
Merge: 371ed2f f808b1f
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 30 22:27:20 2012 -0500
Merge branch 'release/jon3.0.x' of ssh://git.fedorahosted.org/git/rhq/rhq into release/jon3.0.x
commit 371ed2faefd38ca58d514bb95793978de4a4fa46
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 30 22:25:35 2012 -0500
[BZ 785026] if log file event sources are enabled, but SIGAR is disabled or unavailable, log a warning, rather than
silently failing (https://bugzilla.redhat.com/show_bug.cgi?id=785026)
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
index f9bb654..8651272 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
@@ -22,6 +22,7 @@
*/
package org.rhq.core.pluginapi.event;
+import com.sun.istack.Nullable;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
@@ -90,10 +91,10 @@ public interface EventContext {
/**
* Gets an instance of Sigar. Plugins that need to use Sigar, should use this method to get an instance, rather than
- * instantiating Sigar themselves.
+ * instantiating Sigar themselves. Returns null if the native layer is unavailable or has been disabled.
*
- * @return an instance of Sigar
+ * @return an instance of Sigar, or null if the native layer is unavailable or has been disabled
*/
- @NotNull
+ @Nullable
SigarProxy getSigar();
}
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
index d936522..bcc42de 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
@@ -1,6 +1,6 @@
- /*
+/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -55,13 +55,17 @@ public class LogFileEventPoller implements EventPoller {
private LogEntryProcessor entryProcessor;
public LogFileEventPoller(EventContext eventContext, String eventType, File logFile, LogEntryProcessor entryProcessor) {
+ SigarProxy sigar = eventContext.getSigar();
this.eventType = eventType;
this.logFile = logFile;
- SigarProxy sigar = eventContext.getSigar();
- try {
- this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
- } catch (SigarException e) {
- throw new RuntimeException(e);
+ if (sigar != null) {
+ try {
+ this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
+ } catch (SigarException e) {
+ throw new RuntimeException("Failed to obtain file info for log file [" + this.logFile + "].", e);
+ }
+ } else {
+ log.warn("SIGAR is unavailable - cannot poll log file [" + this.logFile + "] for events.");
}
this.entryProcessor = entryProcessor;
}
@@ -78,12 +82,15 @@ public class LogFileEventPoller implements EventPoller {
@Nullable
public Set<Event> poll() {
+ if (this.logFileInfo == null) {
+ return null;
+ }
if (!this.logFile.exists()) {
- log.warn("Log file [" + this.logFile + "' being polled does not exist.");
+ log.warn("Log file [" + this.logFile + "] being polled does not exist.");
return null;
}
if (this.logFile.isDirectory()) {
- log.error("Log file [" + this.logFile + "' being polled is a directory, not a regular file.");
+ log.error("Log file [" + this.logFile + "] being polled is a directory, not a regular file.");
return null;
}
try {
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
index 962764a..d134638 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,9 @@ package org.rhq.core.pluginapi.event.log;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -32,10 +35,12 @@ import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.event.EventSeverity;
+import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.event.EventContext;
import org.rhq.core.pluginapi.event.EventPoller;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.core.system.SystemInfoFactory;
/**
* @author Ian Springer
@@ -47,83 +52,132 @@ public class LogFileEventResourceComponentHelper {
public static final String LOG_EVENT_SOURCE_CONFIG_PROP = "logEventSource";
public abstract static class LogEventSourcePropertyNames {
- public static final String LOG_FILE_PATH = "logFilePath";
- public static final String ENABLED = "enabled";
- public static final String DATE_FORMAT = "dateFormat";
- public static final String INCLUDES_PATTERN = "includesPattern";
- public static final String MINIMUM_SEVERITY = "minimumSeverity";
+ public static final String LOG_FILE_PATH = "logFilePath"; // required
+ public static final String ENABLED = "enabled"; // required
+ public static final String DATE_FORMAT = "dateFormat"; // optional
+ public static final String INCLUDES_PATTERN = "includesPattern"; // optional
+ public static final String MINIMUM_SEVERITY = "minimumSeverity"; // optional
}
+ // TODO: Make this configurable via a plugin config prop.
+ private static final int POLLING_INTERVAL_IN_SECONDS = 60;
+
private final Log log = LogFactory.getLog(this.getClass());
private ResourceContext<?> resourceContext;
+ private List<PropertyMap> startedEventSources = new ArrayList<PropertyMap>();
public LogFileEventResourceComponentHelper(ResourceContext<?> resourceContext) {
this.resourceContext = resourceContext;
}
public void startLogFileEventPollers() {
+ // Grab the list-o-maps of event sources from the plugin config.
Configuration pluginConfig = this.resourceContext.getPluginConfiguration();
PropertyList logEventSources = pluginConfig.getList(LOG_EVENT_SOURCES_CONFIG_PROP);
+
+ // Build a new list containing the event sources that are enabled.
+ List<PropertyMap> enabledEventSources = new ArrayList<PropertyMap>();
for (Property prop : logEventSources.getList()) {
PropertyMap logEventSource = (PropertyMap) prop;
- Boolean enabled = Boolean.valueOf(logEventSource.getSimpleValue(LogEventSourcePropertyNames.ENABLED, null));
- if (enabled) {
- String logFilePathname = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
- if (logFilePathname == null) {
- log.info("LOGFILE: No logfile path given, can not watch this event log.");
- return;
- }
- File logFile = new File(logFilePathname);
- if (!logFile.exists() || !logFile.canRead()) {
- log.error("LOGFILE: Logfile at location " + logFilePathname
- + " does not exist or is not readable. Can not start watching the event log.");
- return;
- }
+ String enabled = logEventSource.getSimpleValue(LogEventSourcePropertyNames.ENABLED, null);
+ if (enabled == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.ENABLED
+ + "] is not defined in map.");
+ }
+ if (Boolean.valueOf(enabled)) {
+ enabledEventSources.add(logEventSource);
+ }
+ }
- Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(LOG_ENTRY_EVENT_TYPE, logFile);
- String dateFormatString = logEventSource.getSimpleValue(LogEventSourcePropertyNames.DATE_FORMAT, null);
- if (dateFormatString != null) {
- try {
- DateFormat dateFormat = new SimpleDateFormat(dateFormatString); // TODO locale specific ?
- processor.setDateFormat(dateFormat);
- } catch (IllegalArgumentException e) {
- throw new InvalidPluginConfigurationException("Date format [" + dateFormatString
- + "] is not a valid simple date format.");
- }
- }
- String includesPatternString = logEventSource.getSimpleValue(
- LogEventSourcePropertyNames.INCLUDES_PATTERN, null);
- if (includesPatternString != null) {
- try {
- Pattern includesPattern = Pattern.compile(includesPatternString);
- processor.setIncludesPattern(includesPattern);
- } catch (PatternSyntaxException e) {
- throw new InvalidPluginConfigurationException("Includes pattern [" + includesPatternString
- + "] is not a valid regular expression.");
- }
+ // Log a warning then return if SIGAR isn't available, since LogFileEventPoller depends on it. We only log this
+ // warning if at least one event source is enabled, since otherwise the user probably doesn't care.
+ boolean sigarAvailable = this.resourceContext.getSystemInformation().isNative();
+ if (!sigarAvailable && !enabledEventSources.isEmpty()) {
+ boolean nativeSystemInfoDisabled = SystemInfoFactory.isNativeSystemInfoDisabled();
+ ResourceType resourceType = this.resourceContext.getResourceType();
+ List<String> logFilePaths = getLogFilePaths(enabledEventSources);
+ log.warn("Log files " + logFilePaths + " for [" + resourceType.getPlugin() + ":"
+ + resourceType.getName() + "] Resource with key [" + this.resourceContext.getResourceKey()
+ + "] cannot be polled, because log file polling requires RHQ native support, which "
+ + ((nativeSystemInfoDisabled) ? "has been disabled for this Agent" : "is not available on this platform") + ".");
+ return;
+ }
+
+ // Start up log file pollers for each of the enabled event sources.
+ for (PropertyMap logEventSource : enabledEventSources) {
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ if (logFilePath == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.LOG_FILE_PATH
+ + "] is not defined in map.");
+ }
+ File logFile = new File(logFilePath);
+ if (!logFile.canRead()) {
+ log.error("LOGFILE: Logfile at location " + logFilePath
+ + " does not exist or is not readable. Can not start watching the event log.");
+ continue;
+ }
+
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(LOG_ENTRY_EVENT_TYPE, logFile);
+ String dateFormatString = logEventSource.getSimpleValue(LogEventSourcePropertyNames.DATE_FORMAT, null);
+ if (dateFormatString != null) {
+ try {
+ DateFormat dateFormat = new SimpleDateFormat(dateFormatString); // TODO locale specific ?
+ processor.setDateFormat(dateFormat);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidPluginConfigurationException("Date format [" + dateFormatString
+ + "] is not a valid simple date format.");
}
- String minimumSeverityString = logEventSource.getSimpleValue(
- LogEventSourcePropertyNames.MINIMUM_SEVERITY, null);
- if (minimumSeverityString != null) {
- EventSeverity minimumSeverity = EventSeverity.valueOf(minimumSeverityString.toUpperCase());
- processor.setMinimumSeverity(minimumSeverity);
+ }
+ String includesPatternString = logEventSource.getSimpleValue(
+ LogEventSourcePropertyNames.INCLUDES_PATTERN, null);
+ if (includesPatternString != null) {
+ try {
+ Pattern includesPattern = Pattern.compile(includesPatternString);
+ processor.setIncludesPattern(includesPattern);
+ } catch (PatternSyntaxException e) {
+ throw new InvalidPluginConfigurationException("Includes pattern [" + includesPatternString
+ + "] is not a valid regular expression.");
}
- EventContext eventContext = this.resourceContext.getEventContext();
- EventPoller poller = new LogFileEventPoller(eventContext, LOG_ENTRY_EVENT_TYPE, logFile, processor);
- eventContext.registerEventPoller(poller, 60, logFile.getPath());
}
+ String minimumSeverityString = logEventSource.getSimpleValue(
+ LogEventSourcePropertyNames.MINIMUM_SEVERITY, null);
+ if (minimumSeverityString != null) {
+ EventSeverity minimumSeverity = EventSeverity.valueOf(minimumSeverityString.toUpperCase());
+ processor.setMinimumSeverity(minimumSeverity);
+ }
+ EventContext eventContext = this.resourceContext.getEventContext();
+ EventPoller poller = new LogFileEventPoller(eventContext, LOG_ENTRY_EVENT_TYPE, logFile, processor);
+ eventContext.registerEventPoller(poller, POLLING_INTERVAL_IN_SECONDS, logFile.getPath());
+ this.startedEventSources.add(logEventSource);
}
}
public void stopLogFileEventPollers() {
- Configuration pluginConfig = this.resourceContext.getPluginConfiguration();
- PropertyList logEventSources = pluginConfig.getList(LOG_EVENT_SOURCES_CONFIG_PROP);
- for (Property prop : logEventSources.getList()) {
- PropertyMap logEventSource = (PropertyMap) prop;
- String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ boolean sigarAvailable = this.resourceContext.getSystemInformation().isNative();
+ if (!sigarAvailable) {
+ return;
+ }
+
+ for (Iterator<PropertyMap> iterator = this.startedEventSources.iterator(); iterator.hasNext(); ) {
+ PropertyMap logEventSource = iterator.next();
EventContext eventContext = this.resourceContext.getEventContext();
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
eventContext.unregisterEventPoller(LOG_ENTRY_EVENT_TYPE, logFilePath);
+ iterator.remove();
+ }
+ }
+
+ private List<String> getLogFilePaths(List<PropertyMap> enabledEventSources) {
+ List<String> logFilePaths = new ArrayList<String>(enabledEventSources.size());
+ for (PropertyMap logEventSource : enabledEventSources) {
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ if (logFilePath == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.LOG_FILE_PATH
+ + "] is not defined in map.");
+ }
+ logFilePaths.add(logFilePath);
}
+ return logFilePaths;
}
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
index b0b37ec..1735aff 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
@@ -24,6 +24,7 @@ package org.rhq.core.pc.event;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventDefinition;
import org.rhq.core.domain.resource.Resource;
@@ -99,7 +100,7 @@ public class EventContextImpl implements EventContext {
unregisterEventPollerInternal(eventType, sourceLocation);
}
- @NotNull
+ @Nullable
public SigarProxy getSigar() {
return getEventManager().getSigar();
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
index 4ad5c50..87b9bd7 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
@@ -34,6 +34,7 @@ import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventDefinition;
import org.rhq.core.domain.event.EventSource;
@@ -44,6 +45,7 @@ import org.rhq.core.pc.PluginContainerConfiguration;
import org.rhq.core.pc.util.LoggingThreadFactory;
import org.rhq.core.pluginapi.event.EventPoller;
import org.rhq.core.system.SigarAccess;
+import org.rhq.core.system.SystemInfoException;
/**
* Manager for the Plugin Container's Event subsystem.
@@ -113,9 +115,12 @@ public class EventManager implements ContainerService {
}
}
+ @Nullable
SigarProxy getSigar() {
if (this.sigar == null) {
- this.sigar = SigarAccess.getSigar();
+ if (SigarAccess.isSigarAvailable()) {
+ this.sigar = SigarAccess.getSigar();
+ }
}
return this.sigar;
}
commit f808b1f8c4837661862825538dd497afc1b671be
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Thu Jan 26 17:37:21 2012 -0500
BZ[784873] fixing issue displaying LDAP registration screen with clean browser cache.
i)Can't count on CoreGUI to be loaded in this case as the user may not have logged in before.
ii)Some refactoring to embed asynchronous call.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
index 74d11e3..50c87a4 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
@@ -103,6 +103,7 @@ public class LoginView extends LocatableCanvas {
private static final String DEPARTMENT = "department";
private static final String SESSIONID = "ldap.sessionid";
static final String PASSWORD = "ldap.password";
+ private ProductInfo productInfo;
public void showLoginDialog(String message) {
showLoginDialog();
@@ -206,195 +207,232 @@ public class LoginView extends LocatableCanvas {
if (!loginShowing) {
loginShowing = true;
- ProductInfo productInfo = CoreGUI.get().getProductInfo();
-
- int fieldWidth = 120;
-
- LocatableVLayout column = new LocatableVLayout(extendLocatorId("NewLdapRegistration"));
- column.setMargin(25);
- HeaderItem header = new HeaderItem();
- header.setValue(MSG.view_login_welcomeMsg(productInfo.getName()));
- header.setWidth("100%");
- //build ui elements for registration screen
- first = new TextItem(FIRST, MSG.dataSource_users_field_firstName());
- {
- first.setRequired(true);
- first.setWrapTitle(false);
- first.setWidth(fieldWidth);
- }
- last = new TextItem(LAST, MSG.dataSource_users_field_lastName());
- {
- last.setWrapTitle(false);
- last.setWidth(fieldWidth);
- last.setRequired(true);
- }
- final TextItem username = new TextItem(USERNAME, MSG.dataSource_users_field_name());
- {
- username.setValue(user);
- username.setDisabled(true);
- username.setWidth(fieldWidth);
- }
- email = new TextItem(EMAIL, MSG.dataSource_users_field_emailAddress());
- email.setRequired(true);
- email.setWidth(fieldWidth);
- email.setWrapTitle(false);
- phone = new TextItem(PHONE, MSG.dataSource_users_field_phoneNumber());
- phone.setWidth(fieldWidth);
- phone.setWrapTitle(false);
- department = new TextItem(DEPARTMENT, MSG.dataSource_users_field_department());
- department.setWidth(fieldWidth);
- SpacerItem space = new SpacerItem();
- space.setColSpan(1);
-
- inputForm = new LocatableDynamicForm(extendLocatorId("LdapUserRegistrationInput"));
- inputForm.setAutoFocus(true);
- inputForm.setErrorOrientation(FormErrorOrientation.LEFT);
- inputForm.setNumCols(4);
- //moving header to it's own container for proper display. Didn't display right in production mode
- inputForm.setFields(username, first, last, email, phone, department);
- loadValidators(inputForm);
- inputForm.setValidateOnExit(true);
- DynamicForm headerWrapper = new DynamicForm();
- headerWrapper.setFields(header);
- column.addMember(headerWrapper);
- column.addMember(inputForm);
-
- HTMLFlow hr = new HTMLFlow("<br/><hr/><br/><br/>");
- hr.setWidth(620);
- hr.setAlign(Alignment.CENTER);
- column.addMember(hr);
-
- HStack row = new HStack();
- row.setMembersMargin(5);
- row.setAlign(VerticalAlignment.CENTER);
- IButton okButton = new LocatableIButton(inputForm.extendLocatorId("OK"), MSG.common_button_ok());
- okButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
-
- //F5 refresh check? If they've reloaded the form for some reason then bail.
- boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
- .trim().isEmpty()));
- //check for session timeout
- if (UserSessionManager.isLoggedOut() || (credentialsEmpty)) {
- resetLogin(LoginView.this.extendLocatorId("Register"));
- return;
+ //BZ:784873. To fix issue with users logging in by LDAP integration with clean browser cache.
+ if (CoreGUI.get().getProductInfo() == null) {
+ //We need to explicitly retrieve product info here as can't count on CoreGui to load it
+ //during LDAP registration. After registration CoreGui is loaded as usual.
+ GWTServiceLookup.getSystemService().getProductInfo(new AsyncCallback<ProductInfo>() {
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_aboutBox_failedToLoad(), caught);
+ productInfo = null;
+ Log.trace("ProductInfo could not be retrieved for some reason. Proceeding anyway.");
+ buildRegistrationWindow(user, sessionId, password, callback);
}
- //validation
- if (inputForm.validate()) {
- Log.trace("Successfully validated all data for user registration.");
- //populate form
- if (first.getValue() != null)
- inputForm.setValue(FIRST, String.valueOf(first.getValue()));
- if (last.getValue() != null)
- inputForm.setValue(LAST, String.valueOf(last.getValue()));
- inputForm.setValue(USERNAME, String.valueOf(username.getValue()));
- if (email.getValue() != null)
- inputForm.setValue(EMAIL, String.valueOf(email.getValue()));
- if (phone.getValue() != null)
- inputForm.setValue(PHONE, String.valueOf(phone.getValue()));
- if (department.getValue() != null)
- inputForm.setValue(DEPARTMENT, String.valueOf(department.getValue()));
- inputForm.setValue(SESSIONID, sessionId);
- inputForm.setValue(PASSWORD, password);
- registerLdapUser(LoginView.this.extendLocatorId("RegisterLdap"), inputForm, callback);
+ public void onSuccess(ProductInfo result) {
+ productInfo = result;
+ Log.trace("ProductInfo has been retrieved for LDAP registration.");
+ buildRegistrationWindow(user, sessionId, password, callback);
}
- }
+ });
+ } else {//if productInfo has already been loaded, save a gwt call.
+ productInfo = CoreGUI.get().getProductInfo();
+ buildRegistrationWindow(user, sessionId, password, callback);
+ }
+ }
+ }
- });
- row.addMember(okButton);
- //send request to LDAP server to grab user details for this user. Already sure ldap user exists
- GWTServiceLookup.getLdapService().getLdapDetailsFor(user, new AsyncCallback<Map<String, String>>() {
- public void onSuccess(final Map<String, String> ldapUserDetails) {
- //now prepopulate UI fields if they exist
- for (String key : ldapUserDetails.keySet()) {
- String value;
- if (key.equalsIgnoreCase("givenName")) {//aka first name
- value = ldapUserDetails.get(key);
- first.setValue(value);
- } else if (key.equalsIgnoreCase("sn")) {//aka Surname
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- last.setValue(value);
- }
- } else if (key.equalsIgnoreCase("telephoneNumber")) {
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- phone.setValue(value);
- }
- } else if (key.equalsIgnoreCase("mail")) {
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- email.setValue(value);
- }
- }
- }
+ /** Duplicate modal Login mechanism to now show last registration screen before launching
+ * core gui.
+ *
+ * @param user prepopulate username field for LDAP registration
+ * @param sessionId pass in valid session id for LDAP registration steps.
+ * @param callback pass in callback reference to indicate success and launch of coreGUI
+ */
+ private void buildRegistrationWindow(final String user, final String sessionId, final String password,
+ final AsyncCallback<Subject> callback) {
+ int fieldWidth = 120;
+
+ //Build registration window.
+ LocatableVLayout column = new LocatableVLayout(extendLocatorId("NewLdapRegistration"));
+ column.setMargin(25);
+ HeaderItem header = new HeaderItem();
+ //Locate product info for registration screen.
+ if (productInfo != null) {
+ header.setValue(MSG.view_login_welcomeMsg(productInfo.getName()));
+ } else {//if not available, let registration continue. Errors already logged and no functionality lost.
+ header.setValue(MSG.view_login_welcomeMsg(""));
+ }
+ header.setWidth("100%");
+ //build ui elements for registration screen
+ first = new TextItem(FIRST, MSG.dataSource_users_field_firstName());
+ {
+ first.setRequired(true);
+ first.setWrapTitle(false);
+ first.setWidth(fieldWidth);
+ }
+ last = new TextItem(LAST, MSG.dataSource_users_field_lastName());
+ {
+ last.setWrapTitle(false);
+ last.setWidth(fieldWidth);
+ last.setRequired(true);
+ }
+ final TextItem username = new TextItem(USERNAME, MSG.dataSource_users_field_name());
+ {
+ username.setValue(user);
+ username.setDisabled(true);
+ username.setWidth(fieldWidth);
+ }
+ email = new TextItem(EMAIL, MSG.dataSource_users_field_emailAddress());
+ email.setRequired(true);
+ email.setWidth(fieldWidth);
+ email.setWrapTitle(false);
+ phone = new TextItem(PHONE, MSG.dataSource_users_field_phoneNumber());
+ phone.setWidth(fieldWidth);
+ phone.setWrapTitle(false);
+ department = new TextItem(DEPARTMENT, MSG.dataSource_users_field_department());
+ department.setWidth(fieldWidth);
+ SpacerItem space = new SpacerItem();
+ space.setColSpan(1);
+
+ inputForm = new LocatableDynamicForm(extendLocatorId("LdapUserRegistrationInput"));
+ inputForm.setAutoFocus(true);
+ inputForm.setErrorOrientation(FormErrorOrientation.LEFT);
+ inputForm.setNumCols(4);
+ //moving header to it's own container for proper display. Didn't display right in production mode
+ inputForm.setFields(username, first, last, email, phone, department);
+ loadValidators(inputForm);
+ inputForm.setValidateOnExit(true);
+ DynamicForm headerWrapper = new DynamicForm();
+ headerWrapper.setFields(header);
+ column.addMember(headerWrapper);
+ column.addMember(inputForm);
+
+ HTMLFlow hr = new HTMLFlow("<br/><hr/><br/><br/>");
+ hr.setWidth(620);
+ hr.setAlign(Alignment.CENTER);
+ column.addMember(hr);
+
+ HStack row = new HStack();
+ row.setMembersMargin(5);
+ row.setAlign(VerticalAlignment.CENTER);
+ IButton okButton = new LocatableIButton(inputForm.extendLocatorId("OK"), MSG.common_button_ok());
+ okButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+
+ //F5 refresh check? If they've reloaded the form for some reason then bail.
+ boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
+ .trim().isEmpty()));
+ //check for session timeout
+ if (UserSessionManager.isLoggedOut() || (credentialsEmpty)) {
+ resetLogin(LoginView.this.extendLocatorId("Register"));
+ return;
}
- public void onFailure(Throwable caught) {
- inputForm.setFieldErrors(FIRST, MSG.view_login_noLdap(), true);
- Log.debug("Optional LDAP detail retrieval did not succeed. Registration prepopulation will not occur.");
+ //validation
+ if (inputForm.validate()) {
+ Log.trace("Successfully validated all data for user registration.");
+ //populate form
+ if (first.getValue() != null)
+ inputForm.setValue(FIRST, String.valueOf(first.getValue()));
+ if (last.getValue() != null)
+ inputForm.setValue(LAST, String.valueOf(last.getValue()));
+ inputForm.setValue(USERNAME, String.valueOf(username.getValue()));
+ if (email.getValue() != null)
+ inputForm.setValue(EMAIL, String.valueOf(email.getValue()));
+ if (phone.getValue() != null)
+ inputForm.setValue(PHONE, String.valueOf(phone.getValue()));
+ if (department.getValue() != null)
+ inputForm.setValue(DEPARTMENT, String.valueOf(department.getValue()));
+ inputForm.setValue(SESSIONID, sessionId);
+ inputForm.setValue(PASSWORD, password);
+ registerLdapUser(LoginView.this.extendLocatorId("RegisterLdap"), inputForm, callback);
}
- });
-
- IButton resetButton = new LocatableIButton(inputForm.extendLocatorId("Reset"), MSG.common_button_reset());
- resetButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- //F5 refresh check? If they've reloaded the form for some reason then bail.
- boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
- .trim().isEmpty()));
- if (UserSessionManager.isLoggedOut() || credentialsEmpty) {
- resetLogin(LoginView.this.extendLocatorId("Reset"));
- return;
- }
+ }
- //clear out all validation messages.
- {
- String empty = " ";
- first.setValue(empty);
- last.setValue(empty);
- email.setValue("test(a)test.com");
- inputForm.validate();
+ });
+ row.addMember(okButton);
+ //send request to LDAP server to grab user details for this user. Already sure ldap user exists
+ GWTServiceLookup.getLdapService().getLdapDetailsFor(user, new AsyncCallback<Map<String, String>>() {
+ public void onSuccess(final Map<String, String> ldapUserDetails) {
+ //now prepopulate UI fields if they exist
+ for (String key : ldapUserDetails.keySet()) {
+ String value;
+ if (key.equalsIgnoreCase("givenName")) {//aka first name
+ value = ldapUserDetails.get(key);
+ first.setValue(value);
+ } else if (key.equalsIgnoreCase("sn")) {//aka Surname
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ last.setValue(value);
+ }
+ } else if (key.equalsIgnoreCase("telephoneNumber")) {
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ phone.setValue(value);
+ }
+ } else if (key.equalsIgnoreCase("mail")) {
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ email.setValue(value);
+ }
}
- first.clearValue();
- last.clearValue();
- email.clearValue();
- phone.clearValue();
- department.clearValue();
}
- });
- row.addMember(resetButton);
+ }
- IButton cancelButton = new LocatableIButton(inputForm.extendLocatorId("Cancel"), MSG.common_button_cancel());
- cancelButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- UserSessionManager.logout();
+ public void onFailure(Throwable caught) {
+ inputForm.setFieldErrors(FIRST, MSG.view_login_noLdap(), true);
+ Log.debug("Optional LDAP detail retrieval did not succeed. Registration prepopulation will not occur.");
+ }
+ });
+
+ IButton resetButton = new LocatableIButton(inputForm.extendLocatorId("Reset"), MSG.common_button_reset());
+ resetButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ //F5 refresh check? If they've reloaded the form for some reason then bail.
+ boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
+ .trim().isEmpty()));
+ if (UserSessionManager.isLoggedOut() || credentialsEmpty) {
resetLogin(LoginView.this.extendLocatorId("Reset"));
+ return;
}
- });
- row.addMember(cancelButton);
- Label logoutLabel = new Label(MSG.view_login_registerLater());
- logoutLabel.setWrap(false);
- row.addMember(logoutLabel);
- column.addMember(row);
-
- window = new LocatableWindow(extendLocatorId("RegistrationWindow"));
- window.setWidth(670);
- window.setHeight(330);
- window.setTitle(MSG.view_login_registerUser());
- // forced focused, static size, can't close / dismiss
- window.setIsModal(true);
- window.setShowModalMask(true);
- window.setCanDragResize(false);
- window.setCanDragReposition(false);
- window.setShowCloseButton(false);
- window.setShowMinimizeButton(false);
- window.setAutoCenter(true);
-
- window.addItem(column);
- window.show();
- }
+ //clear out all validation messages.
+ {
+ String empty = " ";
+ first.setValue(empty);
+ last.setValue(empty);
+ email.setValue("test(a)test.com");
+ inputForm.validate();
+ }
+ first.clearValue();
+ last.clearValue();
+ email.clearValue();
+ phone.clearValue();
+ department.clearValue();
+ }
+ });
+ row.addMember(resetButton);
+
+ IButton cancelButton = new LocatableIButton(inputForm.extendLocatorId("Cancel"), MSG.common_button_cancel());
+ cancelButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ UserSessionManager.logout();
+ resetLogin(LoginView.this.extendLocatorId("Reset"));
+ }
+ });
+ row.addMember(cancelButton);
+ Label logoutLabel = new Label(MSG.view_login_registerLater());
+ logoutLabel.setWrap(false);
+ row.addMember(logoutLabel);
+ column.addMember(row);
+
+ window = new LocatableWindow(extendLocatorId("RegistrationWindow"));
+ window.setWidth(670);
+ window.setHeight(330);
+ window.setTitle(MSG.view_login_registerUser());
+
+ // forced focused, static size, can't close / dismiss
+ window.setIsModal(true);
+ window.setShowModalMask(true);
+ window.setCanDragResize(false);
+ window.setCanDragReposition(false);
+ window.setShowCloseButton(false);
+ window.setShowMinimizeButton(false);
+ window.setAutoCenter(true);
+
+ window.addItem(column);
+ window.show();
}
/** Go through steps of invalidating this login and piping them back to CoreGUI Login.
commit a4602636483a6c8a3093dd16e16c97498286bba9
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Dec 20 17:28:21 2011 -0500
[BZ 766574] for some reason, the remote interface was removed from the discovery SLSB. put it back.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index fcb2f9e..2ea6234 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -99,7 +99,7 @@ import org.rhq.enterprise.server.util.LookupUtil;
* @author Greg Hinkle
*/
@Stateless
-public class DiscoveryBossBean implements DiscoveryBossLocal {
+public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemote {
private final Log log = LogFactory.getLog(DiscoveryBossBean.class.getName());
commit 99ff4f9c796c171b74c3e09b404a2c397607a698
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Dec 20 14:40:53 2011 -0500
[BZ 766574] fix NPE if there is no availability yet
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
index 382ce8c..1623039 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
@@ -44,6 +44,7 @@ import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.ResourceAvailability;
import org.rhq.core.domain.resource.ResourceType;
@@ -671,7 +672,8 @@ public class TabularWriter {
} else if (object instanceof ResourceType) {
return ((ResourceType) object).getName();
} else if (object instanceof ResourceAvailability) {
- return ((ResourceAvailability) object).getAvailabilityType().getName();
+ AvailabilityType availType = ((ResourceAvailability) object).getAvailabilityType();
+ return (availType == null) ? "?" : availType.getName();
} else if (object != null && object.getClass().isArray()) {
return Arrays.toString((Object[]) object);
} else {
commit 9b740863e19ec6cde4007f53c4ad76d399d12ecb
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Nov 11 10:41:00 2011 -0500
[BZ 752981] remove duplicate call to FileSystemInfo.refresh(), which was resulting in invalid metric values (https://bugzilla.redhat.com/show_bug.cgi?id=752981); use switch-case rather than if-else in getValues() to make code more readable
(cherry picked from commit 68be8c6fa8086e0c16fa706e3bad3c84b9d8b2fd)
diff --git a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/FileSystemComponent.java b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/FileSystemComponent.java
index 9d68c23..5eae991 100644
--- a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/FileSystemComponent.java
+++ b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/FileSystemComponent.java
@@ -1,6 +1,6 @@
- /*
+/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.measurement.AvailabilityType;
-import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.MeasurementReport;
@@ -39,12 +38,15 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.pluginapi.util.ObjectUtil;
import org.rhq.core.system.FileSystemInfo;
+import org.rhq.core.system.SystemInfo;
-/**
+ /**
* @author Greg Hinkle
*/
public class FileSystemComponent implements ResourceComponent<PlatformComponent>, MeasurementFacet {
+
private static final Log LOG = LogFactory.getLog(FileSystemComponent.class);
+
private ResourceContext<PlatformComponent> resourceContext;
public void start(ResourceContext<PlatformComponent> resourceContext) throws InvalidPluginConfigurationException,
@@ -65,26 +67,32 @@ public class FileSystemComponent implements ResourceComponent<PlatformComponent>
}
}
- private FileSystemInfo getFileSystemInfo() {
- return resourceContext.getSystemInformation().getFileSystem(resourceContext.getResourceKey());
- }
-
- public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception {
+ public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests) throws Exception {
FileSystemInfo fileSystemInfo = getFileSystemInfo();
- fileSystemInfo.refresh();
- for (MeasurementScheduleRequest request : metrics) {
+ for (MeasurementScheduleRequest request : requests) {
try {
- if (request.getDataType() == DataType.TRAIT) {
- Object value = ObjectUtil.lookupDeepAttributeProperty(fileSystemInfo, request.getName());
- report.addData(new MeasurementDataTrait(request, String.valueOf(value)));
- } else if (request.getDataType() == DataType.MEASUREMENT) {
- report.addData(new MeasurementDataNumeric(request, ObjectUtil.lookupDeepNumericAttributeProperty(
- fileSystemInfo, request.getName())));
+ switch (request.getDataType()) {
+ case TRAIT:
+ Object object = ObjectUtil.lookupDeepAttributeProperty(fileSystemInfo, request.getName());
+ report.addData(new MeasurementDataTrait(request, String.valueOf(object)));
+ break;
+ case MEASUREMENT:
+ Double value = ObjectUtil.lookupDeepNumericAttributeProperty(fileSystemInfo, request.getName());
+ report.addData(new MeasurementDataNumeric(request, value));
+ break;
+ default:
+ throw new IllegalStateException("Unsupported metric type: " + request.getDataType());
}
} catch (Exception e) {
- LOG.info("Unable to collection file system metric [" + request.getName() + "] on resource "
- + this.resourceContext.getResourceKey(), e);
+ LOG.info("Unable to collect metric [" + request.getName() + "] on filesystem resource ["
+ + this.resourceContext.getResourceKey() + "].", e);
}
}
}
+
+ private FileSystemInfo getFileSystemInfo() {
+ SystemInfo systemInfo = resourceContext.getSystemInformation();
+ return systemInfo.getFileSystem(resourceContext.getResourceKey());
+ }
+
}
\ No newline at end of file
commit ceb7b6e337116f4b5af430f43c83884ad15988e1
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Dec 13 13:46:12 2011 -0500
[BZ 767263] don't assume there is always a template
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
index b29e9a6..bece740 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
@@ -198,6 +198,9 @@ public class DriftDefinitionDataSource extends RPCDataSource<DriftDefinitionComp
templateField.setCellFormatter(new CellFormatter() {
public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
DriftDefinition def = (DriftDefinition) listGridRecord.getAttributeAsObject(ATTR_ENTITY);
+ if (null == def.getTemplate()) {
+ return MSG.common_val_none();
+ }
if (null != globalPermissions && globalPermissions.contains(Permission.MANAGE_SETTINGS)) {
int typeId = def.getResource().getResourceType().getId();
int templateId = def.getTemplate().getId();
@@ -422,7 +425,11 @@ public class DriftDefinitionDataSource extends RPCDataSource<DriftDefinitionComp
record.setAttribute(ATTR_IS_PINNED, def.isPinned() ? ImageManager.getPinnedIcon() : ImageManager
.getUnpinnedIcon());
record.setAttribute(ATTR_ATTACHED, def.isAttached() ? MSG.common_val_yes() : MSG.common_val_no());
- record.setAttribute(ATTR_TEMPLATE, def.getTemplate().getName());
+ if (def.getTemplate() != null) {
+ record.setAttribute(ATTR_TEMPLATE, def.getTemplate().getName());
+ } else {
+ record.setAttribute(ATTR_TEMPLATE, MSG.common_val_none());
+ }
record.setAttribute(ATTR_CHANGE_SET_VERSION, (null != changeSet) ? String.valueOf(changeSet.getVersion()) : MSG
.common_label_none());
commit a449c64328ab7c4b729e83adc3505fdf6ec34b90
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Thu Dec 22 17:57:02 2011 -0500
[BZ 767734] conditionally disabling remaining tags references from Bundles.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
index 5ac460c..bbc4175 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
@@ -124,7 +124,11 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
+ deployment.getDestination().getName(), LinkManager.getBundleDestinationLink(version.getBundle().getId(),
deployment.getDestination().getId())));
addMember(new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleDeployment_24.png"), deployment.getName()));
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
addMemberDeploymentsTable();
@@ -219,8 +223,8 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
// deployment represents content on the remote machines, showing purge only for live
// deployments makes sense).
if (deployment.isLive()) {
- IButton revertButton = new LocatableIButton(actionLayout.extendLocatorId("Revert"), MSG
- .view_bundle_revert());
+ IButton revertButton = new LocatableIButton(actionLayout.extendLocatorId("Revert"),
+ MSG.view_bundle_revert());
revertButton.setIcon("subsystems/bundle/BundleAction_Revert_16.png");
revertButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
@@ -252,8 +256,9 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
new Message(MSG.view_bundle_dest_purgeSuccessful(destinationName),
Message.Severity.Info));
// Bundle destination is purged, go back to bundle deployment view - it is not live anymore
- CoreGUI.goToView(LinkManager.getBundleDeploymentLink(bundle.getId(), deployment
- .getId()), true);
+ CoreGUI.goToView(
+ LinkManager.getBundleDeploymentLink(bundle.getId(), deployment.getId()),
+ true);
}
});
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
index 1e47427..d0966f2 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
@@ -101,7 +101,12 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka
addMember(backButton);
addMember(header);
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
+
addMember(createSummaryForm());
addMember(createDeploymentsTable());
addMember(detail);
@@ -223,8 +228,8 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka
new Message(MSG.view_bundle_dest_purgeSuccessful(destination.getName()),
Message.Severity.Info));
// Bundle destination is purged, go back to bundle destination view
- CoreGUI.goToView(LinkManager.getBundleDestinationLink(bundle.getId(), destination
- .getId()), true);
+ CoreGUI.goToView(
+ LinkManager.getBundleDestinationLink(bundle.getId(), destination.getId()), true);
}
});
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
index e8eabfa..7a39e5a 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
@@ -108,7 +108,11 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
addMember(backButton);
addMember(headerLabel);
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
addMember(tabs);
@@ -184,8 +188,8 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
StaticTextItem versionCountItem = new StaticTextItem("versionCount", MSG.view_bundle_list_versionsCount());
versionCountItem.setValue(bundle.getBundleVersions() != null ? bundle.getBundleVersions().size() : 0);
- StaticTextItem destinationsCountItem = new StaticTextItem("destinationsCount", MSG
- .view_bundle_list_destinationsCount());
+ StaticTextItem destinationsCountItem = new StaticTextItem("destinationsCount",
+ MSG.view_bundle_list_destinationsCount());
destinationsCountItem.setValue(bundle.getDestinations() != null ? bundle.getDestinations().size() : 0);
StaticTextItem descriptionItem = new StaticTextItem("description", MSG.common_title_description());
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
index 19116bb..5737a9c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
@@ -93,7 +93,10 @@ public class BundleVersionView extends LocatableVLayout implements BookmarkableV
addMember(new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleVersion_24.png"), version.getName() + ": "
+ version.getVersion()));
- addMember(createTagEditor());
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
@@ -268,16 +271,17 @@ public class BundleVersionView extends LocatableVLayout implements BookmarkableV
criteria.fetchConfigurationDefinition(true);
criteria.fetchTags(true);
- bundleManager.findBundleVersionsByCriteriaWithDestinationFilter(criteria, new AsyncCallback<PageList<BundleVersion>>() {
- public void onFailure(Throwable caught) {
- CoreGUI.getErrorHandler().handleError(MSG.view_bundle_version_loadFailure(), caught);
- }
+ bundleManager.findBundleVersionsByCriteriaWithDestinationFilter(criteria,
+ new AsyncCallback<PageList<BundleVersion>>() {
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_bundle_version_loadFailure(), caught);
+ }
- public void onSuccess(PageList<BundleVersion> result) {
- BundleVersion version = result.get(0);
- ViewId nextPath = viewPath.next().getCurrent();
- viewBundleVersion(version, nextPath);
- }
- });
+ public void onSuccess(PageList<BundleVersion> result) {
+ BundleVersion version = result.get(0);
+ ViewId nextPath = viewPath.next().getCurrent();
+ viewBundleVersion(version, nextPath);
+ }
+ });
}
}
commit 5407b2871b5c8ed074513992aec8cd07a687b949
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 23 17:49:51 2012 +0100
[BZ 767170] - The permissions are already known, don't try to fetch them
asynchronously again in the role and user views.
This simplifies the rendering of those views tremendously making them work
reliably and without possible race conditions.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
index 53bd86d..7d4810b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
@@ -117,13 +117,13 @@ public class AdministrationView extends AbstractSectionedLeftNavigationView {
private NavigationSection buildSecuritySection() {
NavigationItem usersItem = new NavigationItem(UsersView.VIEW_ID, "global/User_16.png", new ViewFactory() {
public Canvas createView() {
- return new UsersView(extendLocatorId("Users"));
+ return new UsersView(extendLocatorId("Users"), getGlobalPermissions().contains(Permission.MANAGE_SECURITY));
}
});
NavigationItem rolesItem = new NavigationItem(RolesView.VIEW_ID, "global/Role_16.png", new ViewFactory() {
public Canvas createView() {
- return new RolesView(extendLocatorId("Roles"));
+ return new RolesView(extendLocatorId("Roles"), getGlobalPermissions().contains(Permission.MANAGE_SECURITY));
}
});
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
index 3c3e91d..91f2c2f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
@@ -20,7 +20,6 @@ package org.rhq.enterprise.gui.coregui.client.admin.roles;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.widgets.Canvas;
@@ -29,10 +28,7 @@ import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
-import org.rhq.core.domain.authz.Permission;
import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoader;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter;
import org.rhq.enterprise.gui.coregui.client.components.table.TableAction;
@@ -46,7 +42,7 @@ import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
* @author Greg Hinkle
* @author Ian Springer
*/
-public class RolesView extends TableSection<RolesDataSource> implements BookmarkableView {
+public class RolesView extends TableSection<RolesDataSource> {
public static final ViewName VIEW_ID = new ViewName("Roles", MSG.common_title_roles());
public static final String VIEW_PATH = AdministrationView.VIEW_ID + "/"
@@ -55,22 +51,18 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark
private static final String HEADER_ICON = "global/Role_24.png";
private boolean hasManageSecurity;
- private boolean initialized;
- public RolesView(String locatorId) {
+ public RolesView(String locatorId, boolean hasManageSecurity) {
super(locatorId, MSG.common_title_roles());
final RolesDataSource datasource = RolesDataSource.getInstance();
setDataSource(datasource);
setHeaderIcon(HEADER_ICON);
setEscapeHtmlInDetailsLinkColumn(true);
+
+ this.hasManageSecurity = hasManageSecurity;
}
-
- @Override
- protected void onDraw() {
- fetchManageSecurityPermissionAsync();
- }
-
+
@Override
protected void configureTable() {
updateSelectionStyle();
@@ -156,31 +148,12 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark
};
}
- private void fetchManageSecurityPermissionAsync() {
- new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- if (permissions != null) {
- hasManageSecurity = permissions.contains(Permission.MANAGE_SECURITY);
- refreshTableInfo();
- } else {
- hasManageSecurity = false;
- }
- if (!initialized) {
- RolesView.super.onDraw();
- }
- initialized = true;
- }
- });
- }
-
private void updateSelectionStyle() {
- if (initialized) {
- if (!hasManageSecurity) {
- getListGrid().deselectAllRecords();
- }
- SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
- getListGrid().setSelectionType(selectionStyle);
+ if (!hasManageSecurity) {
+ getListGrid().deselectAllRecords();
}
+ SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
+ getListGrid().setSelectionType(selectionStyle);
}
@Override
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
index a8b35fd..18213f1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
@@ -20,7 +20,6 @@ package org.rhq.enterprise.gui.coregui.client.admin.users;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.SelectionStyle;
@@ -32,8 +31,6 @@ import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import org.rhq.core.domain.authz.Permission;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoader;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter;
import org.rhq.enterprise.gui.coregui.client.components.table.TableAction;
@@ -61,9 +58,8 @@ public class UsersView extends TableSection<UsersDataSource> {
private static final String HEADER_ICON = "global/User_24.png";
private boolean hasManageSecurity;
- private boolean initialized;
- public UsersView(String locatorId) {
+ public UsersView(String locatorId, boolean hasManageSecurity) {
super(locatorId, MSG.common_title_users());
final UsersDataSource dataSource = UsersDataSource.getInstance();
@@ -71,8 +67,8 @@ public class UsersView extends TableSection<UsersDataSource> {
setDataSource(dataSource);
setHeaderIcon(HEADER_ICON);
setEscapeHtmlInDetailsLinkColumn(true);
-
- fetchManageSecurityPermissionAsync();
+
+ this.hasManageSecurity = hasManageSecurity;
}
@Override
@@ -101,28 +97,12 @@ public class UsersView extends TableSection<UsersDataSource> {
updateSelectionStyle();
}
- private void fetchManageSecurityPermissionAsync() {
- new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- if (permissions != null) {
- hasManageSecurity = permissions.contains(Permission.MANAGE_SECURITY);
- refreshTableInfo();
- } else {
- hasManageSecurity = false;
- }
- initialized = true;
- }
- });
- }
-
private void updateSelectionStyle() {
- if (initialized) {
- if (!hasManageSecurity) {
- getListGrid().deselectAllRecords();
- }
- SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
- getListGrid().setSelectionType(selectionStyle);
+ if (!hasManageSecurity) {
+ getListGrid().deselectAllRecords();
}
+ SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
+ getListGrid().setSelectionType(selectionStyle);
}
private List<ListGridField> createFields() {
commit c8dad0b8a0270387ed55ef13e9f38a40fa08c462
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 23 17:45:46 2012 +0100
Added some clarification to the javadocs of InitializableView to lower
the expectations one might have about it.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
index b5fc3b9..f503d99 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
@@ -33,7 +33,12 @@ public interface InitializableView {
/**
* Return true if this widget's {@link BaseWidget#init() initialization} has completed, or false otherwise.
- *
+ * <p>
+ * Don't expect this to work automagically if the result of this method is dependent on some asynchronous call.
+ * The consumers of this method need in that case loop and check this method periodically. If you cannot guarantee
+ * all the callers of this method on your instance actually do that, you can't assume that the results of
+ * the asynchronous call will be taken into account correctly.
+ *
* @return true if this widget's {@link BaseWidget#init() initialization} has completed, or false otherwise
*/
boolean isInitialized();
12 years, 3 months
[rhq] modules/enterprise
by ips
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ClientCommand.java | 2 +-
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java | 7 -------
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java | 5 -----
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java | 1 -
4 files changed, 1 insertion(+), 14 deletions(-)
New commits:
commit 534d91a7ba0786ebd521cb150b7713718aed946d
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Wed Feb 1 11:36:21 2012 -0500
minor: remove unused imports; alphabetize ClientCommand.COMMANDS array
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ClientCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ClientCommand.java
index 8581484..905d346 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ClientCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/ClientCommand.java
@@ -32,8 +32,8 @@ public interface ClientCommand {
LoginCommand.class,
LogoutCommand.class,
QuitCommand.class,
- ScriptCommand.class,
RecordCommand.class,
+ ScriptCommand.class,
VersionCommand.class
};
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
index abddad4..6366b6e 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/HelpCommand.java
@@ -19,11 +19,7 @@
package org.rhq.enterprise.client.commands;
import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.WildcardType;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,7 +30,6 @@ import java.util.Map;
import org.rhq.bindings.output.TabularWriter;
import org.rhq.enterprise.client.ClientMain;
-import org.rhq.enterprise.client.Controller;
import org.rhq.enterprise.client.utility.ReflectionUtility;
import javax.jws.WebParam;
@@ -154,8 +149,6 @@ public class HelpCommand implements ClientCommand {
return true;
}
-
-
public String getSyntax() {
return "help [command] | [api [service]]";
}
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
index 2f4c640..2e3dbed 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/LoginCommand.java
@@ -20,18 +20,13 @@ package org.rhq.enterprise.client.commands;
import java.io.PrintWriter;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.common.ProductInfo;
-import org.rhq.core.domain.common.ServerDetails;
import org.rhq.enterprise.client.ClientMain;
import org.rhq.enterprise.clientapi.RemoteClient;
-import org.rhq.enterprise.server.system.ServerVersion;
/**
* @author Greg Hinkle
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
index f618a41..8640599 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/QuitCommand.java
@@ -19,7 +19,6 @@
package org.rhq.enterprise.client.commands;
import org.rhq.enterprise.client.ClientMain;
-import org.rhq.enterprise.client.Controller;
/**
* @author Greg Hinkle
12 years, 3 months
[rhq] Branch 'feature/gwt-upgrade' - 148 commits - .classpath modules/common modules/core modules/enterprise modules/integration-tests modules/plugins modules/pom.xml pom.xml
by John Sanda
.classpath | 2
modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java | 20
modules/core/dbutils/pom.xml | 2
modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/DriftTemplateMapDatabaseUpgradeTask.java | 2
modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml | 185
modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementData.java | 4
modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementDataNumeric.java | 5
modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java | 35
modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java | 2
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java | 7
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessor.java | 26
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java | 112
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java | 160
modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceDiscoveryComponent.java | 5
modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessorTest.java | 251
modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java | 54
modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java | 3
modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java | 7
modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java | 264
modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/ResourceContainer.java | 4
modules/core/plugin-container/src/main/java/org/rhq/core/pc/standaloneContainer/Command.java | 4
modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/InventoryPrinter.java | 17
modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java | 72
modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java | 139
modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java | 98
modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java | 49
modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java | 187
modules/enterprise/agent/src/etc/rhq-agent.bat | 10
modules/enterprise/agent/src/etc/rhq-agent.sh | 13
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/AgentMain.java | 119
modules/enterprise/agent/src/main/java/org/rhq/enterprise/agent/i18n/AgentI18NResourceKeys.java | 9
modules/enterprise/binding/pom.xml | 2
modules/enterprise/binding/src/main/java/org/rhq/bindings/SandboxedScriptEngine.java | 3
modules/enterprise/binding/src/main/java/org/rhq/bindings/ScriptEngineFactory.java | 60
modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java | 6
modules/enterprise/binding/src/main/java/org/rhq/bindings/client/ResourceClientFactory.java | 8
modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java | 4
modules/enterprise/binding/src/test/java/org/rhq/bindings/ScriptEngineTest.java | 9
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java | 7
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LinkManager.java | 5
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java | 388 -
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java | 4
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/SystemSettingsView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java | 45
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/templates/ResourceTypeTreeNodeBuilder.java | 10
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java | 34
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java | 15
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleResourceDeploymentHistoryListView.java | 14
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java | 11
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java | 10
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java | 26
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java | 87
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/content/repository/tree/ContentRepositoryTreeView.java | 7
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/PortletFactory.java | 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/groups/FavoriteGroupsPortlet.java | 151
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/inventory/resource/FavoriteResourcesPortlet.java | 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftCarouselView.java | 20
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java | 17
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionTemplatesView.java | 277
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupCompositeDataSource.java | 32
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupsDataSource.java | 8
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java | 57
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/OverviewForm.java | 32
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/test/TestUserPreferencesView.java | 3
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java | 23
modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties | 4
modules/enterprise/gui/installer-war/pom.xml | 4
modules/enterprise/gui/installer-war/src/main/webapp/header.jsp | 4
modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java | 26
modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java | 8
modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java | 63
modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/web.xml | 9
modules/enterprise/gui/portal-war/src/main/webapp/admin/test/control.jsp | 5
modules/enterprise/gui/rest-war/src/main/webapp/index.html | 8
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.csv.js | 92
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geo.js | 938 ++
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geom.js | 835 ++
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.js | 3135 ++++++----
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.layout.js | 454 -
modules/enterprise/gui/rest-war/src/main/webapp/js/d3.time.js | 61
modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html | 184
modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html | 225
modules/enterprise/remoting/cli/pom.xml | 8
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java | 53
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java | 14
modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java | 49
modules/enterprise/server/client-api/pom.xml | 74
modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java | 274
modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java | 20
modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/LocalClientTest.java | 101
modules/enterprise/server/container-lib/pom.xml | 6
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java | 252
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java | 36
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java | 110
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java | 264
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java | 75
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java | 187
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java | 69
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java | 96
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java | 85
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java | 33
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java | 222
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java | 76
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java | 71
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java | 185
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java | 81
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java | 104
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java | 94
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java | 45
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java | 32
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java | 55
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java | 195
modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java | 59
modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java | 145
modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java | 180
modules/enterprise/server/container/src/main/resources/etc/RHQ-mib.txt | 17
modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml | 7
modules/enterprise/server/itests/pom.xml | 51
modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java | 216
modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/server/drift/DriftServerTest.java | 13
modules/enterprise/server/itests/src/test/resources/embedded-jboss-beans.xml | 10
modules/enterprise/server/itests/src/test/resources/security.policy | 10
modules/enterprise/server/jar/pom.xml | 7
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java | 36
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java | 60
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java | 80
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java | 38
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementBaselineManagerBean.java | 23
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerBean.java | 36
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerLocal.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java | 10
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementScheduleManagerBean.java | 44
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/util/MeasurementDataManagerUtility.java | 14
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceFactoryManagerBean.java | 4
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java | 43
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/LdapGroupManagerBean.java | 2
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java | 18
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java | 36
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java | 320 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java | 83
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java | 58
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/NumericDataPoint.java | 65
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/RHQErrorWrapper.java | 28
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/alert/test/DeleteAlertsTest.java | 26
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java | 30
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/cloud/FailoverListManagerBeanTest.java | 14
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java | 58
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/content/test/ContentManagerBeanTest.java | 19
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java | 538 +
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/plugin/DatabaseAndFilePluginDeploymentTest.java | 221
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java | 76
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java | 30
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/inventory/InventoryManagerBeanTest.java | 83
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/operation/OperationManagerBeanTest.java | 128
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncContentProviderTest.java | 112
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncRepoTest.java | 107
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/group/test/LdapGroupManagerBeanTest.java | 28
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ContentMetadataManagerBeanTest.java | 137
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/EventMetadataManagerBeanTest.java | 75
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java | 50
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/PluginManagerBeanTest.java | 43
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBeanTest.java | 103
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/test/UpdatePluginMetadataTestBase.java | 37
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceFactoryManagerBeanTest.java | 22
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceManagerBeanTest.java | 93
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/scheduler/jobs/DataPurgeJobTest.java | 35
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java | 214
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/system/SystemManagerBeanTest.java | 55
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java | 53
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/LargeGroupTestBase.java | 12
modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml | 10
modules/enterprise/server/plugins/alert-cli/src/main/java/org/rhq/enterprise/server/plugins/alertCli/CliSender.java | 9
modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpSender.java | 16
modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpTrapSender.java | 4
modules/enterprise/server/pom.xml | 2
modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/AbstractIntegrationTest.java | 6
modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/UploadAndDeployTest.java | 8
modules/integration-tests/jndi-access/jndi-access-test/pom.xml | 327 +
modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java | 189
modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties | 26
modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/jms-ra.rar |binary
modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml | 78
modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy | 10
modules/integration-tests/jndi-access/pom.xml | 21
modules/integration-tests/jndi-access/remote-server/pom.xml | 72
modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java | 79
modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties | 2
modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties | 5
modules/integration-tests/pom.xml | 1
modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java | 152
modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml | 16
modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java | 11
modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java | 17
modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/helper/JBossInstallationInfo.java | 12
modules/plugins/jboss-as-7/d2d.sh | 2
modules/plugins/jboss-as-7/pom.xml | 15
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7Authenticator.java | 26
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASConnection.java | 70
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java | 15
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java | 287
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java | 41
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseProcessDiscovery.java | 19
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseServerComponent.java | 73
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java | 47
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java | 135
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java | 6
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java | 212
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/Domain2Descriptor.java | 57
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java | 23
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java | 10
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java | 7
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java | 282
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ServerGroupComponent.java | 2
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/StandaloneASComponent.java | 2
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java | 46
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Operation.java | 2
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Result.java | 15
modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml | 657 +-
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/AbstractConfigurationHandlingTest.java | 49
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java | 59
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java | 122
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java | 3
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/PathHandlingTest.java | 27
modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/XmlFileReadingTest.java | 133
modules/plugins/jboss-as-7/src/test/resources/host1.xml | 92
modules/plugins/jboss-as-7/src/test/resources/host2.xml | 91
modules/plugins/jboss-as-7/src/test/resources/standalone70.xml | 433 +
modules/plugins/jboss-as-7/src/test/resources/standalone71.xml | 453 +
modules/plugins/jboss-as-7/src/test/resources/system-props.json | 10
modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml | 28
modules/plugins/jboss-as-7/src/test/resources/web.json | 62
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/AbstractMessagingDiscoveryComponent.java | 2
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java | 2
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASTomcatConnectorDiscoveryComponent.java | 2
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/WarComponent.java | 8
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/helper/JBossInstallationInfo.java | 13
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/DeploymentUtility.java | 4
modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/WarDiscoveryHelper.java | 3
modules/plugins/jboss-cache-v3/src/main/java/org/rhq/plugins/jbosscache3/JBossCacheDiscoveryComponent.java | 2
modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheComponent.java | 2
modules/plugins/jmx/pom.xml | 65
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/EmbeddedJMXServerDiscoveryComponent.java | 1
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/InternalJMXServerDiscoveryComponent.java | 30
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXDiscoveryComponent.java | 599 +
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXServerComponent.java | 181
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/MBeanResourceDiscoveryComponent.java | 6
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ObjectNameQueryUtility.java | 218
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ParentDefinedJMXServerNamingUtility.java | 57
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ConnectionProviderFactory.java | 218
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmResourceKey.java | 179
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmUtility.java | 118
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ObjectNameQueryUtility.java | 218
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ParentDefinedJMXServerNamingUtility.java | 57
modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/Socket.java | 120
modules/plugins/jmx/src/main/resources/META-INF/rhq-plugin.xml | 8
modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/JMXPluginTest.java | 211
modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/ObjectNameQueryUtilityTest.java | 2
modules/plugins/oracle/pom.xml | 355 -
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java | 25
modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java | 30
modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml | 15
modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java | 281
modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java | 95
modules/plugins/oracle/src/test/resources/log4j.xml | 35
modules/plugins/platform/src/main/java/org/rhq/plugins/platform/PlatformDiscoveryComponent.java | 4
modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessDiscoveryComponent.java | 11
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java | 2
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java | 2
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceComponent.java | 35
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java | 63
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerComponent.java | 36
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerOperationsDelegate.java | 2
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java | 30
modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarDiscoveryComponent.java | 4
modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml | 99
modules/pom.xml | 10
pom.xml | 11
280 files changed, 19423 insertions(+), 5125 deletions(-)
New commits:
commit f8032fb26d6fb6159dcb75a09e617bc400ff1f58
Merge: a4c0b1a 55a89fa
Author: John Sanda <john(a)John-Sandas-iMac.local>
Date: Wed Feb 1 11:24:34 2012 -0500
Merge branch 'master' into feature/gwt-upgrade
Conflicts:
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java
commit 55a89fae4b11ca5a8fecb668b87dbcef2bc04cf9
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 17:12:36 2012 -0500
[BZ 784678] prevent NPE from occurring if -f option is not passed to CLI record command - instead throw a command line
parse exception with an informative error message (https://bugzilla.redhat.com/show_bug.cgi?id=784678)
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
index e38e81a..468076e 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -96,8 +96,12 @@ public class RecordCommand implements ClientCommand {
code = getopt.getopt();
}
+ if (recordArgs.file == null) {
+ throw new CommandLineParseException("The file option must be specified.");
+ }
+
if (recordArgs.recordState == null) {
- throw new CommandLineParseException("Either the start or stop option must be specified");
+ throw new CommandLineParseException("Either the start or stop option must be specified.");
}
return recordArgs;
commit ed89cb1f3eb14ef0a805d0723635236bd5870a98
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:59:05 2012 -0500
(minor) remove unused import
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
index a6b97b8..d42fc6d 100755
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
@@ -25,7 +25,6 @@ package org.rhq.enterprise.client;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
commit 0c0a5c916127fd3235850e6619d61eaaf96c88eb
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:58:15 2012 -0500
remove a bunch of dead code
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
index d4444fe..a6b97b8 100755
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
@@ -65,8 +65,6 @@ public class ClientMain {
*/
private Thread inputLoopThread;
- private BufferedReader inputReader;
-
// JLine console reader
private ConsoleReader consoleReader;
@@ -114,7 +112,7 @@ public class ClientMain {
private static void initCommands() {
for (Class<ClientCommand> commandClass : ClientCommand.COMMANDS) {
- ClientCommand command = null;
+ ClientCommand command;
try {
command = commandClass.newInstance();
commands.put(command.getPromptCommandString(), command);
@@ -136,8 +134,7 @@ public class ClientMain {
this.serviceCompletor.setServices(remoteClient.getManagers());
}
}
-
- //
+
public ClientMain() throws Exception {
// this.inputReader = new BufferedReader(new
@@ -167,24 +164,15 @@ public class ClientMain {
consoleReader.setUsePagination(true);
}
- // ?? what is this again? Might be able to remove this.
- public void start() {
- outputWriter = new PrintWriter(System.out);
- // inputReader = new BufferedReader(new InputStreamReader(System.in));
-
- }
-
public String getUserInput(String prompt) {
String input_string = "";
- boolean use_default_prompt = (prompt == null);
while ((input_string != null) && (input_string.trim().length() == 0)) {
if (prompt == null) {
if (!loggedIn()) {
prompt = "unconnected$ ";
} else {
- // prompt = host + ":" + port + "> ";
// Modify the prompt to display host:port(logged-in-user)
String loggedInUser = "";
if ((getSubject() != null) && (getSubject().getName() != null)) {
@@ -197,12 +185,10 @@ public class ClientMain {
}
}
}
- // outputWriter.print(prompt);
try {
outputWriter.flush();
input_string = consoleReader.readLine(prompt);
- // inputReader.readLine();
} catch (Exception e) {
input_string = null;
}
@@ -213,12 +199,6 @@ public class ClientMain {
if (!stdinInput) {
outputWriter.println(input_string);
}
- } else if (!stdinInput) {
- // if we are processing a script, we hit the EOF, so close the inputstream
- try {
- inputReader.close();
- } catch (IOException e1) {
- }
}
return input_string;
@@ -602,7 +582,7 @@ public class ClientMain {
/**
* This method allows ClientCommands to insert a small note to be displayed after the command has been executed. A
- * note can be an indicaiton of a problem that was handled or a note about some option that should be changed.
+ * note can be an indication of a problem that was handled or a note about some option that should be changed.
*
* These notes are meant to be terse, and pasted/purged at the end of every command execution.
*
commit 3c0e9542e0ddfa60828ea44c37af715a79bfcc6b
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:43:11 2012 -0500
[BZ 785218] fix so -v/--version option does not print redundant info
(https://bugzilla.redhat.com/show_bug.cgi?id=785218)
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
index 191c537..d4444fe 100755
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/ClientMain.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2009 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -82,6 +82,7 @@ public class ClientMain {
private String user;
private String pass;
private ArrayList<String> notes = new ArrayList<String>();
+ private boolean showDetailedVersion;
// reference to the webservice reference factory
private RemoteClient remoteClient;
@@ -403,7 +404,7 @@ public class ClientMain {
}
private void displayUsage() {
- outputWriter.println("rhq-cli.sh [-h] [-u user] [-p pass] [-P] [-s host] [-t port] [-f file]|[-c command]");
+ outputWriter.println("rhq-cli.sh [-h] [-u user] [-p pass] [-P] [-s host] [-t port] [-v] [-f file]|[-c command]");
}
void processArguments(String[] args) throws IllegalArgumentException, IOException {
@@ -478,10 +479,10 @@ public class ClientMain {
setHost(getopt.getOptarg());
break;
}
- case 'r': {
- setTransport(getopt.getOptarg());
- break;
- }
+ case 'r': {
+ setTransport(getopt.getOptarg());
+ break;
+ }
case 't': {
String portArg = getopt.getOptarg();
try {
@@ -492,15 +493,20 @@ public class ClientMain {
break;
}
case 'v': {
- String versionString = Version.getProductNameAndVersionBuildInfo();
- outputWriter.println(versionString);
+ showDetailedVersion = true;
break;
}
}
}
if (interactiveMode) {
- outputWriter.println(Version.getProductNameAndVersion());
+ String version = (showDetailedVersion) ? Version.getProductNameAndVersionBuildInfo() :
+ Version.getProductNameAndVersion();
+ outputWriter.println(version);
+ if (showDetailedVersion && args.length == 1) {
+ // If -v was the only option specified, exit after printing the version.
+ System.exit(0);
+ }
}
if (user != null && pass != null) {
@@ -516,7 +522,7 @@ public class ClientMain {
}
if (!interactiveMode) {
- commands.get("exec").execute(this, execCmdLine.toArray(new String[] {}));
+ commands.get("exec").execute(this, execCmdLine.toArray(new String[execCmdLine.size()]));
}
}
commit 35e9cce2d3dc07636bf2ece0acbde13a3b862eeb
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 31 22:33:36 2012 +0100
Upgrade RESTEasy to 2.3.1.GA
diff --git a/pom.xml b/pom.xml
index 3b77493..44c6b34 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,7 +92,7 @@
<twitter4j.version>2.2.4</twitter4j.version>
<commons-codec.version>1.4</commons-codec.version>
<!-- NOTE (ips, 10/04/11): Upgrading testng to 6.2.x causes 10 server-jar tests to fail for an unknown reason. -->
- <!-- NOTE (jshaughn, 01/20/12): With the latest work, the sserver-jar tests passed using testng to 6.3.1, so perhaps an upgrade is possible -->
+ <!-- NOTE (jshaughn, 01/20/12): With the latest work, the sserver-jar tests passed using testng to 6.3.1, so perhaps an upgrade is possible -->
<testng.version>6.1.1</testng.version>
<cobertura.version>1.9.4.1</cobertura.version>
<augeas.version>0.9.0</augeas.version>
@@ -101,7 +101,7 @@
<augeas.zip.location>${settings.localRepository}/net/augeas/augeas-native/${augeas.version}</augeas.zip.location>
<augeas.zip.mask>*-${augeas.classifier}.zip</augeas.zip.mask>
<ant.contrib.version>1.0b3</ant.contrib.version>
- <resteasy.version>2.2.3.GA</resteasy.version>
+ <resteasy.version>2.3.1.GA</resteasy.version>
<freemarker.version>2.3.18</freemarker.version>
<rhq.db.admin.username>rhqadmin</rhq.db.admin.username>
@@ -888,11 +888,11 @@
<phase>generate-sources</phase>
<configuration>
<tasks>
- <mkdir dir="target" />
+ <mkdir dir="target" />
<tstamp>
<format property="buildTime" pattern="MM/dd/yy hh:mm aa z" locale="en,US" timezone="GMT" />
- </tstamp>
+ </tstamp>
<echo file="target/build.properties">buildTime = ${buildTime}${line.separator}</echo>
<exec executable="git" outputproperty="buildNumber" failonerror="false" failifexecutionfails="false">
@@ -918,7 +918,7 @@
</tasks>
</configuration>
</execution>
-
+
<execution>
<id>javadoc-dist</id>
<phase>site</phase>
@@ -949,7 +949,7 @@
</goals>
<configuration>
<files>
- <file>${project.build.directory}/build.properties</file>
+ <file>${project.build.directory}/build.properties</file>
</files>
<quiet>true</quiet>
</configuration>
commit 43f016c9d9da95d2f5ea1bed4d1ee7fdbf9e07c3
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:08:05 2012 -0500
[BZ 784983] fix output of CLI version command (https://bugzilla.redhat.com/show_bug.cgi?id=784983)
diff --git a/modules/enterprise/remoting/cli/pom.xml b/modules/enterprise/remoting/cli/pom.xml
index 32921bb..21e9c47 100644
--- a/modules/enterprise/remoting/cli/pom.xml
+++ b/modules/enterprise/remoting/cli/pom.xml
@@ -172,14 +172,6 @@
</includes>
<archive>
<index>true</index>
- <manifestEntries>
- <Implementation-Title>${rhq.product.name} - ${project.name}</Implementation-Title>
- <Implementation-Version>${project.version}</Implementation-Version>
- <Specification-Vendor>org.jboss</Specification-Vendor>
- <Specification-Title>JBossWS</Specification-Title>
- <Specification-Version>${jbossws-native-dist.version}</Specification-Version>
- <Build-Number>${buildNumber}</Build-Number>
- </manifestEntries>
</archive>
</configuration>
</plugin>
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
index d27c3f3..2df0b72 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/VersionCommand.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,10 @@
package org.rhq.enterprise.client.commands;
import java.util.Properties;
+import java.util.jar.Attributes;
+import gnu.getopt.Getopt;
+import gnu.getopt.LongOpt;
import org.rhq.enterprise.client.ClientMain;
import org.rhq.enterprise.client.Version;
@@ -35,26 +38,56 @@ public class VersionCommand implements ClientCommand {
}
public boolean execute(ClientMain client, String[] args) {
- if (args.length <= 1) {
+ VersionArgs versionArgs = parseArgs(args);
+ if (versionArgs.verbose) {
client.getPrintWriter().println(Version.getVersionPropertiesAsString());
} else {
Properties props = Version.getVersionProperties();
- for (int i = 1; i < args.length; i++) {
- client.getPrintWriter().println(args[i] + "=" + props.getProperty(args[i], "<unknown>"));
- }
+ String version = props.getProperty(Attributes.Name.IMPLEMENTATION_VERSION.toString());
+ client.getPrintWriter().println(version);
}
+
return true;
}
public String getSyntax() {
- return "version [prop name]...";
+ return getPromptCommandString() + " [-v | --verbose]";
}
public String getHelp() {
- return "Show version information and properties";
+ return "Show CLI version information";
}
public String getDetailedHelp() {
- return getHelp();
+ return getHelp() + ". If no arguments are specified, the CLI's version is printed. If the verbose option is "
+ + "specified, the values of the main attributes from the CLI jar's MANIFEST.MF are printed.";
+ }
+
+ private VersionArgs parseArgs(String[] args) {
+ String shortOpts = "-:v";
+ LongOpt[] longOpts = {
+ new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v')
+ };
+ Getopt getopt = new Getopt("exec", args, shortOpts, longOpts);
+
+ VersionArgs versionArgs = new VersionArgs();
+
+ int code = getopt.getopt();
+ while (code != -1) {
+ switch (code) {
+ case ':':
+ throw new IllegalArgumentException("Illegal option.");
+ case 'v':
+ versionArgs.verbose = true;
+ break;
+ }
+ code = getopt.getopt();
+ }
+
+ return versionArgs;
+ }
+
+ private static class VersionArgs {
+ boolean verbose;
}
}
\ No newline at end of file
commit 5853591e052fc9bf2e852f98c6fdb9ad4f278c2a
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 16:00:44 2012 -0500
minor: make help output consistent w/ the other CLI commands
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
index 7db869a..e38e81a 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
@@ -128,7 +128,7 @@ public class RecordCommand implements ClientCommand {
}
public String getHelp() {
- return "Records user input commands to a specified file. Use the --start option to begin recording. Use the " +
+ return "Record user input commands to a specified file. Use the --start option to begin recording. Use the " +
"--end option to stop recording. Use --append to append output to the end of an existing file; otherwise, " +
"recording will start at the beginning of the file.";
}
commit ab6ce9d9ddbb25d78a8d46859a9e025a2d820094
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 15:34:47 2012 -0500
fix typo and remove redundant import
diff --git a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
index e1244ae..7db869a 100644
--- a/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
+++ b/modules/enterprise/remoting/cli/src/main/java/org/rhq/enterprise/client/commands/RecordCommand.java
@@ -20,10 +20,8 @@
* if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-
package org.rhq.enterprise.client.commands;
-import org.rhq.enterprise.client.Controller;
import org.rhq.enterprise.client.ClientMain;
import org.rhq.enterprise.client.NoOpRecorder;
import org.rhq.enterprise.client.Recorder;
@@ -132,7 +130,7 @@ public class RecordCommand implements ClientCommand {
public String getHelp() {
return "Records user input commands to a specified file. Use the --start option to begin recording. Use the " +
"--end option to stop recording. Use --append to append output to the end of an existing file; otherwise, " +
- "recording will start at the begining of the file.";
+ "recording will start at the beginning of the file.";
}
public String getDetailedHelp() {
commit 3ae6a9600f01eb0fad0f52b61277d9cbb31e5479
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 31 15:05:24 2012 -0500
[Bug 785022 - Server upgrade fails if db-uprade.xml task is unable to created index when index already exists]
Applying suggested fix from loleary. Could not apply patch successfully
so manually reapplied the fix, which is to protect create/drop index
stmts with ignoreErrors="true".
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index c9b0bea..7b1f9a2 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -296,7 +296,7 @@
</schema-directSQL>
<schema-alterColumn table="RHQ_SERVER" column="OPERATION_MODE" nullable="FALSE" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_SERVER unique constraint on NAME">
CREATE UNIQUE INDEX rhq_server_name_unique ON rhq_server (name)
</statement>
@@ -853,7 +853,7 @@
</schemaSpec>
<schemaSpec version="2.24">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_MEASUREMENT_BLINE index on SCHEDULE_ID">
CREATE INDEX rhq_meas_baseline_sid_idx ON rhq_measurement_bline (schedule_id)
</statement>
@@ -1078,7 +1078,7 @@
</schemaSpec>
<schemaSpec version="2.36">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique constraint on RHQ_MEASUREMENT_DEF">
DROP INDEX RHQ_METRIC_DEF_KEY_IDX
</statement>
@@ -1093,7 +1093,7 @@
WHERE NUMERIC_TYPE = 0
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RHQ_MEASUREMENT_DEF (RESOURCE_TYPE_ID, NAME, RAW_NUMERIC_TYPE)">
CREATE UNIQUE INDEX RHQ_METRIC_DEF_KEY_IDX ON RHQ_MEASUREMENT_DEF (RESOURCE_TYPE_ID, NAME, RAW_NUMERIC_TYPE)
</statement>
@@ -1193,49 +1193,77 @@
<!-- RHQ 1448 -->
<schemaSpec version="2.44">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R00 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R00_SID_IDX ON RHQ_MEAS_DATA_NUM_R00 (schedule_id)
- </statement>
+ </statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R01 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R01_SID_IDX ON RHQ_MEAS_DATA_NUM_R01 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R02 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R02_SID_IDX ON RHQ_MEAS_DATA_NUM_R02 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R03 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R03_SID_IDX ON RHQ_MEAS_DATA_NUM_R03 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R04 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R04_SID_IDX ON RHQ_MEAS_DATA_NUM_R04 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R05 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R05_SID_IDX ON RHQ_MEAS_DATA_NUM_R05 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R06 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R06_SID_IDX ON RHQ_MEAS_DATA_NUM_R06 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R07 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R07_SID_IDX ON RHQ_MEAS_DATA_NUM_R07 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R08 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R08_SID_IDX ON RHQ_MEAS_DATA_NUM_R08 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R09 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R09_SID_IDX ON RHQ_MEAS_DATA_NUM_R09 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R10 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R10_SID_IDX ON RHQ_MEAS_DATA_NUM_R10 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R11 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R11_SID_IDX ON RHQ_MEAS_DATA_NUM_R11 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R12 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R12_SID_IDX ON RHQ_MEAS_DATA_NUM_R12 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R13 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R13_SID_IDX ON RHQ_MEAS_DATA_NUM_R13 (schedule_id)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R14 (SCHEDULE_ID)">
CREATE INDEX RHQ_MEAS_DATA_R14_SID_IDX ON RHQ_MEAS_DATA_NUM_R14 (schedule_id)
</statement>
@@ -1300,7 +1328,7 @@
</schemaSpec>
<schemaSpec version="2.50">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_RESOURCE_ERROR.RESOURCE_ID">
CREATE INDEX RHQ_RES_ERROR_IDX_RES_ID ON RHQ_RESOURCE_ERROR (RESOURCE_ID)
</statement>
@@ -1313,12 +1341,12 @@
</schemaSpec>
<schemaSpec version="2.52">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique name constraint on RHQ_RESOURCE_GROUP">
DROP INDEX RHQ_RES_GROUP_NAME
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Deleting unique name constraint on RHQ_RESOURCE_GROUP">
CREATE INDEX RHQ_RES_GROUP_NAME ON RHQ_RESOURCE_GROUP (name)
</statement>
@@ -1348,57 +1376,87 @@
</schemaSpec>
<schemaSpec version="2.55">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on TIME_STAMP column of RHQ_MEASUREMENT_DATA_NUM_1H">
CREATE INDEX RHQ_MEAS_DATA_1H_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_1H(TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on TIME_STAMP column of RHQ_MEASUREMENT_DATA_NUM_6H">
CREATE INDEX RHQ_MEAS_DATA_6H_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_6H(TIME_STAMP)
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R00 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R00_TS_IDX ON RHQ_MEAS_DATA_NUM_R00 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R01 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R01_TS_IDX ON RHQ_MEAS_DATA_NUM_R01 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R02 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R02_TS_IDX ON RHQ_MEAS_DATA_NUM_R02 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R03 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R03_TS_IDX ON RHQ_MEAS_DATA_NUM_R03 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R04 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R04_TS_IDX ON RHQ_MEAS_DATA_NUM_R04 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R05 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R05_TS_IDX ON RHQ_MEAS_DATA_NUM_R05 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R06 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R06_TS_IDX ON RHQ_MEAS_DATA_NUM_R06 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R07 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R07_TS_IDX ON RHQ_MEAS_DATA_NUM_R07 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R08 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R08_TS_IDX ON RHQ_MEAS_DATA_NUM_R08 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R09 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R09_TS_IDX ON RHQ_MEAS_DATA_NUM_R09 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R10 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R10_TS_IDX ON RHQ_MEAS_DATA_NUM_R10 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R11 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R11_TS_IDX ON RHQ_MEAS_DATA_NUM_R11 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R12 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R12_TS_IDX ON RHQ_MEAS_DATA_NUM_R12 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R13 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R13_TS_IDX ON RHQ_MEAS_DATA_NUM_R13 (TIME_STAMP)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating index on RHQ_MEAS_DATA_NUM_R14 (TIME_STAMP)">
CREATE INDEX RHQ_MEAS_DATA_R14_TS_IDX ON RHQ_MEAS_DATA_NUM_R14 (TIME_STAMP)
</statement>
@@ -1406,49 +1464,77 @@
</schemaSpec>
<schemaSpec version="2.56">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R00_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R00_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R01_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R01_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R02_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R02_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R03_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R03_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R04_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R04_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R05_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R05_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R06_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R06_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R07_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R07_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R08_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R08_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R09_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R09_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R10_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R10_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R11_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R11_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R12_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R12_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R13_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R13_SID_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping index on RHQ_MEAS_DATA_R14_SID_IDX">
DROP INDEX RHQ_MEAS_DATA_R14_SID_IDX
</statement>
@@ -1456,7 +1542,7 @@
</schemaSpec>
<schemaSpec version="2.57">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Create index on RHQ_CONFIG_PROPERTY(PARENT_LIST_ID)">
CREATE INDEX RHQ_CONFIG_PROP_idx_list_key ON RHQ_CONFIG_PROPERTY(PARENT_LIST_ID)
</statement>
@@ -1683,6 +1769,8 @@
FOREIGN KEY ( REPO_GROUP_TYPE_ID )
REFERENCES RHQ_REPO_GROUP_TYPE ( ID )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_REPO_GROUP_IDX
ON RHQ_REPO_GROUP ( NAME, REPO_GROUP_TYPE_ID )
@@ -1842,7 +1930,7 @@
<schema-alterColumn table="RHQ_DISTRIBUTION" column="BASE_PATH" nullable="false" />
<schema-addColumn table="RHQ_DISTRIBUTION" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_DISTRIBUTION" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_DISTRIBUTION_IDX ON RHQ_DISTRIBUTION ( LABEL, BASE_PATH )
</statement>
@@ -1947,6 +2035,8 @@
FOREIGN KEY (DISTRIBUTION_ID)
REFERENCES RHQ_DISTRIBUTION ( ID )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_DISTRIBUTION_FILE_IDX
ON RHQ_DISTRIBUTION_FILE ( DISTRIBUTION_ID, RELATIVE_FILENAME )
@@ -2019,7 +2109,7 @@
</schema-directSQL>
<!-- Fix bug:538157 -->
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE INDEX RHQ_REPO_PKG_VER_MAP_IDX
ON RHQ_REPO_PKG_VERSION_MAP ( PACKAGE_VERSION_ID )
@@ -2040,10 +2130,12 @@
<schemaSpec version="2.69.2">
<!-- plugin names must be unique only if they are deployed on the same side (agent vs. server) -->
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping unique index on RHQ_PLUGIN (NAME)">
DROP INDEX RHQ_PLUGIN_NAME_IDX
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RHQ_PLUGIN (NAME, DEPLOYMENT) so server plugin names need not be unique with agent plugins">
CREATE UNIQUE INDEX RHQ_PLUGIN_NAME_DEPLOY_IDX ON RHQ_PLUGIN (NAME, DEPLOYMENT)
</statement>
@@ -2086,7 +2178,7 @@
<schema-addColumn table="RHQ_ALERT_NOTIF_LOG" column="MESSAGE" columnType="VARCHAR2" precision="4000" />
</schemaSpec>
<schemaSpec version="2.70.3">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Dropping unique index RHQ_ALERT_IDX_ALERT">
DROP INDEX RHQ_ALERT_IDX_ALERT
</statement>
@@ -2127,7 +2219,7 @@
<schema-deleteColumn table="RHQ_ALERT" column="triggered_operation" />
</schemaSpec>
<schemaSpec version="2.70.7">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Recreating RHQ_ALERT_IDX_ALERT as non-unique index">
CREATE INDEX RHQ_ALERT_IDX_ALERT ON RHQ_ALERT_NOTIF_LOG (alert_id)
</statement>
@@ -2168,13 +2260,17 @@
<schema-addColumn table="RHQ_ADVISORY" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_NAME_UQ ON RHQ_ADVISORY ( ADVISORY_NAME )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_UQ ON RHQ_ADVISORY ( ADVISORY )
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE INDEX RHQ_ADVISORY_UDATE_IDX ON RHQ_ADVISORY (UPDATE_DATE )
</statement>
@@ -2193,7 +2289,7 @@
<schema-alterColumn table="RHQ_ADVISORY_PACKAGE" column="PACKAGE_VERSION_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_PACKAGE" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_PACKAGE" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_PACKAGE_IDX ON RHQ_ADVISORY_PACKAGE ( ADVISORY_ID, PACKAGE_VERSION_ID )
</statement>
@@ -2234,7 +2330,7 @@
<schema-alterColumn table="RHQ_ADVISORY_CVE" column="CVE_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_CVE" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_CVE" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_CVE_IDX ON RHQ_ADVISORY_CVE ( ADVISORY_ID, CVE_ID )
</statement>
@@ -2266,7 +2362,7 @@
<schema-alterColumn table="RHQ_ADVISORY_BUGLIST" column="BUG_ID" nullable="false" />
<schema-addColumn table="RHQ_ADVISORY_BUGLIST" column="LAST_MODIFIED" columnType="LONG" />
<schema-alterColumn table="RHQ_ADVISORY_BUGLIST" column="LAST_MODIFIED" nullable="false" />
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ADVISORY_BUG_IDX ON RHQ_ADVISORY_BUGLIST ( ADVISORY_ID, BUG_ID )
</statement>
@@ -2365,6 +2461,8 @@
FOREIGN KEY (RESOURCE_TYPE_ID)
REFERENCES RHQ_RESOURCE_TYPE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_TYPE unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_TYPE_UNIQUE ON RHQ_BUNDLE_TYPE (name)
</statement>
@@ -2406,6 +2504,8 @@
FOREIGN KEY (PACKAGE_TYPE_ID)
REFERENCES RHQ_PACKAGE_TYPE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_UNIQUE ON RHQ_BUNDLE (bundle_type_id, name)
</statement>
@@ -2444,6 +2544,8 @@
FOREIGN KEY (CONFIG_DEF_ID)
REFERENCES RHQ_CONFIG_DEF (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_VERSION unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_VERSION_UNIQUE ON RHQ_BUNDLE_VERSION (bundle_id, name, version)
</statement>
@@ -2539,6 +2641,8 @@
FOREIGN KEY (GROUP_ID)
REFERENCES RHQ_RESOURCE_GROUP (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_DESTINATION unique constraint">
CREATE UNIQUE INDEX RHQ_BUNDLE_DESTINATION_UNIQUE
ON RHQ_BUNDLE_DESTINATION (bundle_id, group_id, deploy_dir)
@@ -2630,6 +2734,8 @@
FOREIGN KEY (RESOURCE_ID)
REFERENCES RHQ_RESOURCE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_BUNDLE_RES_DEPLOY unique constraint on dep-resource mapping">
CREATE UNIQUE INDEX RHQ_BUNDLE_RES_DEPLOY_IDX
ON RHQ_BUNDLE_RES_DEPLOY (BUNDLE_DEPLOYMENT_ID, RESOURCE_ID)
@@ -2788,6 +2894,8 @@
FOREIGN KEY ( ROLE_ID )
REFERENCES RHQ_ROLE (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement>
CREATE UNIQUE INDEX RHQ_ROLE_LDAP_GROUP_IDX
ON RHQ_ROLE_LDAP_GROUP ( ROLE_ID, LDAP_GROUP_NAME )
@@ -2996,10 +3104,12 @@
</schemaSpec>
<schemaSpec version="2.87">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Drop non-unique RHQ_RES_TYPE_IDX_PLG_NAME index">
DROP INDEX RHQ_RES_TYPE_IDX_PLG_NAME
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Recreate RHQ_RES_TYPE_IDX_PLG_NAME index as unique">
CREATE UNIQUE INDEX RHQ_RES_TYPE_IDX_PLG_NAME ON RHQ_RESOURCE_TYPE (name, plugin)
</statement>
@@ -3007,10 +3117,12 @@
</schemaSpec>
<schemaSpec version="2.88">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add end time index on call time data to speed up purges">
CREATE INDEX RHQ_CT_DA_VA_END_TIM_IDX ON RHQ_CALLTIME_DATA_VALUE (end_time)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add index on measurement definition numeric type">
CREATE INDEX RHQ_METRIC_DEF_NT_IDX ON RHQ_MEASUREMENT_DEF (numeric_type)
</statement>
@@ -3131,7 +3243,7 @@
</schemaSpec>
<schemaSpec version="2.92.4">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Add index on measurement data 1d table timestamp">
CREATE INDEX RHQ_MEAS_DATA_1D_TIME_IDX ON RHQ_MEASUREMENT_DATA_NUM_1D (time_stamp)
</statement>
@@ -3294,6 +3406,8 @@
<statement desc="Changing primary key of RHQ_OPERATION_SCHEDULE to ID. Step2/3...">
ALTER TABLE RHQ_OPERATION_SCHEDULE ADD PRIMARY KEY (ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Changing primary key of RHQ_OPERATION_SCHEDULE to ID. Step3/3...">
CREATE UNIQUE INDEX RHQ_OPERATION_SCHEDULE_KEY_IDX ON RHQ_OPERATION_SCHEDULE (JOB_NAME, JOB_GROUP)
</statement>
@@ -3607,10 +3721,12 @@
</schemaSpec>
<schemaSpec version="2.113">
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_ALERT_CONDITION_LOG index on CONDITION_ID">
CREATE INDEX RHQ_ALERT_COND_LOG_COND_IDX ON RHQ_ALERT_CONDITION_LOG (CONDITION_ID)
</statement>
+ </schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating RHQ_MEASUREMENT_SCHED index on RESOURCE_ID">
CREATE INDEX RHQ_MEAS_SCHED_RESID_IDX ON RHQ_MEASUREMENT_SCHED (RESOURCE_ID)
</statement>
@@ -3669,7 +3785,7 @@
REFERENCES RHQ_CONFIG (ID)
</statement>
</schema-directSQL>
- <schema-directSQL>
+ <schema-directSQL ignoreError="true">
<statement desc="Creating unique index on RESOURCE_TYPE_ID and NAME columns">
CREATE UNIQUE INDEX RHQ_TYPE_DEF_NAME ON RHQ_DRIFT_DEF_TEMPLATE ( RESOURCE_TYPE_ID, NAME )
</statement>
commit c9cc6ed13db6d9d246611f627323abc86bd3f461
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 31 19:11:25 2012 +0100
[BZ 786194] - Make sure to set the correct context classloader when
simplifying the interfaces for the LocalClientProxy.
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index 29ac29a..f200744 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -40,6 +40,13 @@
<version>1.0</version>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/LocalClientTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/LocalClientTest.java
new file mode 100644
index 0000000..3b949e3
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/test/LocalClientTest.java
@@ -0,0 +1,101 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.client.test;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.jmock.Expectations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.alert.AlertManagerLocal;
+import org.rhq.enterprise.server.alert.AlertManagerRemote;
+import org.rhq.test.JMockTest;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class LocalClientTest extends JMockTest {
+
+ public static class FakeContextFactory implements InitialContextFactory {
+ @Override
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return CONTEXT_MOCK_FOR_TEST;
+ }
+ }
+
+ public static Context CONTEXT_MOCK_FOR_TEST = null;
+
+ @BeforeClass
+ public void setUpNaming() {
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY, FakeContextFactory.class.getName());
+ }
+
+ @Test
+ public void testResilienceAgainstContextClassloaders() throws Exception {
+ CONTEXT_MOCK_FOR_TEST = context.mock(Context.class);
+ final AlertManagerRemote alertManagerMock = (AlertManagerRemote) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[] { AlertManagerRemote.class, AlertManagerLocal.class }, new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return null;
+ }
+
+ });
+
+ context.checking(new Expectations() {{
+ allowing(CONTEXT_MOCK_FOR_TEST).lookup(with(any(String.class)));
+ will(returnValue(alertManagerMock));
+
+ allowing(CONTEXT_MOCK_FOR_TEST).close();
+ }});
+
+ ClassLoader origCl = Thread.currentThread().getContextClassLoader();
+ try {
+ ClassLoader differentCl = new URLClassLoader(new URL[0], getClass().getClassLoader());
+
+ Thread.currentThread().setContextClassLoader(differentCl);
+
+ LocalClient lc = new LocalClient(null);
+
+ //this call creates the proxy and is theoretically prone to the context classloader
+ AlertManagerRemote am = lc.getAlertManager();
+
+ //check that both the original and simplified methods exist on the returned object
+ am.getClass().getMethod("deleteAlerts", new Class<?>[] { Subject.class, int[].class });
+ am.getClass().getMethod("deleteAlerts", new Class<?>[] { int[].class });
+ } finally {
+ Thread.currentThread().setContextClassLoader(origCl);
+ }
+ }
+}
commit ef9f0ada2d2ac587d701da5ea03507b2fb74b8c3
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 30 18:37:21 2012 +0100
Make sure to set the correct context classloader when running inside
a EJB container.
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/client/ResourceClientFactory.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/client/ResourceClientFactory.java
index 6f15e81..2c1258d 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/client/ResourceClientFactory.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/client/ResourceClientFactory.java
@@ -199,7 +199,13 @@ public class ResourceClientFactory {
}
}
- return customClass.toClass();
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(ResourceClientProxy.class.getClassLoader());
+ return customClass.toClass();
+ } finally {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
} catch (NotFoundException e) {
LOG.error("Could not create custom interface for resource with id " + proxy.getId(), e);
} catch (CannotCompileException e) {
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
index 2414bf6..2e48048 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
@@ -432,10 +432,19 @@ public class LocalClient implements RhqFacade {
private <T> T getProxy(Object slsb, Class<T> iface) {
RhqManagers manager = RhqManagers.forInterface(iface);
- Class<?> simplified = InterfaceSimplifier.simplify(iface);
+ Class<?> simplified = null;
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(iface.getClassLoader());
+ simplified = InterfaceSimplifier.simplify(iface);
+ } finally {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
- Object proxy = Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { simplified },
- new LocalClientProxy(slsb, this, manager));
+ Object proxy =
+ Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { simplified }, new LocalClientProxy(slsb,
+ this, manager));
return iface.cast(proxy);
}
commit 5b7557b941711586d3c3be1447e0a9c3319fe029
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 31 12:21:04 2012 -0500
[BZ 785026] log an informative warning, if log files cannot be polled for events due to SIGAR being disabled or unavailable (https://bugzilla.redhat.com/show_bug.cgi?id=785026)
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
index f9bb654..8651272 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/EventContext.java
@@ -22,6 +22,7 @@
*/
package org.rhq.core.pluginapi.event;
+import com.sun.istack.Nullable;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
@@ -90,10 +91,10 @@ public interface EventContext {
/**
* Gets an instance of Sigar. Plugins that need to use Sigar, should use this method to get an instance, rather than
- * instantiating Sigar themselves.
+ * instantiating Sigar themselves. Returns null if the native layer is unavailable or has been disabled.
*
- * @return an instance of Sigar
+ * @return an instance of Sigar, or null if the native layer is unavailable or has been disabled
*/
- @NotNull
+ @Nullable
SigarProxy getSigar();
}
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
index 6fcb6d1..b4e19c4 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -54,6 +54,7 @@ public class LogFileEventPoller implements EventPoller {
private FileInfo logFileInfo;
private LogEntryProcessor entryProcessor;
private EventContext eventContext;
+ private boolean initialized;
public LogFileEventPoller(EventContext eventContext, String eventType, File logFile,
LogEntryProcessor entryProcessor) {
@@ -73,45 +74,54 @@ public class LogFileEventPoller implements EventPoller {
return this.logFile.getPath();
}
- // we can't get the FileInfo in the constructor because pollers are constructed during pc initialization, and
- // at that time the eventManager is not available (and so we can't get sigar).
- private FileInfo getFileInfo() {
- if (null == this.logFileInfo) {
- try {
- SigarProxy sigar = eventContext.getSigar();
- this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
- // once we have the file info we can let go of the event context, just in case that's useful
- this.eventContext = null;
-
- } catch (SigarException e) {
- throw new RuntimeException(e);
- }
- }
-
- return this.logFileInfo;
- }
-
@Nullable
public Set<Event> poll() {
-
+ if (!this.initialized) {
+ init();
+ }
+ if (this.logFileInfo == null) {
+ // This means SIGAR, which we require, is unavailable, so just return null.
+ return null;
+ }
+
if (!this.logFile.exists()) {
- log.warn("Log file [" + this.logFile + "' being polled does not exist.");
+ log.warn("Log file [" + this.logFile + "] being polled does not exist.");
return null;
}
if (this.logFile.isDirectory()) {
- log.error("Log file [" + this.logFile + "' being polled is a directory, not a regular file.");
+ log.error("Log file [" + this.logFile + "] being polled is a directory, not a regular file.");
return null;
}
- FileInfo fileInfo;
- try {
- fileInfo = getFileInfo();
- if (!fileInfo.changed()) {
+
+ try {
+ if (!this.logFileInfo.changed()) {
return null;
}
} catch (SigarException e) {
throw new RuntimeException(e);
}
- return processNewLines(fileInfo);
+ return processNewLines(this.logFileInfo);
+ }
+
+ /**
+ * This performs any initialization that requires using the EventContext. It must *not* be called from our
+ * constructor, because pollers are constructed during PC initialization, and at that time the PC EventManager,
+ * which the EventContext relies on, is not yet available. Instead it is called from {@link #poll()} on the first
+ * invocation of that method, at which point the PC will be initialized.
+ */
+ protected void init() {
+ SigarProxy sigar = this.eventContext.getSigar();
+ if (sigar != null) {
+ try {
+ this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
+ } catch (SigarException e) {
+ throw new RuntimeException("Failed to obtain file info for log file [" + this.logFile + "].", e);
+ }
+ } else {
+ log.warn("SIGAR is unavailable - cannot poll log file [" + this.logFile + "] for events.");
+ }
+
+ this.initialized = true;
}
private Set<Event> processNewLines(FileInfo fileInfo) {
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
index 962764a..d134638 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventResourceComponentHelper.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,9 @@ package org.rhq.core.pluginapi.event.log;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -32,10 +35,12 @@ import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.event.EventSeverity;
+import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.event.EventContext;
import org.rhq.core.pluginapi.event.EventPoller;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.core.system.SystemInfoFactory;
/**
* @author Ian Springer
@@ -47,83 +52,132 @@ public class LogFileEventResourceComponentHelper {
public static final String LOG_EVENT_SOURCE_CONFIG_PROP = "logEventSource";
public abstract static class LogEventSourcePropertyNames {
- public static final String LOG_FILE_PATH = "logFilePath";
- public static final String ENABLED = "enabled";
- public static final String DATE_FORMAT = "dateFormat";
- public static final String INCLUDES_PATTERN = "includesPattern";
- public static final String MINIMUM_SEVERITY = "minimumSeverity";
+ public static final String LOG_FILE_PATH = "logFilePath"; // required
+ public static final String ENABLED = "enabled"; // required
+ public static final String DATE_FORMAT = "dateFormat"; // optional
+ public static final String INCLUDES_PATTERN = "includesPattern"; // optional
+ public static final String MINIMUM_SEVERITY = "minimumSeverity"; // optional
}
+ // TODO: Make this configurable via a plugin config prop.
+ private static final int POLLING_INTERVAL_IN_SECONDS = 60;
+
private final Log log = LogFactory.getLog(this.getClass());
private ResourceContext<?> resourceContext;
+ private List<PropertyMap> startedEventSources = new ArrayList<PropertyMap>();
public LogFileEventResourceComponentHelper(ResourceContext<?> resourceContext) {
this.resourceContext = resourceContext;
}
public void startLogFileEventPollers() {
+ // Grab the list-o-maps of event sources from the plugin config.
Configuration pluginConfig = this.resourceContext.getPluginConfiguration();
PropertyList logEventSources = pluginConfig.getList(LOG_EVENT_SOURCES_CONFIG_PROP);
+
+ // Build a new list containing the event sources that are enabled.
+ List<PropertyMap> enabledEventSources = new ArrayList<PropertyMap>();
for (Property prop : logEventSources.getList()) {
PropertyMap logEventSource = (PropertyMap) prop;
- Boolean enabled = Boolean.valueOf(logEventSource.getSimpleValue(LogEventSourcePropertyNames.ENABLED, null));
- if (enabled) {
- String logFilePathname = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
- if (logFilePathname == null) {
- log.info("LOGFILE: No logfile path given, can not watch this event log.");
- return;
- }
- File logFile = new File(logFilePathname);
- if (!logFile.exists() || !logFile.canRead()) {
- log.error("LOGFILE: Logfile at location " + logFilePathname
- + " does not exist or is not readable. Can not start watching the event log.");
- return;
- }
+ String enabled = logEventSource.getSimpleValue(LogEventSourcePropertyNames.ENABLED, null);
+ if (enabled == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.ENABLED
+ + "] is not defined in map.");
+ }
+ if (Boolean.valueOf(enabled)) {
+ enabledEventSources.add(logEventSource);
+ }
+ }
- Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(LOG_ENTRY_EVENT_TYPE, logFile);
- String dateFormatString = logEventSource.getSimpleValue(LogEventSourcePropertyNames.DATE_FORMAT, null);
- if (dateFormatString != null) {
- try {
- DateFormat dateFormat = new SimpleDateFormat(dateFormatString); // TODO locale specific ?
- processor.setDateFormat(dateFormat);
- } catch (IllegalArgumentException e) {
- throw new InvalidPluginConfigurationException("Date format [" + dateFormatString
- + "] is not a valid simple date format.");
- }
- }
- String includesPatternString = logEventSource.getSimpleValue(
- LogEventSourcePropertyNames.INCLUDES_PATTERN, null);
- if (includesPatternString != null) {
- try {
- Pattern includesPattern = Pattern.compile(includesPatternString);
- processor.setIncludesPattern(includesPattern);
- } catch (PatternSyntaxException e) {
- throw new InvalidPluginConfigurationException("Includes pattern [" + includesPatternString
- + "] is not a valid regular expression.");
- }
+ // Log a warning then return if SIGAR isn't available, since LogFileEventPoller depends on it. We only log this
+ // warning if at least one event source is enabled, since otherwise the user probably doesn't care.
+ boolean sigarAvailable = this.resourceContext.getSystemInformation().isNative();
+ if (!sigarAvailable && !enabledEventSources.isEmpty()) {
+ boolean nativeSystemInfoDisabled = SystemInfoFactory.isNativeSystemInfoDisabled();
+ ResourceType resourceType = this.resourceContext.getResourceType();
+ List<String> logFilePaths = getLogFilePaths(enabledEventSources);
+ log.warn("Log files " + logFilePaths + " for [" + resourceType.getPlugin() + ":"
+ + resourceType.getName() + "] Resource with key [" + this.resourceContext.getResourceKey()
+ + "] cannot be polled, because log file polling requires RHQ native support, which "
+ + ((nativeSystemInfoDisabled) ? "has been disabled for this Agent" : "is not available on this platform") + ".");
+ return;
+ }
+
+ // Start up log file pollers for each of the enabled event sources.
+ for (PropertyMap logEventSource : enabledEventSources) {
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ if (logFilePath == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.LOG_FILE_PATH
+ + "] is not defined in map.");
+ }
+ File logFile = new File(logFilePath);
+ if (!logFile.canRead()) {
+ log.error("LOGFILE: Logfile at location " + logFilePath
+ + " does not exist or is not readable. Can not start watching the event log.");
+ continue;
+ }
+
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(LOG_ENTRY_EVENT_TYPE, logFile);
+ String dateFormatString = logEventSource.getSimpleValue(LogEventSourcePropertyNames.DATE_FORMAT, null);
+ if (dateFormatString != null) {
+ try {
+ DateFormat dateFormat = new SimpleDateFormat(dateFormatString); // TODO locale specific ?
+ processor.setDateFormat(dateFormat);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidPluginConfigurationException("Date format [" + dateFormatString
+ + "] is not a valid simple date format.");
}
- String minimumSeverityString = logEventSource.getSimpleValue(
- LogEventSourcePropertyNames.MINIMUM_SEVERITY, null);
- if (minimumSeverityString != null) {
- EventSeverity minimumSeverity = EventSeverity.valueOf(minimumSeverityString.toUpperCase());
- processor.setMinimumSeverity(minimumSeverity);
+ }
+ String includesPatternString = logEventSource.getSimpleValue(
+ LogEventSourcePropertyNames.INCLUDES_PATTERN, null);
+ if (includesPatternString != null) {
+ try {
+ Pattern includesPattern = Pattern.compile(includesPatternString);
+ processor.setIncludesPattern(includesPattern);
+ } catch (PatternSyntaxException e) {
+ throw new InvalidPluginConfigurationException("Includes pattern [" + includesPatternString
+ + "] is not a valid regular expression.");
}
- EventContext eventContext = this.resourceContext.getEventContext();
- EventPoller poller = new LogFileEventPoller(eventContext, LOG_ENTRY_EVENT_TYPE, logFile, processor);
- eventContext.registerEventPoller(poller, 60, logFile.getPath());
}
+ String minimumSeverityString = logEventSource.getSimpleValue(
+ LogEventSourcePropertyNames.MINIMUM_SEVERITY, null);
+ if (minimumSeverityString != null) {
+ EventSeverity minimumSeverity = EventSeverity.valueOf(minimumSeverityString.toUpperCase());
+ processor.setMinimumSeverity(minimumSeverity);
+ }
+ EventContext eventContext = this.resourceContext.getEventContext();
+ EventPoller poller = new LogFileEventPoller(eventContext, LOG_ENTRY_EVENT_TYPE, logFile, processor);
+ eventContext.registerEventPoller(poller, POLLING_INTERVAL_IN_SECONDS, logFile.getPath());
+ this.startedEventSources.add(logEventSource);
}
}
public void stopLogFileEventPollers() {
- Configuration pluginConfig = this.resourceContext.getPluginConfiguration();
- PropertyList logEventSources = pluginConfig.getList(LOG_EVENT_SOURCES_CONFIG_PROP);
- for (Property prop : logEventSources.getList()) {
- PropertyMap logEventSource = (PropertyMap) prop;
- String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ boolean sigarAvailable = this.resourceContext.getSystemInformation().isNative();
+ if (!sigarAvailable) {
+ return;
+ }
+
+ for (Iterator<PropertyMap> iterator = this.startedEventSources.iterator(); iterator.hasNext(); ) {
+ PropertyMap logEventSource = iterator.next();
EventContext eventContext = this.resourceContext.getEventContext();
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
eventContext.unregisterEventPoller(LOG_ENTRY_EVENT_TYPE, logFilePath);
+ iterator.remove();
+ }
+ }
+
+ private List<String> getLogFilePaths(List<PropertyMap> enabledEventSources) {
+ List<String> logFilePaths = new ArrayList<String>(enabledEventSources.size());
+ for (PropertyMap logEventSource : enabledEventSources) {
+ String logFilePath = logEventSource.getSimpleValue(LogEventSourcePropertyNames.LOG_FILE_PATH, null);
+ if (logFilePath == null) {
+ throw new IllegalStateException("Required property [" + LogEventSourcePropertyNames.LOG_FILE_PATH
+ + "] is not defined in map.");
+ }
+ logFilePaths.add(logFilePath);
}
+ return logFilePaths;
}
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
index b0b37ec..1735aff 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
@@ -24,6 +24,7 @@ package org.rhq.core.pc.event;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventDefinition;
import org.rhq.core.domain.resource.Resource;
@@ -99,7 +100,7 @@ public class EventContextImpl implements EventContext {
unregisterEventPollerInternal(eventType, sourceLocation);
}
- @NotNull
+ @Nullable
public SigarProxy getSigar() {
return getEventManager().getSigar();
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
index 4ad5c50..87b9bd7 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventManager.java
@@ -34,6 +34,7 @@ import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.rhq.core.domain.event.Event;
import org.rhq.core.domain.event.EventDefinition;
import org.rhq.core.domain.event.EventSource;
@@ -44,6 +45,7 @@ import org.rhq.core.pc.PluginContainerConfiguration;
import org.rhq.core.pc.util.LoggingThreadFactory;
import org.rhq.core.pluginapi.event.EventPoller;
import org.rhq.core.system.SigarAccess;
+import org.rhq.core.system.SystemInfoException;
/**
* Manager for the Plugin Container's Event subsystem.
@@ -113,9 +115,12 @@ public class EventManager implements ContainerService {
}
}
+ @Nullable
SigarProxy getSigar() {
if (this.sigar == null) {
- this.sigar = SigarAccess.getSigar();
+ if (SigarAccess.isSigarAvailable()) {
+ this.sigar = SigarAccess.getSigar();
+ }
}
return this.sigar;
}
commit 47aff4689a8275d18382a8f0f93d7144cc8f0795
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 31 16:55:49 2012 +0100
Fix compile error
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 6205576..382a145 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
@@ -173,7 +173,7 @@ public class ASConnection {
Result failure = new Result();
failure.setFailureDescription(ste.getMessage());
failure.setOutcome("failure");
-// failure.setThrowable(ste); TODO
+ failure.setRhqThrowable(ste);
JsonNode ret = mapper.valueToTree(failure);
return ret;
@@ -201,7 +201,7 @@ public class ASConnection {
Result failure = new Result();
failure.setFailureDescription(e.getMessage());
failure.setOutcome("failure");
-// failure.setThrowable(e); TODO
+ failure.setRhqThrowable(e);
JsonNode ret = mapper.valueToTree(failure);
return ret;
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 60f819f..8078e15 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
@@ -162,7 +162,7 @@ public class BaseServerComponent extends BaseComponent {
* reading, this is a good sign.
*/
if (!res.isSuccess()) {
- if (res.getThrowable()!=null && (res.getThrowable() instanceof ConnectException || res.getThrowable().getMessage().equals("Connection refused"))) {
+ if (res.getRhqThrowable()!=null && (res.getRhqThrowable() instanceof ConnectException || res.getRhqThrowable().getMessage().equals("Connection refused"))) {
operationResult.setSimpleResult("Success");
log.debug("Got a ConnectionRefused for operation " + name + " this is considered ok, as the remote server sometimes closes the communications channel before sending a reply");
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
index abf40fa..c87b899 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
@@ -173,6 +173,9 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
Operation op = new ReadChildrenResources(address1,"deployment");
ComplexResult cres = getASConnection().executeComplex(op);
+ if (cres==null)
+ return details;
+
if (!cres.isSuccess())
return details;
@@ -181,19 +184,22 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
Map<String,Object> deployment = (Map<String, Object>) deployments.get(key);
log.info("Discover package [" + key + "] for type [" + type + "]");
- List<Map> contentList = (List<Map>) deployment.get("content"); // deployments on SG or ManagedServer level have no hash
- Map<String,Map> hashMap = contentList.get(0);
- Map<String,String> bvMap = hashMap.get("hash");
- String content = bvMap.get("BYTES_VALUE");
- PackageDetailsKey pdKey = new PackageDetailsKey(key,
- content, // no way to obtain the user defined version from the server
- type.getName(),
- "noarch"
- );
- ResourcePackageDetails detail = new ResourcePackageDetails(pdKey);
- detail.setSHA256(content);
-
- details.add(detail);
+ List<Map> contentList = (List<Map>) deployment.get("content"); // TODO deployments on SG or ManagedServer level have no hash
+ if (contentList!=null) {
+
+ Map<String,Map> hashMap = contentList.get(0);
+ Map<String,String> bvMap = hashMap.get("hash");
+ String content = bvMap.get("BYTES_VALUE");
+ PackageDetailsKey pdKey = new PackageDetailsKey(key,
+ content, // no way to obtain the user defined version from the server
+ type.getName(),
+ "noarch"
+ );
+ ResourcePackageDetails detail = new ResourcePackageDetails(pdKey);
+ detail.setSHA256(content);
+
+ details.add(detail);
+ }
}
return details;
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
index f21e598..b46b108 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
@@ -117,7 +117,7 @@ public class HostControllerComponent extends BaseServerComponent implements Oper
else {
report.setErrorMessage(res.getFailureDescription());
report.setStatus(CreateResourceStatus.FAILURE);
- report.setException(res.getThrowable());
+ report.setException(res.getRhqThrowable());
}
return report;
}
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 8f6cfa0..1c68eca 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
@@ -40,6 +40,8 @@ public class Result {
private boolean success = false;
@JsonProperty("rolled-back")
private boolean rolledBack = false;
+ @JsonIgnore
+ private Throwable rhqThrowable;
/** Record throwsables during low level processing */
@JsonIgnore
@@ -106,6 +108,13 @@ public class Result {
this.throwable = throwable;
}
+ public Throwable getRhqThrowable() {
+ return rhqThrowable;
+ }
+
+ public void setRhqThrowable(Throwable rhqThrowable) {
+ this.rhqThrowable = rhqThrowable;
+ }
@Override
public String toString() {
commit 02dafbc97a76c3813afd0f05b213d8a1de70a3c2
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 31 14:35:07 2012 +0100
[BZ 786106] Wrap calls to obtain managers in privileged blocks so that 3rd
callers can safely obtain them.
The StandardBindings put all the managers into the script context before
the script engine is initialized with the security measures which makes
the managers available inside the scripts. Java code that gets injected as
other params into the scripts (like the "ProxyFactory" (of class
ResourceClientFactory) would suffer from access control exceptions when
it tried to obtain some manager while being called from the script because
it would try to call the methods from the LocalClient to obtain the remote
interfaces directly, without a wrapping in a privileged block). Obtaining
the remote interfaces is a safe operation wrt the scripts and so can be
wrapped in privileged block so that any caller of the LocalClient can
have access to the regardless of the access control restrictions in place.
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
index 025b60d..2414bf6 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClient.java
@@ -21,6 +21,9 @@ package org.rhq.enterprise.client;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
import java.util.HashMap;
import java.util.Map;
@@ -79,141 +82,335 @@ public class LocalClient implements RhqFacade {
this.subject = subject;
}
+ @Override
public Subject getSubject() {
return subject;
}
+ @Override
public Subject login(String user, String password) throws Exception {
return subject;
}
+ @Override
public void logout() {
}
+ @Override
public boolean isLoggedIn() {
return true;
}
+ @Override
public AlertManagerRemote getAlertManager() {
- return getProxy(LookupUtil.getAlertManager(), AlertManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<AlertManagerRemote>() {
+ @Override
+ public AlertManagerRemote run() {
+ return AccessController.doPrivileged(new PrivilegedAction<AlertManagerRemote>() {
+ @Override
+ public AlertManagerRemote run() {
+ return getProxy(LookupUtil.getAlertManager(), AlertManagerRemote.class);
+ }
+ });
+ }
+ });
}
+ @Override
public AlertDefinitionManagerRemote getAlertDefinitionManager() {
- return getProxy(LookupUtil.getAlertDefinitionManager(), AlertDefinitionManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<AlertDefinitionManagerRemote>() {
+ @Override
+ public AlertDefinitionManagerRemote run() {
+ return getProxy(LookupUtil.getAlertDefinitionManager(), AlertDefinitionManagerRemote.class);
+ }
+ });
}
+ @Override
public AvailabilityManagerRemote getAvailabilityManager() {
- return getProxy(LookupUtil.getAvailabilityManager(), AvailabilityManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<AvailabilityManagerRemote>() {
+ @Override
+ public AvailabilityManagerRemote run() {
+ return getProxy(LookupUtil.getAvailabilityManager(), AvailabilityManagerRemote.class);
+ }
+ });
}
+ @Override
public BundleManagerRemote getBundleManager() {
- return getProxy(LookupUtil.getBundleManager(), BundleManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<BundleManagerRemote>() {
+ @Override
+ public BundleManagerRemote run() {
+ return AccessController.doPrivileged(new PrivilegedAction<BundleManagerRemote>() {
+ @Override
+ public BundleManagerRemote run() {
+ return getProxy(LookupUtil.getBundleManager(), BundleManagerRemote.class);
+ }
+ });
+ }
+ });
}
+ @Override
public CallTimeDataManagerRemote getCallTimeDataManager() {
- return getProxy(LookupUtil.getCallTimeDataManager(), CallTimeDataManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<CallTimeDataManagerRemote>() {
+ @Override
+ public CallTimeDataManagerRemote run() {
+ return getProxy(LookupUtil.getCallTimeDataManager(), CallTimeDataManagerRemote.class);
+ }
+ });
}
+ @Override
public RepoManagerRemote getRepoManager() {
- return getProxy(LookupUtil.getRepoManagerLocal(), RepoManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<RepoManagerRemote>() {
+ @Override
+ public RepoManagerRemote run() {
+ return getProxy(LookupUtil.getRepoManagerLocal(), RepoManagerRemote.class);
+ }
+ });
}
+ @Override
public ConfigurationManagerRemote getConfigurationManager() {
- return getProxy(LookupUtil.getConfigurationManager(), ConfigurationManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ConfigurationManagerRemote>() {
+ @Override
+ public ConfigurationManagerRemote run() {
+ return getProxy(LookupUtil.getConfigurationManager(), ConfigurationManagerRemote.class);
+ }
+ });
}
+ @Override
public ContentManagerRemote getContentManager() {
- return getProxy(LookupUtil.getContentManager(), ContentManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ContentManagerRemote>() {
+ @Override
+ public ContentManagerRemote run() {
+ return getProxy(LookupUtil.getContentManager(), ContentManagerRemote.class);
+ }
+ });
}
+ @Override
public DataAccessManagerRemote getDataAccessManager() {
- return getProxy(LookupUtil.getDataAccessManager(), DataAccessManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<DataAccessManagerRemote>() {
+ @Override
+ public DataAccessManagerRemote run() {
+ return getProxy(LookupUtil.getDataAccessManager(), DataAccessManagerRemote.class);
+ }
+ });
}
+ @Override
public DiscoveryBossRemote getDiscoveryBoss() {
- return getProxy(LookupUtil.getDiscoveryBoss(), DiscoveryBossRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<DiscoveryBossRemote>() {
+ @Override
+ public DiscoveryBossRemote run() {
+ return getProxy(LookupUtil.getDiscoveryBoss(), DiscoveryBossRemote.class);
+ }
+ });
}
+ @Override
public DriftManagerRemote getDriftManager() {
- return getProxy(LookupUtil.getDriftManager(), DriftManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<DriftManagerRemote>() {
+ @Override
+ public DriftManagerRemote run() {
+ return getProxy(LookupUtil.getDriftManager(), DriftManagerRemote.class);
+ }
+ });
}
public DriftTemplateManagerRemote getDriftTemplateManager() {
- return getProxy(LookupUtil.getDriftTemplateManager(), DriftTemplateManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<DriftTemplateManagerRemote>() {
+ @Override
+ public DriftTemplateManagerRemote run() {
+ return getProxy(LookupUtil.getDriftTemplateManager(), DriftTemplateManagerRemote.class);
+ }
+ });
}
+ @Override
public EventManagerRemote getEventManager() {
- return getProxy(LookupUtil.getEventManager(), EventManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<EventManagerRemote>() {
+ @Override
+ public EventManagerRemote run() {
+ return getProxy(LookupUtil.getEventManager(), EventManagerRemote.class);
+ }
+ });
}
+ @Override
public MeasurementBaselineManagerRemote getMeasurementBaselineManager() {
- return getProxy(LookupUtil.getMeasurementBaselineManager(), MeasurementBaselineManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<MeasurementBaselineManagerRemote>() {
+ @Override
+ public MeasurementBaselineManagerRemote run() {
+ return getProxy(LookupUtil.getMeasurementBaselineManager(), MeasurementBaselineManagerRemote.class);
+ }
+ });
}
+ @Override
public MeasurementDataManagerRemote getMeasurementDataManager() {
- return getProxy(LookupUtil.getMeasurementDataManager(), MeasurementDataManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<MeasurementDataManagerRemote>() {
+ @Override
+ public MeasurementDataManagerRemote run() {
+ return getProxy(LookupUtil.getMeasurementDataManager(), MeasurementDataManagerRemote.class);
+ }
+ });
}
+ @Override
public MeasurementDefinitionManagerRemote getMeasurementDefinitionManager() {
- return getProxy(LookupUtil.getMeasurementDefinitionManager(), MeasurementDefinitionManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<MeasurementDefinitionManagerRemote>() {
+ @Override
+ public MeasurementDefinitionManagerRemote run() {
+ return getProxy(LookupUtil.getMeasurementDefinitionManager(), MeasurementDefinitionManagerRemote.class);
+ }
+ });
}
+ @Override
public MeasurementScheduleManagerRemote getMeasurementScheduleManager() {
- return getProxy(LookupUtil.getMeasurementScheduleManager(), MeasurementScheduleManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<MeasurementScheduleManagerRemote>() {
+ @Override
+ public MeasurementScheduleManagerRemote run() {
+ return getProxy(LookupUtil.getMeasurementScheduleManager(), MeasurementScheduleManagerRemote.class);
+ }
+ });
}
+ @Override
public OperationManagerRemote getOperationManager() {
- return getProxy(LookupUtil.getOperationManager(), OperationManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<OperationManagerRemote>() {
+ @Override
+ public OperationManagerRemote run() {
+ return getProxy(LookupUtil.getOperationManager(), OperationManagerRemote.class);
+ }
+ });
}
+ @Override
public ResourceManagerRemote getResourceManager() {
- return getProxy(LookupUtil.getResourceManager(), ResourceManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ResourceManagerRemote>() {
+ @Override
+ public ResourceManagerRemote run() {
+ return getProxy(LookupUtil.getResourceManager(), ResourceManagerRemote.class);
+ }
+ });
}
+ @Override
public ResourceFactoryManagerRemote getResourceFactoryManager() {
- return getProxy(LookupUtil.getResourceFactoryManager(), ResourceFactoryManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ResourceFactoryManagerRemote>() {
+ @Override
+ public ResourceFactoryManagerRemote run() {
+ return getProxy(LookupUtil.getResourceFactoryManager(), ResourceFactoryManagerRemote.class);
+ }
+ });
}
+ @Override
public ResourceGroupManagerRemote getResourceGroupManager() {
- return getProxy(LookupUtil.getResourceGroupManager(), ResourceGroupManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ResourceGroupManagerRemote>() {
+ @Override
+ public ResourceGroupManagerRemote run() {
+ return getProxy(LookupUtil.getResourceGroupManager(), ResourceGroupManagerRemote.class);
+ }
+ });
}
+ @Override
public ResourceTypeManagerRemote getResourceTypeManager() {
- return getProxy(LookupUtil.getResourceTypeManager(), ResourceTypeManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<ResourceTypeManagerRemote>() {
+ @Override
+ public ResourceTypeManagerRemote run() {
+ return getProxy(LookupUtil.getResourceTypeManager(), ResourceTypeManagerRemote.class);
+ }
+ });
}
+ @Override
public RoleManagerRemote getRoleManager() {
- return getProxy(LookupUtil.getRoleManager(), RoleManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<RoleManagerRemote>() {
+ @Override
+ public RoleManagerRemote run() {
+ return getProxy(LookupUtil.getRoleManager(), RoleManagerRemote.class);
+ }
+ });
}
+ @Override
public SavedSearchManagerRemote getSavedSearchManager() {
- return getProxy(LookupUtil.getSavedSearchManager(), SavedSearchManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<SavedSearchManagerRemote>() {
+ @Override
+ public SavedSearchManagerRemote run() {
+ return getProxy(LookupUtil.getSavedSearchManager(), SavedSearchManagerRemote.class);
+ }
+ });
}
+ @Override
public SubjectManagerRemote getSubjectManager() {
- return getProxy(LookupUtil.getSubjectManager(), SubjectManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<SubjectManagerRemote>() {
+ @Override
+ public SubjectManagerRemote run() {
+ return getProxy(LookupUtil.getSubjectManager(), SubjectManagerRemote.class);
+ }
+ });
}
+ @Override
public SupportManagerRemote getSupportManager() {
- return getProxy(LookupUtil.getSupportManager(), SupportManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<SupportManagerRemote>() {
+ @Override
+ public SupportManagerRemote run() {
+ return getProxy(LookupUtil.getSupportManager(), SupportManagerRemote.class);
+ }
+ });
}
+ @Override
public SystemManagerRemote getSystemManager() {
- return getProxy(LookupUtil.getSystemManager(), SystemManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<SystemManagerRemote>() {
+ @Override
+ public SystemManagerRemote run() {
+ return getProxy(LookupUtil.getSystemManager(), SystemManagerRemote.class);
+ }
+ });
}
+ @Override
public RemoteInstallManagerRemote getRemoteInstallManager() {
- return getProxy(LookupUtil.getRemoteInstallManager(), RemoteInstallManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<RemoteInstallManagerRemote>() {
+ @Override
+ public RemoteInstallManagerRemote run() {
+ return getProxy(LookupUtil.getRemoteInstallManager(), RemoteInstallManagerRemote.class);
+ }
+ });
}
+ @Override
public TagManagerRemote getTagManager() {
- return getProxy(LookupUtil.getTagManager(), TagManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<TagManagerRemote>() {
+ @Override
+ public TagManagerRemote run() {
+ return getProxy(LookupUtil.getTagManager(), TagManagerRemote.class);
+ }
+ });
}
+ @Override
public SynchronizationManagerRemote getSynchronizationManager() {
- return getProxy(LookupUtil.getSynchronizationManager(), SynchronizationManagerRemote.class);
+ return AccessController.doPrivileged(new PrivilegedAction<SynchronizationManagerRemote>() {
+ @Override
+ public SynchronizationManagerRemote run() {
+ return getProxy(LookupUtil.getSynchronizationManager(), SynchronizationManagerRemote.class);
+ }
+ });
}
-
+
+ @Override
public Map<String, Object> getManagers() {
if (managers == null) {
diff --git a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
index de0d912..f6772e5 100644
--- a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
+++ b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
@@ -21,7 +21,6 @@ package org.rhq.enterprise.client.security.test;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
-import java.io.SerializablePermission;
import java.security.PermissionCollection;
import java.util.Collections;
@@ -31,7 +30,6 @@ import javax.script.ScriptException;
import org.testng.Assert;
import org.testng.annotations.Test;
-import org.rhq.bindings.SandboxedScriptEngine;
import org.rhq.bindings.ScriptEngineFactory;
import org.rhq.bindings.StandardBindings;
import org.rhq.bindings.StandardScriptPermissions;
@@ -179,6 +177,21 @@ public class JndiAccessTest extends AbstractEJB3Test {
}
}
+ @Test
+ public void testProxyFactoryWorksWithSecuredScriptEngine() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval("var resource = ProxyFactory.getResource(10001);");
+ } catch (ScriptException e) {
+ //if the script fails (there is no resource with ID 10001)
+ //it should not be because of an access control exception
+ checkIsNotASecurityException(e);
+ }
+ }
+
private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
@@ -193,4 +206,11 @@ public class JndiAccessTest extends AbstractEJB3Test {
Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
}
+
+ private static void checkIsNotASecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertFalse(message.contains(permissionTrace), "The script exception does seem to be caused by the AllowRhqServerInternalsAccessPermission security exception although it shouldn't. " + message);
+ }
}
commit fda3d0ac47f1eb68f6ef9d2d4f60df21262a1500
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 30 22:27:51 2012 +0100
Set timeouts for connecting and reading of data.
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 9651be2..6205576 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
@@ -26,6 +26,7 @@ import java.io.OutputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
import java.net.URL;
import org.apache.commons.logging.Log;
@@ -108,12 +109,17 @@ public class ASConnection {
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/json");
conn.addRequestProperty("Accept","application/json");
+ conn.setConnectTimeout(10 * 1000); // 10s
+ conn.setReadTimeout(10 * 1000); // 10s
+
+ if (conn.getReadTimeout()!=10*1000)
+ log.warn("JRE uses a broken timeout mechanism - nothing we can do");
OutputStream out = conn.getOutputStream();
- String result = mapper.writeValueAsString(operation);
+ String json_to_send = mapper.writeValueAsString(operation);
if (verbose) {
- log.info("Json to send: " + result);
+ log.info("Json to send: " + json_to_send);
}
mapper.writeValue(out, operation);
@@ -158,6 +164,19 @@ public class ASConnection {
} else {
log.error("IS was null and code was " + responseCode);
}
+ } catch (IllegalArgumentException iae) {
+ log.error("Illegal argument " + iae);
+ log.error(" for input " + operation);
+ } catch (SocketTimeoutException ste) {
+ log.error("Request to AS timed out " + ste.getMessage());
+ conn.disconnect();
+ Result failure = new Result();
+ failure.setFailureDescription(ste.getMessage());
+ failure.setOutcome("failure");
+// failure.setThrowable(ste); TODO
+
+ JsonNode ret = mapper.valueToTree(failure);
+ return ret;
} catch (IOException e) {
log.error("Failed to get data: " + e.getMessage());
@@ -182,7 +201,7 @@ public class ASConnection {
Result failure = new Result();
failure.setFailureDescription(e.getMessage());
failure.setOutcome("failure");
- failure.setThrowable(e);
+// failure.setThrowable(e); TODO
JsonNode ret = mapper.valueToTree(failure);
return ret;
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
index ff5aa94..90316a4 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
@@ -82,6 +82,8 @@ public class ASUploadConnection {
// Create the HTTP connection to the upload URL
String url = "http://" + host + ":" + port + UPLOAD_URL_PATH;
connection = (HttpURLConnection) new URL(url).openConnection();
+ connection.setConnectTimeout(10 * 1000); // 10s
+ connection.setReadTimeout(60 * 1000); // 60s
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod(POST_REQUEST_METHOD);
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 42ffee7..8f6cfa0 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
@@ -43,7 +43,7 @@ public class Result {
/** Record throwsables during low level processing */
@JsonIgnore
- private Throwable throwable;
+ private Map<String,Object> throwable;
public Object getResponseHeaders() {
return responseHeaders;
@@ -98,11 +98,11 @@ public class Result {
this.rolledBack = rolledBack;
}
- public Throwable getThrowable() {
+ public Map<String, Object> getThrowable() {
return throwable;
}
- public void setThrowable(Throwable throwable) {
+ public void setThrowable(Map<String,Object> throwable) {
this.throwable = throwable;
}
commit 8e4ea4f7a28dd0f877e909941615136af85d1b4b
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Mon Jan 30 10:18:16 2012 -0500
[BZ 703557] eclipse has to be told where tools.jar is in order to build the jmx plugin
diff --git a/.classpath b/.classpath
index 9eaf31b..e20fe75 100644
--- a/.classpath
+++ b/.classpath
@@ -124,7 +124,8 @@
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/resteasy-jaxrs/2.2.1.GA/resteasy-jaxrs-2.2.1.GA.jar"/>
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/resteasy-jettison-provider/2.2.1.GA/resteasy-jettison-provider-2.2.1.GA.jar"/>
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/jaxrs-api/2.2.1.GA/jaxrs-api-2.2.1.GA.jar"/>
- <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/sasl/jboss-sasl/1.0.0.Beta9/jboss-sasl-1.0.0.Beta9.jar"/>
+ <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/sasl/jboss-sasl/1.0.0.Beta9/jboss-sasl-1.0.0.Beta9.jar"/>
+ <classpathentry exported="true" kind="var" path="JDK_HOME/lib/tools.jar"/>
<classpathentry kind="src" path="modules/common/ant-bundle/src/main/java"/>
<classpathentry kind="src" path="modules/enterprise/server/itests/src/test/java"/>
<classpathentry kind="src" path="modules/enterprise/server/plugins/drift-mongodb/src/main/java"/>
commit 4073cfff186308efce9da4566b749c1076e91f7f
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 30 16:01:03 2012 +0100
BZ 758655 - more fixes.
BZ 767629 - filter, only allow .jar for jdbc drivers.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
index 60550be..980d9e9 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
@@ -25,6 +25,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.ejb.EJB;
import javax.ejb.Stateless;
@@ -2511,6 +2513,11 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
PropertyOptionsSource pos = pds.getOptionsSource();
PropertyOptionsSource.TargetType tt = pos.getTargetType();
String expression = pos.getExpression();
+ String filter = pos.getFilter();
+ Pattern filterPattern = null;
+ if (filter!=null)
+ filterPattern = Pattern.compile(filter);
+
if (tt == PropertyOptionsSource.TargetType.RESOURCE || tt == PropertyOptionsSource.TargetType.CONFIGURATION) {
ResourceCriteria criteria = new ResourceCriteria();
@@ -2533,10 +2540,21 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
if (tt == PropertyOptionsSource.TargetType.RESOURCE) {
- PropertyDefinitionEnumeration pde = new PropertyDefinitionEnumeration(composite.getResource()
- .getName(), "" + composite.getResource().getName());
- // TODO filter -- or leave up to search expression??
- pds.getEnumeratedValues().add(pde);
+ String name = composite.getResource().getName();
+ // filter if the user provided a filter
+
+ if (filterPattern !=null ) {
+ Matcher m = filterPattern.matcher(name);
+ if (m.matches()) {
+ PropertyDefinitionEnumeration pde = new PropertyDefinitionEnumeration(name, "" + name);
+ pds.getEnumeratedValues().add(pde);
+ }
+ } else { // Filter is null -> none provided -> do not filter
+ PropertyDefinitionEnumeration pde = new PropertyDefinitionEnumeration(name, "" + name);
+ pds.getEnumeratedValues().add(pde);
+
+ }
+
} else if (tt == PropertyOptionsSource.TargetType.CONFIGURATION) {
// for configuration we need to drill down into the resource configuration
if (!handleConfigurationTarget(pds, expression, composite.getResource()))
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
index 4a7c4cc..68c0bce 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
@@ -69,7 +69,7 @@ public class DatasourceComponent extends BaseComponent implements OperationFacet
addRequiredToOp(op,parameters,"jndi-name");
addOptionalToOp(op,parameters,"user-name");
addOptionalToOp(op,parameters,"password");
- addRequiredToOp(op,parameters,"xa-data-source-class");
+ addRequiredToOp(op,parameters,"xa-datasource-class");
Map<String,Object> props = new HashMap<String, Object>(); // TODO
op.addAdditionalProperty("xa-data-source-properties",props);
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 3f29cce..3ef70c9 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
@@ -1017,7 +1017,7 @@
<parameters>
<c:simple-property name="name" required="true" description="Name of the datasource"/>
<c:simple-property name="driver-name" required="true">
- <c:option-source target="resource" expression="type=^Deployment$" filter="sameHierarchy"/>
+ <c:option-source target="resource" expression="type=^Deployment$" filter=".*\.jar"/>
</c:simple-property>
<c:simple-property name="jndi-name" description="JNDI-Name of the Datasource" required="true"/>
<c:simple-property name="connection-url" description="URL for the connection to the database" required="true"/>
@@ -1033,11 +1033,10 @@
<parameters>
<c:simple-property name="name" required="true" description="Name of the datasource"/>
<c:simple-property name="driver-name" required="true">
- <c:option-source target="resource" expression="type=^Deployment$"/>
+ <c:option-source target="resource" expression="type=^Deployment$" filter=".*\.jar"/>
</c:simple-property>
- <c:simple-property name="xa-data-source-class" required="true" description="xa-data-source-class"/>
+ <c:simple-property name="xa-datasource-class" required="true" description="xa-datasource-class"/>
<c:simple-property name="jndi-name" description="JNDI-Name of the Datasource" required="true"/>
- <!--<c:simple-property name="connection-url" description="URL for the connection to the database" required="true"/>-->
<c:simple-property name="user-name" description="User name for DB-connections" required="false" />
<c:simple-property name="password" description="Password" type="password" required="false"/>
<c:list-property name="xa-properties" displayName="XA Properties" description="Additional XA Properties" required="false">
@@ -1128,8 +1127,6 @@
description="Defines the JDBC driver the datasource should use with this format: driver-name>#major-version.minor-version where driver-name is the fully qualifed name of the JDBC driver class"/>
<c:simple-property name="new-connection-sql" type="string" readOnly="true" required="false"
description="Specifies an SQL statement to execute whenever a connection is added to the connection pool."/>
- <c:simple-property name="pool-name" type="string" readOnly="true"
- description="Specifies the pool name for the datasource used for management"/>
<c:simple-property name="url-delimiter" type="string" readOnly="true"
description="Specifies the delimeter for URLs in connection-url for HA datasources" required="false"/>
<c:simple-property name="url-selector-strategy-class-name" type="string" readOnly="true"
@@ -1273,11 +1270,10 @@
<metric property="DestroyedCount" description="The destroyed count" measurementType="trendsup"/>
<resource-configuration>
- <c:simple-property name="xa-data-source-class" required="true" type="string" readOnly="true" description="The fully qualifed name of the javax.sql.XADataSource implementation"/>
+ <c:simple-property name="xa-datasource-class" required="true" type="string" readOnly="true" description="The fully qualifed name of the javax.sql.XADataSource implementation"/>
<c:simple-property name="jndi-name" required="true" type="string" readOnly="true" description="Specifies the JNDI name for the datasource"/>
<c:simple-property name="driver-name" required="true" type="string" readOnly="true" description="Defines the JDBC driver the datasource should use. It is a symbolic name matching the the name of installed driver. In case the driver is deployed as jar, the name is the name of deployment unit"/>
<c:simple-property name="new-connection-sql" required="false" type="string" readOnly="true" description="Specifies an SQL statement to execute whenever a connection is added to the connection pool."/>
- <c:simple-property name="pool-name" required="false" type="string" readOnly="true" description="Specifies the pool name for the datasource used for management"/>
<c:simple-property name="url-delimiter" required="false" type="string" readOnly="true" description="Specifies the delimeter for URLs in connection-url for HA datasources"/>
<c:simple-property name="url-selector-strategy-class-name" required="false" type="string" readOnly="true" description="A class that implements org.jboss.jca.adapters.jdbc.URLSelectorStrategy"/>
<c:simple-property name="use-java-context" required="false" type="boolean" readOnly="true" description="Setting this to false will bind the DataSource into global JNDI;"/>
@@ -1286,7 +1282,7 @@
<c:simple-property name="min-pool-size" required="false" type="integer" readOnly="false" description="The min-pool-size element indicates the minimum number of connections a pool should hold. These are not created until a Subject is known from a request for a connection."/>
<c:simple-property name="pool-prefill" required="false" type="boolean" readOnly="false" description="Whether to attempt to prefill the connection pool. Changing this value require a server restart."/>
<c:simple-property name="pool-use-strict-min" required="false" type="boolean" readOnly="false" description="Define if the min-pool-size should be considered a strictly."/>
- <c:simple-property name="interliving" required="false" type="boolean" readOnly="true" description="An element to enable interleaving for XA connection factories"/>
+ <c:simple-property name="interleaving" required="false" type="boolean" readOnly="true" description="An element to enable interleaving for XA connection factories"/>
<c:simple-property name="no-tx-separate-pool" required="false" type="boolean" readOnly="true" description="Oracle does not like XA connections getting used both inside and outside a JTA transaction. To workaround the problem you can create separate sub-pools for the different context"/>
<c:simple-property name="pad-xid" required="false" type="boolean" readOnly="true" description="Should the Xid be padded"/>
<c:simple-property name="same-rm-override" required="false" type="boolean" readOnly="true" description="The is-same-rm-override element allows one to unconditionally set whether the javax.transaction.xa.XAResource.isSameRM(XAResource) returns true or false"/>
commit a8622b6e11a76be7558ef8561f475e827ff2a80c
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 30 13:57:15 2012 +0100
BZ 758655 - remove no longer needed attributes, as they were removed in AS7
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
index 1a44230..4a7c4cc 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
@@ -55,7 +55,6 @@ public class DatasourceComponent extends BaseComponent implements OperationFacet
op = new Operation("add",theAddress);
addRequiredToOp(op,parameters,"driver-name");
addRequiredToOp(op,parameters,"jndi-name");
- addRequiredToOp(op, parameters, "pool-name");
addRequiredToOp(op, parameters, "connection-url");
addOptionalToOp(op, parameters, "user-name");
addOptionalToOp(op,parameters,"password");
@@ -68,14 +67,11 @@ public class DatasourceComponent extends BaseComponent implements OperationFacet
op = new Operation("add",theAddress);
addRequiredToOp(op,parameters,"driver-name");
addRequiredToOp(op,parameters,"jndi-name");
- addRequiredToOp(op,parameters,"pool-name");
- addRequiredToOp(op,parameters,"connection-url");
addOptionalToOp(op,parameters,"user-name");
addOptionalToOp(op,parameters,"password");
addRequiredToOp(op,parameters,"xa-data-source-class");
Map<String,Object> props = new HashMap<String, Object>(); // TODO
- props.put("_foo","_bar"); // TODO AS7-1209
op.addAdditionalProperty("xa-data-source-properties",props);
}
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 2e6aba3..3f29cce 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
@@ -1021,7 +1021,6 @@
</c:simple-property>
<c:simple-property name="jndi-name" description="JNDI-Name of the Datasource" required="true"/>
<c:simple-property name="connection-url" description="URL for the connection to the database" required="true"/>
- <c:simple-property name="pool-name" description="Name of the pool" required="true"/>
<c:simple-property name="user-name" description="User name for DB-connections" required="false" />
<c:simple-property name="password" description="Password" type="password" required="false"/>
</parameters>
@@ -1038,8 +1037,7 @@
</c:simple-property>
<c:simple-property name="xa-data-source-class" required="true" description="xa-data-source-class"/>
<c:simple-property name="jndi-name" description="JNDI-Name of the Datasource" required="true"/>
- <c:simple-property name="connection-url" description="URL for the connection to the database" required="true"/>
- <c:simple-property name="pool-name" description="Name of the pool" required="true"/>
+ <!--<c:simple-property name="connection-url" description="URL for the connection to the database" required="true"/>-->
<c:simple-property name="user-name" description="User name for DB-connections" required="false" />
<c:simple-property name="password" description="Password" type="password" required="false"/>
<c:list-property name="xa-properties" displayName="XA Properties" description="Additional XA Properties" required="false">
commit 04f7e30401feb9cc210e075779792db1c08e02b6
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 30 12:05:16 2012 +0100
Small comment fix.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/SystemSettingsView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/SystemSettingsView.java
index b5cf9e8..1badea3 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/SystemSettingsView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/SystemSettingsView.java
@@ -438,7 +438,7 @@ public class SystemSettingsView extends LocatableVLayout implements PropertyValu
pd.setDescription(MSG.view_admin_systemSettings_BaselineDataSet_desc());
pd.setDisplayName(MSG.view_admin_systemSettings_BaselineDataSet_name());
pd.setPropertyGroupDefinition(baselineGroup);
- pd.addConstraints(new IntegerRangeConstraint(Long.valueOf(1), Long.valueOf(14))); // can't do more than 14 days since our raw tables don't hold more
+ pd.addConstraints(new IntegerRangeConstraint(Long.valueOf(1), Long.valueOf(14))); // can't do more than 14 days since our 1h table doesn't hold more
pd.setDefaultValue("7");
break;
commit 1bdc6262cd500351b67d5685562f3e54ab03e2ff
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 30 11:35:36 2012 +0100
Add a note about the max. allowed value.
diff --git a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
index e96c012..8de2555 100644
--- a/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
+++ b/modules/enterprise/gui/coregui/src/main/resources/org/rhq/enterprise/gui/coregui/client/Messages.properties
@@ -507,7 +507,7 @@ view_admin_downloads_bundle_link_label = Link
view_admin_downloads_bundle_link_value = Download Bundle Deployer {0}
view_admin_downloads_bundle_loadError = Cannot get bundle deployer info
view_admin_downloads_cliAlertScriptsDownload = CLI Alert Scripts Download
-view_admin_downloads_cliAlertScripts_help = CLI alert scripts are pre-canned scripts that can be used for creating scripted alert notifications. The scripts will usually require some tweaking before they can be used as a notification on a particular alert definition.
+view_admin_downloads_cliAlertScripts_help = CLI alert scripts are pre-canned scripts that can be used for creating scripted alert notifications. The scripts will usually require some tweaking before they can be used as a notification on a particular alert definition.
view_admin_downloads_cliAlertScripts_loadError = Cannot get info on available CLI alert scripts for download
view_admin_downloads_cliAlertScripts_none = No CLI alert scripts are available for download
view_admin_downloads_cliDownload = Command Line Client Download
@@ -587,7 +587,7 @@ view_admin_systemSettings_BaseURL_desc = A URL to the server GUI, used mainly wi
view_admin_systemSettings_BaseURL_name = GUI Console URL
view_admin_systemSettings_BaselineDataSet_desc = The amount of past measurement data that is used to determine a baseline. This is specified in days.
view_admin_systemSettings_BaselineDataSet_name = Baseline Dataset
-view_admin_systemSettings_BaselineFrequency_desc = The frequency which the auto-calculation of baselines will be performed. If 0, baseline auto-calculation is disabled. This is specified in days.
+view_admin_systemSettings_BaselineFrequency_desc = The frequency which the auto-calculation of baselines will be performed. If 0, baseline auto-calculation is disabled. This is specified in days. Maximum value is 'Baseline Dataset'.
view_admin_systemSettings_BaselineFrequency_name = Baseline Calculation Frequency
view_admin_systemSettings_DataMaintenance_desc = How often database maintenance is performed (for example, vacuuming if using Postgres). This is specified in hours.
view_admin_systemSettings_DataMaintenance_name = Database Maintenance Period
commit 657f2f242c2193173b8e68b6cdb34f04f2057d43
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Fri Jan 27 16:56:27 2012 -0500
[BZ 785268] fix the case where you do a clean deploy but a file was edited (where the file content didn't change from bundle v1 to bundle v2)
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
index 40ce727..602df4c 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
@@ -422,9 +422,11 @@ public class Deployer {
// that a file is different from the deployment distribution.
// If the new is different from the original and if the new is different than the current, we need to backup the
// current because we will be overwriting the current file with the new.
+ // Note that if we were told to "clean", we never leave files alone (since everything must be cleaned) but
+ // we will backup the touched file that is being removed
String changedFileHashcode = changed.getValue();
String originalFileHashcode = original.get(changedFilePath);
- if (newHashcode.equals(originalFileHashcode)) {
+ if (newHashcode.equals(originalFileHashcode) && !clean) {
currentFilesToLeaveAlone.put(changedFilePath, originalFileHashcode);
} else if (!newHashcode.equals(changedFileHashcode)) {
currentFilesToBackup.add(changedFilePath);
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
index d8a355f..8a222a4 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
@@ -118,7 +118,11 @@ public class SimpleDeployerTest {
}
public void testX_Y_X() throws Exception {
- baseX_Y_X(false);
+ baseX_Y_X(false, false);
+ }
+
+ public void testX_Y_X_Clean() throws Exception {
+ baseX_Y_X(false, true);
}
public void testX_Y_Y() throws Exception {
@@ -174,7 +178,11 @@ public class SimpleDeployerTest {
}
public void testX_Y_X_DryRun() throws Exception {
- baseX_Y_X(true);
+ baseX_Y_X(true, false);
+ }
+
+ public void testX_Y_X_DryRun_Clean() throws Exception {
+ baseX_Y_X(true, true);
}
public void testX_Y_Y_DryRun() throws Exception {
@@ -414,7 +422,7 @@ public class SimpleDeployerTest {
}
}
- private void baseX_Y_X(boolean dryRun) throws Exception {
+ private void baseX_Y_X(boolean dryRun, boolean clean) throws Exception {
String newContent = "testX_Y_X";
String newHashcode = MessageDigestGenerator.getDigestString(newContent);
writeFile(newContent, this.currentFile);
@@ -423,11 +431,7 @@ public class SimpleDeployerTest {
null, null, true, null);
Deployer deployer = new Deployer(dd);
FileHashcodeMap newFileHashcodeMap;
- if (dryRun) {
- newFileHashcodeMap = deployer.dryRun(this.diff);
- } else {
- newFileHashcodeMap = deployer.deploy(this.diff);
- }
+ newFileHashcodeMap = deployer.deploy(this.diff, clean, dryRun);
// very important to understand this - even though the current file is changed, the hashcode
// stored in the map and the metadata directory is the ORIGINAL hashcode. This is to make it
@@ -439,17 +443,37 @@ public class SimpleDeployerTest {
assert newFileHashcodeMap.equals(this.originalFileHashcodeMap);
String[] contentHash = getOriginalFilenameContentHashcode();
- assert contentHash[0].equals(newContent);
- assert contentHash[1].equals(newHashcode);
+
+ // if we are cleaning, then the old content is blown away anyway and the original is replaced
+ // (but not if this is a dryRun - dryRun always means the changed/new content remains)
+ if (clean && !dryRun) {
+ assert contentHash[0].equals(originalContent);
+ assert contentHash[1].equals(originalHashcode);
+ } else {
+ assert contentHash[0].equals(newContent);
+ assert contentHash[1].equals(newHashcode);
+ }
// note nothing changed - our current file remains as is
assert this.diff.getAddedFiles().isEmpty() : this.diff;
assert this.diff.getDeletedFiles().isEmpty() : this.diff;
assert this.diff.getChangedFiles().isEmpty() : this.diff;
- assert this.diff.getBackedUpFiles().isEmpty() : this.diff;
+ if (clean) {
+ assert this.diff.getBackedUpFiles().size() == 1 : this.diff;
+ assert this.diff.getBackedUpFiles().containsKey(originalFileName) : this.diff;
+ File backupFile = new File(this.diff.getBackedUpFiles().get(originalFileName));
+ if (dryRun) {
+ assert !backupFile.exists() : "dry run should not create backup";
+ } else {
+ assert readFile(backupFile).equals(newContent) : "did not backup the correct file?";
+ }
+ } else {
+ assert this.diff.getBackedUpFiles().isEmpty() : this.diff;
+ }
assert this.diff.getIgnoredFiles().isEmpty() : this.diff;
assert this.diff.getRealizedFiles().isEmpty() : this.diff;
assert this.diff.getErrors().isEmpty() : this.diff;
+ assert this.diff.wasCleaned() == clean : this.diff;
if (dryRun) {
assert this.metadata.getCurrentDeploymentProperties().equals(originalDeployProps);
commit 2dc60e41f255d5b64b991be32eee560cd5887ed9
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Fri Jan 27 16:07:24 2012 -0500
[BZ 785270] add 4 new unit tests to make sure we handle the case when a new file was added but is not part of any bundle deployment (either in the original or new deployment)
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
index 2736f16..d8a355f 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
@@ -145,6 +145,14 @@ public class SimpleDeployerTest {
baseNoOriginalWithCurrentWithNew(false);
}
+ public void testNoOriginalWithCurrentNoNew() throws Exception {
+ baseNoOriginalWithCurrentNoNew(false, false);
+ }
+
+ public void testNoOriginalWithCurrentNoNew_Clean() throws Exception {
+ baseNoOriginalWithCurrentNoNew(false, true);
+ }
+
public void testNoCurrent() throws Exception {
baseNoCurrent(false);
}
@@ -193,6 +201,14 @@ public class SimpleDeployerTest {
baseNoOriginalWithCurrentWithNew(true);
}
+ public void testNoOriginalWithCurrentNoNew_DryRun() throws Exception {
+ baseNoOriginalWithCurrentNoNew(true, false);
+ }
+
+ public void testNoOriginalWithCurrentNoNew_DryRun_Clean() throws Exception {
+ baseNoOriginalWithCurrentNoNew(true, true);
+ }
+
public void testNoCurrent_DryRun() throws Exception {
baseNoCurrent(true);
}
@@ -683,6 +699,54 @@ public class SimpleDeployerTest {
}
}
+ /**
+ * This tests when there was no file in the bundle but some unknown file was added to the
+ * destination directory. When redeploying the same bundle, there is no original file,
+ * there is no new file, but there is a current file (which is unknown to the bundle).
+ * It should be removed and backed up.
+ */
+ private void baseNoOriginalWithCurrentNoNew(boolean dryRun, boolean clean) throws Exception {
+ String inTheWayFileName = "unknown.txt";
+ File inTheWayFile = new File(this.deployDir, inTheWayFileName);
+ String inTheWayContent = "this is a new file but shouldn't be here - its not part of the bundle";
+ writeFile(inTheWayContent, inTheWayFile);
+
+ DeploymentData dd = new DeploymentData(originalDeployProps, originalZipFiles, null, tmpDir, deployDir, null,
+ null, null, null, true, null);
+ Deployer deployer = new Deployer(dd);
+ FileHashcodeMap newFileHashcodeMap;
+ newFileHashcodeMap = deployer.deploy(this.diff, clean, dryRun);
+
+ assert newFileHashcodeMap.equals(this.originalFileHashcodeMap);
+ assert newFileHashcodeMap.size() == 1;
+ assert newFileHashcodeMap.get(originalFileName).equals(originalHashcode);
+ String[] contentHash = getOriginalFilenameContentHashcode();
+ assert contentHash[0].equals(originalContent);
+ assert contentHash[1].equals(originalHashcode);
+
+ assert this.diff.getAddedFiles().isEmpty() : this.diff;
+ assert this.diff.getDeletedFiles().size() == 1 : this.diff;
+ assert this.diff.getDeletedFiles().contains(inTheWayFileName) : this.diff;
+ assert this.diff.getChangedFiles().isEmpty() : this.diff;
+ assert this.diff.getBackedUpFiles().size() == 1 : this.diff;
+ assert this.diff.getBackedUpFiles().containsKey(inTheWayFileName) : this.diff;
+ assert this.diff.getIgnoredFiles().isEmpty() : this.diff;
+ assert this.diff.getRealizedFiles().isEmpty() : this.diff;
+ assert this.diff.getErrors().isEmpty() : this.diff;
+ assert this.diff.wasCleaned() == clean : this.diff;
+
+ assert this.metadata.getCurrentDeploymentProperties().equals(originalDeployProps);
+ assert this.metadata.getCurrentDeploymentFileHashcodes().equals(originalFileHashcodeMap);
+
+ // verify the backup copy
+ File backupFile = new File(this.diff.getBackedUpFiles().get(inTheWayFileName));
+ if (dryRun) {
+ assert !backupFile.exists() : "dry run should not create backup";
+ } else {
+ assert readFile(backupFile).equals(inTheWayContent) : "did not backup the correct file?";
+ }
+ }
+
private void baseNoCurrent(boolean dryRun) throws Exception {
assert this.currentFile.delete() : "Failed to delete the current file, cannot prepare the test";
commit 581bb4295d1a6bc3c991493a38f35ad9ef9073b7
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Jan 27 17:28:43 2012 +0100
Also allow to deploy to domain deployments.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
index 2e6163d..abf40fa 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
@@ -15,6 +15,7 @@ import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.content.transfer.ContentResponseResult;
+import org.rhq.core.domain.content.transfer.DeployIndividualPackageResponse;
import org.rhq.core.domain.content.transfer.DeployPackageStep;
import org.rhq.core.domain.content.transfer.DeployPackagesResponse;
import org.rhq.core.domain.content.transfer.RemovePackagesResponse;
@@ -89,11 +90,13 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
public DeployPackagesResponse deployPackages(Set<ResourcePackageDetails> packages,
ContentServices contentServices) {
+ log.info("Starting deployment..");
DeployPackagesResponse response = new DeployPackagesResponse();
if (packages.size()!=1) {
response.setOverallRequestResult(ContentResponseResult.FAILURE);
response.setOverallRequestErrorMessage("Can only deploy one package at a time");
+ log.warn("deployPackages can only deploy one package at a time");
}
ResourcePackageDetails detail = packages.iterator().next();
@@ -102,7 +105,7 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
OutputStream out = uploadConnection.getOutputStream(detail.getFileName());
ResourceType resourceType = context.getResourceType();
- log.info("trying " + resourceType.getName() + ", " + detail.getKey() );
+ log.info("trying deployment of" + resourceType.getName() + ", key=" + detail.getKey() );
contentServices.downloadPackageBits(context.getContentContext(),
detail.getKey(), out, true);
@@ -128,11 +131,15 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
try {
redeployOnServer(detail.getKey().getName(), hash);
response.setOverallRequestResult(ContentResponseResult.SUCCESS);
+ DeployIndividualPackageResponse packageResponse = new DeployIndividualPackageResponse(detail.getKey(), ContentResponseResult.SUCCESS);
+ response.addPackageResponse(packageResponse);
+
}
catch (Exception e) {
response.setOverallRequestResult(ContentResponseResult.FAILURE);
}
+ log.info(".. result is " + response);
return response;
}
@@ -172,8 +179,9 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
Map<String,Object> deployments = cres.getResult();
for (String key : deployments.keySet()) {
Map<String,Object> deployment = (Map<String, Object>) deployments.get(key);
+ log.info("Discover package [" + key + "] for type [" + type + "]");
- List<Map> contentList = (List<Map>) deployment.get("content");
+ List<Map> contentList = (List<Map>) deployment.get("content"); // deployments on SG or ManagedServer level have no hash
Map<String,Map> hashMap = contentList.get(0);
Map<String,String> bvMap = hashMap.get("hash");
String content = bvMap.get("BYTES_VALUE");
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
new file mode 100644
index 0000000..8db86c7
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DomainDeploymentComponent.java
@@ -0,0 +1,23 @@
+package org.rhq.modules.plugins.jbossas7;
+
+import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.modules.plugins.jbossas7.json.Operation;
+import org.rhq.modules.plugins.jbossas7.json.ReadResource;
+import org.rhq.modules.plugins.jbossas7.json.Result;
+
+/**
+ * Handle domain deployments
+ * @author Heiko W. Rupp
+ */
+public class DomainDeploymentComponent extends DeploymentComponent{
+
+ @Override
+ public AvailabilityType getAvailability() {
+ // Domain deployments have no 'enabled' attribute
+
+ Operation op = new ReadResource(getAddress());
+ Result res = getASConnection().execute(op);
+
+ return (res!=null && res.isSuccess()) ? AvailabilityType.UP: AvailabilityType.DOWN;
+ }
+}
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 fdebf0a..2e6aba3 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
@@ -284,7 +284,9 @@
<operation name="server:add" displayName="Create server" description="Add a new server to this host.">
<parameters>
<c:simple-property name="name" description="Name of this new server" required="true"/>
- <c:simple-property name="group" displayName="Server Group" description="Server group to put this sever in" default="" required="false"/>
+ <c:simple-property name="group" displayName="Server Group" description="Server group to put this sever in" default="" required="true">
+ <c:option-source target="resource" expression="type=ServerGroup"/>
+ </c:simple-property>
<c:simple-property name="auto-start" displayName="Autostart" description="Should this server start at boot?" type="boolean" default="false" required="true"/>
</parameters>
<results>
@@ -293,7 +295,7 @@
</operation>
<operation name="server:remove" displayName="Delete server" description="Deletes a server on this host.">
<parameters>
- <c:simple-property name="name" description="Name of this new server" required="true"/>
+ <c:simple-property name="name" description="Name of the server to be removed" required="true"/>
</parameters>
<results>
<c:simple-property name="operationResult" description="Outcome of the delete server operation"/>
@@ -366,7 +368,7 @@
</server>
<service name="DomainDeployment"
- class="BaseComponent"
+ class="DomainDeploymentComponent"
discovery="SubsystemDiscovery"
createDeletePolicy="both"
creationDataType="content">
@@ -2125,11 +2127,10 @@ working area for individual server instances</li></ul>"/>
createDeletePolicy="both"
creationDataType="content">
-
<runs-inside>
- <parent-resource-type name="ServerGroup" plugin="jboss-as-7"/>
+ <parent-resource-type name="ServerGroup" plugin="jboss-as-7"/> <!-- TODO -->
<parent-resource-type name="JBossAS7 Standalone Server" plugin="jboss-as-7"/>
- <parent-resource-type name="Managed Server" plugin="jboss-as-7"/>
+ <parent-resource-type name="Managed Server" plugin="jboss-as-7"/> <!-- TODO -->
</runs-inside>
<plugin-configuration>
<c:simple-property name="path" default="deployment" readOnly="true"/>
commit d8bd66821bfa11f77ce7c539d9fa90a7c9daf102
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Fri Jan 27 10:02:49 2012 -0500
[BZ 784124] forgot to fix this test
diff --git a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
index 0240f72..bd2d35d 100644
--- a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
+++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java
@@ -108,12 +108,13 @@ public class AntLauncherTest {
public void testInstall() throws Exception {
- if (skipNonRHLinux("testInstall")) return;
+ if (skipNonRHLinux("testInstall"))
+ return;
// We want to test a fresh install, so make sure the deploy dir doesn't pre-exist.
FileUtil.purge(DEPLOY_DIR, true);
- // but we do want to add an unrelated file to see that it remains untouched - the install just "goes around" it
+ // but we do want to add an unrelated file to see that it goes away - since we have manageRootDir=true
File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
AntLauncher ant = new AntLauncher();
@@ -157,7 +158,7 @@ public class AntLauncherTest {
assert new File(DEPLOY_DIR, "subdir/test.properties").exists() : "missing file";
assert new File(DEPLOY_DIR, "archived-bundle-file.txt").exists() : "missing archived bundle file";
assert new File(DEPLOY_DIR, "archived-subdir/archived-file-in-subdir.properties").exists() : "missing subdir archive file";
- assert unrelatedFile.exists() : "unrelated file was removed during the install";
+ assert !unrelatedFile.exists() : "unrelated file was not removed during the install";
assert readPropsFile(new File(DEPLOY_DIR, "subdir/test.properties")).getProperty("junk.listener.port").equals(
"10000");
assert readPropsFile(new File(DEPLOY_DIR, "archived-subdir/archived-file-in-subdir.properties")).getProperty(
@@ -165,7 +166,7 @@ public class AntLauncherTest {
}
private boolean skipNonRHLinux(String meth) {
- if (!System.getProperty("os.name").equals("Linux") || !REDHAT_RELEASE_FILE.exists()) {
+ if (!System.getProperty("os.name").equals("Linux") || !REDHAT_RELEASE_FILE.exists()) {
System.out.println("Skipping " + meth + "() as this only works on Red Hat Linux flavors");
return true;
}
@@ -175,10 +176,10 @@ public class AntLauncherTest {
@Test(dependsOnMethods = "testInstall")
public void testUpgrade() throws Exception {
- if (skipNonRHLinux("testUpgrade")) return;
+ if (skipNonRHLinux("testUpgrade"))
+ return;
- // We want to test an upgrade, so do *not* wipe out the deploy dir - our test method @dependsOnMethods testInstall
- // but we do want to add an unrelated file to see that it gets deleted as part of the upgrade
+ // add an unrelated file to see that it gets deleted as part of the upgrade
File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
AntLauncher ant = new AntLauncher();
@@ -231,14 +232,15 @@ public class AntLauncherTest {
public void testUpgradeNoManageRootDir() throws Exception {
- if (skipNonRHLinux("testInstall")) return;
+ if (skipNonRHLinux("testInstall"))
+ return;
// We want to test an upgrade, so do *not* wipe out the deploy dir - let's re-invoke testInstall
// to get us to an initial state of the v1 bundle installed
testInstall();
// we still want the unrelated file - we want to see that manageRootDir=false works (unrelated files should not be deleted)
- File unrelatedFile = new File(DEPLOY_DIR, "unrelated-file.txt");
+ File unrelatedFile = writeFile("unrelated content", DEPLOY_DIR, "unrelated-file.txt");
assert unrelatedFile.exists() : "our initial install test method should have prepared an unmanaged file";
AntLauncher ant = new AntLauncher();
commit 42b9f09016e6cb0bff55901869b8f5e12dad73d6
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Thu Jan 26 17:37:21 2012 -0500
BZ[784873] fixing issue displaying LDAP registration screen with clean browser cache.
i)Can't count on CoreGUI to be loaded in this case as the user may not have logged in before.
ii)Some refactoring to embed asynchronous call.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
index 74d11e3..50c87a4 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LoginView.java
@@ -103,6 +103,7 @@ public class LoginView extends LocatableCanvas {
private static final String DEPARTMENT = "department";
private static final String SESSIONID = "ldap.sessionid";
static final String PASSWORD = "ldap.password";
+ private ProductInfo productInfo;
public void showLoginDialog(String message) {
showLoginDialog();
@@ -206,195 +207,232 @@ public class LoginView extends LocatableCanvas {
if (!loginShowing) {
loginShowing = true;
- ProductInfo productInfo = CoreGUI.get().getProductInfo();
-
- int fieldWidth = 120;
-
- LocatableVLayout column = new LocatableVLayout(extendLocatorId("NewLdapRegistration"));
- column.setMargin(25);
- HeaderItem header = new HeaderItem();
- header.setValue(MSG.view_login_welcomeMsg(productInfo.getName()));
- header.setWidth("100%");
- //build ui elements for registration screen
- first = new TextItem(FIRST, MSG.dataSource_users_field_firstName());
- {
- first.setRequired(true);
- first.setWrapTitle(false);
- first.setWidth(fieldWidth);
- }
- last = new TextItem(LAST, MSG.dataSource_users_field_lastName());
- {
- last.setWrapTitle(false);
- last.setWidth(fieldWidth);
- last.setRequired(true);
- }
- final TextItem username = new TextItem(USERNAME, MSG.dataSource_users_field_name());
- {
- username.setValue(user);
- username.setDisabled(true);
- username.setWidth(fieldWidth);
- }
- email = new TextItem(EMAIL, MSG.dataSource_users_field_emailAddress());
- email.setRequired(true);
- email.setWidth(fieldWidth);
- email.setWrapTitle(false);
- phone = new TextItem(PHONE, MSG.dataSource_users_field_phoneNumber());
- phone.setWidth(fieldWidth);
- phone.setWrapTitle(false);
- department = new TextItem(DEPARTMENT, MSG.dataSource_users_field_department());
- department.setWidth(fieldWidth);
- SpacerItem space = new SpacerItem();
- space.setColSpan(1);
-
- inputForm = new LocatableDynamicForm(extendLocatorId("LdapUserRegistrationInput"));
- inputForm.setAutoFocus(true);
- inputForm.setErrorOrientation(FormErrorOrientation.LEFT);
- inputForm.setNumCols(4);
- //moving header to it's own container for proper display. Didn't display right in production mode
- inputForm.setFields(username, first, last, email, phone, department);
- loadValidators(inputForm);
- inputForm.setValidateOnExit(true);
- DynamicForm headerWrapper = new DynamicForm();
- headerWrapper.setFields(header);
- column.addMember(headerWrapper);
- column.addMember(inputForm);
-
- HTMLFlow hr = new HTMLFlow("<br/><hr/><br/><br/>");
- hr.setWidth(620);
- hr.setAlign(Alignment.CENTER);
- column.addMember(hr);
-
- HStack row = new HStack();
- row.setMembersMargin(5);
- row.setAlign(VerticalAlignment.CENTER);
- IButton okButton = new LocatableIButton(inputForm.extendLocatorId("OK"), MSG.common_button_ok());
- okButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
-
- //F5 refresh check? If they've reloaded the form for some reason then bail.
- boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
- .trim().isEmpty()));
- //check for session timeout
- if (UserSessionManager.isLoggedOut() || (credentialsEmpty)) {
- resetLogin(LoginView.this.extendLocatorId("Register"));
- return;
+ //BZ:784873. To fix issue with users logging in by LDAP integration with clean browser cache.
+ if (CoreGUI.get().getProductInfo() == null) {
+ //We need to explicitly retrieve product info here as can't count on CoreGui to load it
+ //during LDAP registration. After registration CoreGui is loaded as usual.
+ GWTServiceLookup.getSystemService().getProductInfo(new AsyncCallback<ProductInfo>() {
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_aboutBox_failedToLoad(), caught);
+ productInfo = null;
+ Log.trace("ProductInfo could not be retrieved for some reason. Proceeding anyway.");
+ buildRegistrationWindow(user, sessionId, password, callback);
}
- //validation
- if (inputForm.validate()) {
- Log.trace("Successfully validated all data for user registration.");
- //populate form
- if (first.getValue() != null)
- inputForm.setValue(FIRST, String.valueOf(first.getValue()));
- if (last.getValue() != null)
- inputForm.setValue(LAST, String.valueOf(last.getValue()));
- inputForm.setValue(USERNAME, String.valueOf(username.getValue()));
- if (email.getValue() != null)
- inputForm.setValue(EMAIL, String.valueOf(email.getValue()));
- if (phone.getValue() != null)
- inputForm.setValue(PHONE, String.valueOf(phone.getValue()));
- if (department.getValue() != null)
- inputForm.setValue(DEPARTMENT, String.valueOf(department.getValue()));
- inputForm.setValue(SESSIONID, sessionId);
- inputForm.setValue(PASSWORD, password);
- registerLdapUser(LoginView.this.extendLocatorId("RegisterLdap"), inputForm, callback);
+ public void onSuccess(ProductInfo result) {
+ productInfo = result;
+ Log.trace("ProductInfo has been retrieved for LDAP registration.");
+ buildRegistrationWindow(user, sessionId, password, callback);
}
- }
+ });
+ } else {//if productInfo has already been loaded, save a gwt call.
+ productInfo = CoreGUI.get().getProductInfo();
+ buildRegistrationWindow(user, sessionId, password, callback);
+ }
+ }
+ }
- });
- row.addMember(okButton);
- //send request to LDAP server to grab user details for this user. Already sure ldap user exists
- GWTServiceLookup.getLdapService().getLdapDetailsFor(user, new AsyncCallback<Map<String, String>>() {
- public void onSuccess(final Map<String, String> ldapUserDetails) {
- //now prepopulate UI fields if they exist
- for (String key : ldapUserDetails.keySet()) {
- String value;
- if (key.equalsIgnoreCase("givenName")) {//aka first name
- value = ldapUserDetails.get(key);
- first.setValue(value);
- } else if (key.equalsIgnoreCase("sn")) {//aka Surname
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- last.setValue(value);
- }
- } else if (key.equalsIgnoreCase("telephoneNumber")) {
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- phone.setValue(value);
- }
- } else if (key.equalsIgnoreCase("mail")) {
- value = ldapUserDetails.get(key);
- if ((value != null) && (!value.isEmpty())) {
- email.setValue(value);
- }
- }
- }
+ /** Duplicate modal Login mechanism to now show last registration screen before launching
+ * core gui.
+ *
+ * @param user prepopulate username field for LDAP registration
+ * @param sessionId pass in valid session id for LDAP registration steps.
+ * @param callback pass in callback reference to indicate success and launch of coreGUI
+ */
+ private void buildRegistrationWindow(final String user, final String sessionId, final String password,
+ final AsyncCallback<Subject> callback) {
+ int fieldWidth = 120;
+
+ //Build registration window.
+ LocatableVLayout column = new LocatableVLayout(extendLocatorId("NewLdapRegistration"));
+ column.setMargin(25);
+ HeaderItem header = new HeaderItem();
+ //Locate product info for registration screen.
+ if (productInfo != null) {
+ header.setValue(MSG.view_login_welcomeMsg(productInfo.getName()));
+ } else {//if not available, let registration continue. Errors already logged and no functionality lost.
+ header.setValue(MSG.view_login_welcomeMsg(""));
+ }
+ header.setWidth("100%");
+ //build ui elements for registration screen
+ first = new TextItem(FIRST, MSG.dataSource_users_field_firstName());
+ {
+ first.setRequired(true);
+ first.setWrapTitle(false);
+ first.setWidth(fieldWidth);
+ }
+ last = new TextItem(LAST, MSG.dataSource_users_field_lastName());
+ {
+ last.setWrapTitle(false);
+ last.setWidth(fieldWidth);
+ last.setRequired(true);
+ }
+ final TextItem username = new TextItem(USERNAME, MSG.dataSource_users_field_name());
+ {
+ username.setValue(user);
+ username.setDisabled(true);
+ username.setWidth(fieldWidth);
+ }
+ email = new TextItem(EMAIL, MSG.dataSource_users_field_emailAddress());
+ email.setRequired(true);
+ email.setWidth(fieldWidth);
+ email.setWrapTitle(false);
+ phone = new TextItem(PHONE, MSG.dataSource_users_field_phoneNumber());
+ phone.setWidth(fieldWidth);
+ phone.setWrapTitle(false);
+ department = new TextItem(DEPARTMENT, MSG.dataSource_users_field_department());
+ department.setWidth(fieldWidth);
+ SpacerItem space = new SpacerItem();
+ space.setColSpan(1);
+
+ inputForm = new LocatableDynamicForm(extendLocatorId("LdapUserRegistrationInput"));
+ inputForm.setAutoFocus(true);
+ inputForm.setErrorOrientation(FormErrorOrientation.LEFT);
+ inputForm.setNumCols(4);
+ //moving header to it's own container for proper display. Didn't display right in production mode
+ inputForm.setFields(username, first, last, email, phone, department);
+ loadValidators(inputForm);
+ inputForm.setValidateOnExit(true);
+ DynamicForm headerWrapper = new DynamicForm();
+ headerWrapper.setFields(header);
+ column.addMember(headerWrapper);
+ column.addMember(inputForm);
+
+ HTMLFlow hr = new HTMLFlow("<br/><hr/><br/><br/>");
+ hr.setWidth(620);
+ hr.setAlign(Alignment.CENTER);
+ column.addMember(hr);
+
+ HStack row = new HStack();
+ row.setMembersMargin(5);
+ row.setAlign(VerticalAlignment.CENTER);
+ IButton okButton = new LocatableIButton(inputForm.extendLocatorId("OK"), MSG.common_button_ok());
+ okButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+
+ //F5 refresh check? If they've reloaded the form for some reason then bail.
+ boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
+ .trim().isEmpty()));
+ //check for session timeout
+ if (UserSessionManager.isLoggedOut() || (credentialsEmpty)) {
+ resetLogin(LoginView.this.extendLocatorId("Register"));
+ return;
}
- public void onFailure(Throwable caught) {
- inputForm.setFieldErrors(FIRST, MSG.view_login_noLdap(), true);
- Log.debug("Optional LDAP detail retrieval did not succeed. Registration prepopulation will not occur.");
+ //validation
+ if (inputForm.validate()) {
+ Log.trace("Successfully validated all data for user registration.");
+ //populate form
+ if (first.getValue() != null)
+ inputForm.setValue(FIRST, String.valueOf(first.getValue()));
+ if (last.getValue() != null)
+ inputForm.setValue(LAST, String.valueOf(last.getValue()));
+ inputForm.setValue(USERNAME, String.valueOf(username.getValue()));
+ if (email.getValue() != null)
+ inputForm.setValue(EMAIL, String.valueOf(email.getValue()));
+ if (phone.getValue() != null)
+ inputForm.setValue(PHONE, String.valueOf(phone.getValue()));
+ if (department.getValue() != null)
+ inputForm.setValue(DEPARTMENT, String.valueOf(department.getValue()));
+ inputForm.setValue(SESSIONID, sessionId);
+ inputForm.setValue(PASSWORD, password);
+ registerLdapUser(LoginView.this.extendLocatorId("RegisterLdap"), inputForm, callback);
}
- });
-
- IButton resetButton = new LocatableIButton(inputForm.extendLocatorId("Reset"), MSG.common_button_reset());
- resetButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- //F5 refresh check? If they've reloaded the form for some reason then bail.
- boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
- .trim().isEmpty()));
- if (UserSessionManager.isLoggedOut() || credentialsEmpty) {
- resetLogin(LoginView.this.extendLocatorId("Reset"));
- return;
- }
+ }
- //clear out all validation messages.
- {
- String empty = " ";
- first.setValue(empty);
- last.setValue(empty);
- email.setValue("test(a)test.com");
- inputForm.validate();
+ });
+ row.addMember(okButton);
+ //send request to LDAP server to grab user details for this user. Already sure ldap user exists
+ GWTServiceLookup.getLdapService().getLdapDetailsFor(user, new AsyncCallback<Map<String, String>>() {
+ public void onSuccess(final Map<String, String> ldapUserDetails) {
+ //now prepopulate UI fields if they exist
+ for (String key : ldapUserDetails.keySet()) {
+ String value;
+ if (key.equalsIgnoreCase("givenName")) {//aka first name
+ value = ldapUserDetails.get(key);
+ first.setValue(value);
+ } else if (key.equalsIgnoreCase("sn")) {//aka Surname
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ last.setValue(value);
+ }
+ } else if (key.equalsIgnoreCase("telephoneNumber")) {
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ phone.setValue(value);
+ }
+ } else if (key.equalsIgnoreCase("mail")) {
+ value = ldapUserDetails.get(key);
+ if ((value != null) && (!value.isEmpty())) {
+ email.setValue(value);
+ }
}
- first.clearValue();
- last.clearValue();
- email.clearValue();
- phone.clearValue();
- department.clearValue();
}
- });
- row.addMember(resetButton);
+ }
- IButton cancelButton = new LocatableIButton(inputForm.extendLocatorId("Cancel"), MSG.common_button_cancel());
- cancelButton.addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- UserSessionManager.logout();
+ public void onFailure(Throwable caught) {
+ inputForm.setFieldErrors(FIRST, MSG.view_login_noLdap(), true);
+ Log.debug("Optional LDAP detail retrieval did not succeed. Registration prepopulation will not occur.");
+ }
+ });
+
+ IButton resetButton = new LocatableIButton(inputForm.extendLocatorId("Reset"), MSG.common_button_reset());
+ resetButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ //F5 refresh check? If they've reloaded the form for some reason then bail.
+ boolean credentialsEmpty = ((user == null) || (user.trim().isEmpty()) || (password == null) || (password
+ .trim().isEmpty()));
+ if (UserSessionManager.isLoggedOut() || credentialsEmpty) {
resetLogin(LoginView.this.extendLocatorId("Reset"));
+ return;
}
- });
- row.addMember(cancelButton);
- Label logoutLabel = new Label(MSG.view_login_registerLater());
- logoutLabel.setWrap(false);
- row.addMember(logoutLabel);
- column.addMember(row);
-
- window = new LocatableWindow(extendLocatorId("RegistrationWindow"));
- window.setWidth(670);
- window.setHeight(330);
- window.setTitle(MSG.view_login_registerUser());
- // forced focused, static size, can't close / dismiss
- window.setIsModal(true);
- window.setShowModalMask(true);
- window.setCanDragResize(false);
- window.setCanDragReposition(false);
- window.setShowCloseButton(false);
- window.setShowMinimizeButton(false);
- window.setAutoCenter(true);
-
- window.addItem(column);
- window.show();
- }
+ //clear out all validation messages.
+ {
+ String empty = " ";
+ first.setValue(empty);
+ last.setValue(empty);
+ email.setValue("test(a)test.com");
+ inputForm.validate();
+ }
+ first.clearValue();
+ last.clearValue();
+ email.clearValue();
+ phone.clearValue();
+ department.clearValue();
+ }
+ });
+ row.addMember(resetButton);
+
+ IButton cancelButton = new LocatableIButton(inputForm.extendLocatorId("Cancel"), MSG.common_button_cancel());
+ cancelButton.addClickHandler(new ClickHandler() {
+ public void onClick(ClickEvent event) {
+ UserSessionManager.logout();
+ resetLogin(LoginView.this.extendLocatorId("Reset"));
+ }
+ });
+ row.addMember(cancelButton);
+ Label logoutLabel = new Label(MSG.view_login_registerLater());
+ logoutLabel.setWrap(false);
+ row.addMember(logoutLabel);
+ column.addMember(row);
+
+ window = new LocatableWindow(extendLocatorId("RegistrationWindow"));
+ window.setWidth(670);
+ window.setHeight(330);
+ window.setTitle(MSG.view_login_registerUser());
+
+ // forced focused, static size, can't close / dismiss
+ window.setIsModal(true);
+ window.setShowModalMask(true);
+ window.setCanDragResize(false);
+ window.setCanDragReposition(false);
+ window.setShowCloseButton(false);
+ window.setShowMinimizeButton(false);
+ window.setAutoCenter(true);
+
+ window.addItem(column);
+ window.show();
}
/** Go through steps of invalidating this login and piping them back to CoreGUI Login.
commit 9946f3e2b2b4b0a86ebe001594818f016a4c4130
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 26 17:19:43 2012 -0500
[BZ 784124] fix the issue where, on initial deployment of a bundle, we didn't clean out any files that happen to be in the deployment dir.
we need to remove them, they are in the way. we do back them up so they can be manually retrieved if the user screwed up.
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
index 14ed3af..a78f6b2 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/file/FileUtil.java
@@ -33,6 +33,7 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
@@ -102,6 +103,77 @@ public class FileUtil {
StreamUtil.copy(is, os);
}
+ public static void copyDirectory(File inDir, File outDir) throws IOException {
+ if (inDir.exists()) {
+ if (!inDir.isDirectory()) {
+ throw new IOException("Source directory [" + inDir + "] is not a directory");
+ }
+ } else {
+ throw new FileNotFoundException("Source directory [" + inDir + "] does not exist");
+ }
+
+ if (!outDir.mkdirs()) {
+ throw new IOException("Destination directory [" + outDir + "] failed to be created");
+ }
+
+ if (!canWrite(outDir)) {
+ throw new IOException("Cannot write to destination directory [" + outDir + "]");
+ }
+
+ // TODO do we care to restore the last mod time on the destination dir?
+ //outDir.setLastModified(inDir.lastModified());
+
+ File[] files = inDir.listFiles();
+ if (files == null) {
+ throw new IOException("Failed to get the list of files in source directory [" + inDir + "]");
+ }
+ for (File file : files) {
+ File copiedFile = new File(outDir, file.getName());
+ if (file.isDirectory()) {
+ copyDirectory(file, copiedFile);
+ } else {
+ copyFile(file, copiedFile);
+ }
+ }
+
+ files = null; // help GC
+ return;
+ }
+
+ /**
+ * Obtains the list of all files in the given directory and, recursively, all its subdirectories.
+ * Note that the returns list is only regular files - directory names are NOT in the list. Also,
+ * the names in the list are relative to the given directory.
+ * @param directory the directory whose files are to be returned
+ * @return list of files in the directory, not sorted in any particular order
+ * @throws IOException if directory does not exist or is not a directory
+ */
+ public static List<File> getDirectoryFiles(File directory) throws IOException {
+ ArrayList<File> files = new ArrayList<File>();
+ if (!directory.isDirectory()) {
+ throw new IOException("[" + directory + "] is not an existing directory");
+ }
+ getDirectoryFilesRecursive(directory, files, null);
+ return files;
+ }
+
+ private static void getDirectoryFilesRecursive(File directory, List<File> files, String relativeTo)
+ throws IOException {
+ File[] children = directory.listFiles();
+ if (children == null) {
+ throw new IOException("Cannot obtain files from directory [" + directory + "]");
+ }
+ for (File child : children) {
+ if (child.isDirectory()) {
+ getDirectoryFilesRecursive(child, files, ((relativeTo == null) ? "" : relativeTo) + child.getName()
+ + File.separatorChar);
+ } else {
+ files.add(new File(relativeTo, child.getName()));
+ }
+ }
+ return;
+ }
+
/**
* Copy a stream, using a buffer.
* @deprecated use {@link StreamUtil} for more methods like this - those are unit tested and used more
diff --git a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
index 652bcda..40ce727 100644
--- a/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
+++ b/modules/core/util/src/main/java/org/rhq/core/util/updater/Deployer.java
@@ -28,6 +28,8 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -301,9 +303,9 @@ public class Deployer {
return;
}
- debug("Estimated disk usage for this deployment is [", usage.getDiskUsage(), "] bytes (file count=[", usage
- .getFileCount(), "]). The maximum disk space currently usable is estimated to be [", usage
- .getMaxDiskUsable(), "] bytes.");
+ debug("Estimated disk usage for this deployment is [", usage.getDiskUsage(), "] bytes (file count=[",
+ usage.getFileCount(), "]). The maximum disk space currently usable is estimated to be [",
+ usage.getMaxDiskUsable(), "] bytes.");
if (usage.getDiskUsage() > usage.getMaxDiskUsable()) {
throw new Exception(
@@ -316,6 +318,31 @@ public class Deployer {
}
private FileHashcodeMap performInitialDeployment(DeployDifferences diff, boolean dryRun) throws Exception {
+ // If we are to fully manage the deployment dir, then we need to delete everything we find here.
+ // Any old files do not belong here - only our bundle files should live here now.
+ if (this.deploymentData.isManageRootDir()) {
+ File destDir = this.deploymentData.getDestinationDir();
+ log.info(buildLogMessage("Will be managing the deploy dir[", destDir,
+ "]; backing up and purging any obsolete content existing in there"));
+ if (destDir.isDirectory()) {
+ int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId();
+ backupFiles(diff, deploymentId, destDir, dryRun, null, true);
+ if (!dryRun) {
+ // we want to purge everything that is originally in here, but we backed up the files in here
+ // so make sure we don't delete our metadata directory, which is where the backed up files are
+ File[] doomedFiles = destDir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return !DeploymentsMetadata.METADATA_DIR.equals(name);
+ }
+ });
+ for (File doomedFile : doomedFiles) {
+ FileUtil.purge(doomedFile, true);
+ }
+ }
+ }
+ }
+
FileHashcodeMap newFileHashcodeMap = extractZipAndRawFiles(new HashMap<String, String>(0), diff, dryRun);
// this is an initial deployment, so we know every file is new - tell our diff about them all
@@ -340,8 +367,8 @@ public class Deployer {
// * if a current file is backed up
FileHashcodeMap original = this.deploymentsMetadata.getCurrentDeploymentFileHashcodes();
- ChangesFileHashcodeMap current = original.rescan(this.deploymentData.getDestinationDir(), this.deploymentData
- .getIgnoreRegex(), this.deploymentData.isManageRootDir());
+ ChangesFileHashcodeMap current = original.rescan(this.deploymentData.getDestinationDir(),
+ this.deploymentData.getIgnoreRegex(), this.deploymentData.isManageRootDir());
FileHashcodeMap newFiles = getNewDeploymentFileHashcodeMap();
if (current.getUnknownContent() != null) {
@@ -457,7 +484,8 @@ public class Deployer {
int backupDeploymentId = props.getDeploymentId();
debug("Backing up files as part of update deployment. dryRun=", dryRun);
for (String fileToBackupPath : currentFilesToBackup) {
- backupFile(diff, backupDeploymentId, fileToBackupPath, dryRun);
+ boolean toBeDeleted = currentFilesToDelete.remove(fileToBackupPath);
+ backupFile(diff, backupDeploymentId, fileToBackupPath, dryRun, toBeDeleted);
}
}
@@ -503,8 +531,8 @@ public class Deployer {
return newFileHashCodeMap;
}
- private void backupFile(DeployDifferences diff, int deploymentId, final String fileToBackupPath, boolean dryRun)
- throws Exception {
+ private void backupFile(DeployDifferences diff, int deploymentId, final String fileToBackupPath, boolean dryRun,
+ boolean removeFileToBackup) throws Exception {
File bakFile;
@@ -536,8 +564,8 @@ public class Deployer {
String destDirDriveLetter = FileUtil.stripDriveLetter(destDirAbsPathBuilder);
if (destDirDriveLetter == null || driveLetter.equals(destDirDriveLetter)) {
bakFile = new File(backupDir, fileToBackupPath);
- fileToBackup = new File(this.deploymentData.getDestinationDir(), fileToBackupPathNoDriveLetter
- .toString());
+ fileToBackup = new File(this.deploymentData.getDestinationDir(),
+ fileToBackupPathNoDriveLetter.toString());
} else {
throw new Exception("Cannot backup relative path [" + fileToBackupPath
+ "] whose drive letter is different than the destination directory ["
@@ -549,20 +577,77 @@ public class Deployer {
}
}
+ boolean deleted = false; // will be true if we were told to delete the file and we actually did delete it
+
if (!dryRun) {
bakFile.getParentFile().mkdirs();
- FileUtil.copyFile(fileToBackup, bakFile);
+ // try to do a rename first if we are to remove the file, since this is more likely
+ // much faster and more efficient.
+ // if it fails (perhaps because we are crossing file systems), try a true copy
+ if (removeFileToBackup) {
+ boolean movedSuccessfully = fileToBackup.renameTo(bakFile);
+ if (movedSuccessfully) {
+ deleted = true;
+ } else {
+ FileUtil.copyFile(fileToBackup, bakFile);
+ deleted = fileToBackup.delete();
+ if (deleted == false) {
+ // TODO: what should we do? is it a major failure if we can't remove files here?
+ debug("Failed to delete file [", fileToBackup, "] but it is backed up");
+ if (diff != null) {
+ diff.addError(fileToBackupPath, "File [" + fileToBackup.getAbsolutePath()
+ + "] did not delete");
+ }
+ }
+ }
+ } else {
+ FileUtil.copyFile(fileToBackup, bakFile);
+ }
+ } else {
+ deleted = removeFileToBackup; // this is a dry run, pretend we deleted it if we were asked to
}
debug("Backed up file [", fileToBackup, "] to [", bakFile, "]. dryRun=", dryRun);
+ if (deleted) {
+ debug("Deleted file [", fileToBackup, "] after backing it up. dryRun=", dryRun);
+ }
if (diff != null) {
diff.addBackedUpFile(fileToBackupPath, bakFile.getAbsolutePath());
+ if (deleted) {
+ diff.addDeletedFile(fileToBackupPath);
+ }
}
return;
}
+ private void backupFiles(DeployDifferences diff, int deploymentId, File dirToBackup, boolean dryRun,
+ String relativeTo, boolean removeSourceFiles) throws Exception {
+ File[] files = dirToBackup.listFiles();
+ if (files == null) {
+ throw new IOException("Failed to get the list of files in source directory [" + dirToBackup + "]");
+ }
+ if (files.length > 0) {
+ this.deploymentsMetadata.getMetadataDirectory().mkdirs(); // make sure we create this, might not be there yet
+ for (File file : files) {
+ if (file.isDirectory()) {
+ if (file.getName().equals(DeploymentsMetadata.METADATA_DIR)) {
+ continue; // skip the RHQ metadata directory, its where we are putting our backups!
+ }
+ backupFiles(diff, deploymentId, file, dryRun,
+ ((relativeTo == null) ? "" : relativeTo) + file.getName() + File.separatorChar,
+ removeSourceFiles);
+ } else {
+ backupFile(diff, deploymentId, ((relativeTo == null) ? "" : relativeTo) + file.getName(), dryRun,
+ removeSourceFiles);
+ }
+ }
+
+ files = null; // help GC
+ }
+ }
+
private FileHashcodeMap extractZipAndRawFiles(Map<String, String> currentFilesToLeaveAlone, DeployDifferences diff,
boolean dryRun) throws Exception {
@@ -615,8 +700,8 @@ public class Deployer {
ZipUtil.walkZipFile(zipFile, visitor);
// we have to compress the file again - our new compressed file will have the new realized files in them
if (!dryRun) {
- createZipFile(compressedFile, this.deploymentData.getDestinationDir(), visitor
- .getFileHashcodeMap());
+ createZipFile(compressedFile, this.deploymentData.getDestinationDir(),
+ visitor.getFileHashcodeMap());
}
}
@@ -1040,16 +1125,20 @@ public class Deployer {
private void debug(Object... objs) {
if (log.isDebugEnabled()) {
- String bundleName = this.deploymentData.getDeploymentProps().getBundleName();
- String bundleVersion = this.deploymentData.getDeploymentProps().getBundleVersion();
- int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId();
- StringBuilder str = new StringBuilder();
- str.append("Bundle [").append(bundleName).append(" v").append(bundleVersion).append(']');
- str.append("; Deployment [").append(deploymentId).append("]: ");
- for (Object o : objs) {
- str.append(o);
- }
- log.debug(str.toString());
+ log.debug(buildLogMessage(objs));
+ }
+ }
+
+ private String buildLogMessage(Object... objs) {
+ String bundleName = this.deploymentData.getDeploymentProps().getBundleName();
+ String bundleVersion = this.deploymentData.getDeploymentProps().getBundleVersion();
+ int deploymentId = this.deploymentData.getDeploymentProps().getDeploymentId();
+ StringBuilder str = new StringBuilder();
+ str.append("Bundle [").append(bundleName).append(" v").append(bundleVersion).append(']');
+ str.append("; Deployment [").append(deploymentId).append("]: ");
+ for (Object o : objs) {
+ str.append(o);
}
+ return str.toString();
}
}
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
index 31659bd..bb7ad34 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/file/FileUtilTest.java
@@ -22,21 +22,92 @@
*/
package org.rhq.core.util.file;
+import static java.util.Arrays.asList;
+import static org.apache.commons.io.FileUtils.deleteDirectory;
+import static org.apache.commons.io.FileUtils.toFile;
+import static org.apache.commons.io.FileUtils.touch;
+import static org.rhq.test.AssertUtils.assertCollectionEqualsNoOrder;
+
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.testng.annotations.Test;
-import static java.util.Arrays.asList;
-import static org.apache.commons.io.FileUtils.deleteDirectory;
-import static org.apache.commons.io.FileUtils.toFile;
-import static org.apache.commons.io.FileUtils.touch;
-import static org.rhq.test.AssertUtils.assertCollectionEqualsNoOrder;
+import org.rhq.core.util.stream.StreamUtil;
@Test
public class FileUtilTest {
+ public void testCopyDirectory() throws Exception {
+ try {
+ FileUtil.copyDirectory(new File("this.does.not.exist"), new File("dummy"));
+ assert false : "the source directory did not exist, this should have failed because of that";
+ } catch (Exception ok) {
+ }
+
+ // create a source directory and a destination directory. Make sure we start off
+ // with a non-existent destination directory - we want the copyDirectory to create it for us.
+ File outDir = FileUtil.createTempDirectory("fileUtilTestCopyDir", ".dest", null);
+ assert outDir.delete() : "failed to start out with a non-existent dest directory";
+ assert !outDir.exists() : "dest directory should not exist"; // yes, I am paranoid
+
+ File inDir = FileUtil.createTempDirectory("fileUtilTestCopyDir", ".src", null);
+ try {
+ // create some test files in our source directory
+ String testFilename0 = "file0.txt";
+ String testFilename1 = "subdir" + File.separatorChar + "subfile1.txt";
+ String testFilename2 = "subdir" + File.separatorChar + "subfile2.txt";
+
+ File testFile = new File(inDir, testFilename0);
+ StreamUtil.copy(new ByteArrayInputStream("0".getBytes()), new FileOutputStream(testFile));
+ assert "0".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there
+
+ testFile = new File(inDir, testFilename1);
+ testFile.getParentFile().mkdirs();
+ StreamUtil.copy(new ByteArrayInputStream("1".getBytes()), new FileOutputStream(testFile));
+ assert "1".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there
+ testFile = new File(inDir, testFilename2);
+ testFile.getParentFile().mkdirs();
+ StreamUtil.copy(new ByteArrayInputStream("2".getBytes()), new FileOutputStream(testFile));
+ assert "2".equals(new String(StreamUtil.slurp(new FileInputStream(testFile)))); // sanity check, make sure its there
+
+ // copy our source directory and confirm the copies are correct
+ FileUtil.copyDirectory(inDir, outDir);
+
+ testFile = new File(outDir, testFilename0);
+ assert testFile.exists() : "file did not get created: " + testFile;
+ assert "0".equals(new String(StreamUtil.slurp(new FileInputStream(testFile))));
+ testFile = new File(outDir, testFilename1);
+ assert testFile.exists() : "file did not get created: " + testFile;
+ assert "1".equals(new String(StreamUtil.slurp(new FileInputStream(testFile))));
+ testFile = new File(outDir, testFilename2);
+ assert testFile.exists() : "file did not get created: " + testFile;
+ assert "2".equals(new String(StreamUtil.slurp(new FileInputStream(testFile))));
+
+ // let's test getDirectoryFiles while we are here
+ List<File> outFiles = FileUtil.getDirectoryFiles(outDir);
+ assert outFiles != null : outFiles;
+ assert outFiles.size() == 3 : outFiles;
+ assert outFiles.contains(new File(testFilename0)) : outFiles;
+ assert outFiles.contains(new File(testFilename1)) : outFiles;
+ assert outFiles.contains(new File(testFilename2)) : outFiles;
+ } finally {
+ // clean up our test
+ try {
+ FileUtil.purge(inDir, true);
+ } catch (Exception ignore) {
+ }
+ try {
+ FileUtil.purge(outDir, true);
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
public void testStripDriveLetter() {
StringBuilder str;
@@ -142,8 +213,7 @@ public class FileUtilTest {
}
});
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles,
- "Expected to visit all files in directory");
+ assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit all files in directory");
}
@Test
@@ -176,8 +246,7 @@ public class FileUtilTest {
}
});
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles,
- "Expected to visit files in sub directories");
+ assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit files in sub directories");
}
@Test
@@ -210,8 +279,7 @@ public class FileUtilTest {
}
});
- assertCollectionEqualsNoOrder(expectedFiles, actualFiles,
- "Expected to visit files in nested sub directories");
+ assertCollectionEqualsNoOrder(expectedFiles, actualFiles, "Expected to visit files in nested sub directories");
}
public void testGetPattern() {
@@ -222,8 +290,8 @@ public class FileUtilTest {
assert regex.matcher("/basedir/test1.txt").matches();
assert !regex.matcher("/basedir/test2.txt").matches();
- regex = assertPatternsRegex("(/basedir/easy\\.txt)|(/basedir/test\\.txt)",
- new PathFilter("/basedir/easy.txt", null), new PathFilter("/basedir/test.txt", null));
+ regex = assertPatternsRegex("(/basedir/easy\\.txt)|(/basedir/test\\.txt)", new PathFilter("/basedir/easy.txt",
+ null), new PathFilter("/basedir/test.txt", null));
assert regex.matcher("/basedir/easy.txt").matches();
assert regex.matcher("/basedir/test.txt").matches();
@@ -244,8 +312,8 @@ public class FileUtilTest {
assert !regex.matcher("/basedir/subdir/foo.txt").matches();
assert !regex.matcher("/basedir/foo.txt.swp").matches();
- regex = assertPatternsRegex("(/var/lib/([^/]*\\.war))|(/var/lib/([^/]*\\.ear))",
- new PathFilter("/var/lib", "*.war"), new PathFilter("/var/lib", "*.ear"));
+ regex = assertPatternsRegex("(/var/lib/([^/]*\\.war))|(/var/lib/([^/]*\\.ear))", new PathFilter("/var/lib",
+ "*.war"), new PathFilter("/var/lib", "*.ear"));
assert regex.matcher("/var/lib/myapp.war").matches();
assert regex.matcher("/var/lib/myapp.ear").matches();
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java
index 69d6d53..a69931a 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/DeployerTest.java
@@ -230,12 +230,13 @@ public class DeployerTest {
final String file999 = "dir1" + fileSeparator + "file999";
try {
- if (ignore) {
- // create a file that will be retained because we will be ignoring it
- File ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir);
- fileToIgnore = new File(ignoreDir, "some-log.log");
- StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore));
- }
+ // this is a file that will be removed because our initial deployment is managing the root deploy dir
+ // later we will recreate it to see that we ignore it during the upgrade.
+ // note that during the initial deployment, we will still back it up.
+ File ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir);
+ fileToIgnore = new File(ignoreDir, "some-log.log");
+ StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore));
+ String fileToIgnorePath = ignoreDir.getName() + "/" + fileToIgnore.getName(); // yes, use /, even if we are on windows
File testZipFile1 = new File("target/test-classes/updater-test1.zip");
File testZipFile2 = new File("target/test-classes/updater-test2.zip");
@@ -267,15 +268,25 @@ public class DeployerTest {
deployer.deploy(diff);
- if (ignore) {
- assert "boo".equals(new String(StreamUtil.slurp(new FileInputStream(fileToIgnore))));
- assert diff.getIgnoredFiles().size() == 0 : "this was an initial deploy - nothing to ignore (ignore is only for updates)";
- }
+ // our initial deploy should have deleted this because we are managing the root dir
+ assert !fileToIgnore.exists() : "should have removed this file since we are managing the root dir";
+ assert !fileToIgnore.getParentFile().exists() : "should have removed this file since we are managing the root dir";
+ assert diff.getIgnoredFiles().size() == 0 : "this was an initial deploy - nothing to ignore (ignore is only for updates)";
assert diff.getAddedFiles().size() == 6 : diff;
- assert diff.getDeletedFiles().size() == 0 : diff;
+ assert diff.getDeletedFiles().size() == 1 : diff;
+ assert diff.getDeletedFiles().contains(fileToIgnorePath) : "should have deleted this unknown file" + diff;
assert diff.getChangedFiles().size() == 0 : diff;
assert diff.getRealizedFiles().size() == 0 : "No fileA to realize in this deployment: " + diff;
- assert diff.getBackedUpFiles().size() == 0 : "No fileA to realize in this deployment: " + diff;
+ assert diff.getBackedUpFiles().size() == 1 : diff;
+ assert diff.getBackedUpFiles().get(fileToIgnorePath) != null : "should have backed up this file" + diff;
+
+ if (ignore) {
+ // let's create this again to make sure we really do ignore it
+ ignoreDir = FileUtil.createTempDirectory("ignoreme", ".dir", tmpDir);
+ fileToIgnore = new File(ignoreDir, "some-log.log");
+ StreamUtil.copy(new ByteArrayInputStream("boo".getBytes()), new FileOutputStream(fileToIgnore));
+ fileToIgnorePath = ignoreDir.getName() + "/" + fileToIgnore.getName(); // yes, use /, even if we are on windows
+ }
StreamUtil.copy(new ByteArrayInputStream("X".getBytes()), new FileOutputStream(new File(tmpDir, file1)));
StreamUtil.copy(new ByteArrayInputStream("X".getBytes()), new FileOutputStream(updaterAabsolute));
@@ -295,7 +306,7 @@ public class DeployerTest {
templateEngine, ignoreRegex, true, null);
deployer = new Deployer(dd);
diff = new DeployDifferences();
- deployer.deploy(diff);
+ deployer.deploy(diff); // this is an upgrade
if (ignore) {
assert "boo".equals(new String(StreamUtil.slurp(new FileInputStream(fileToIgnore))));
@@ -396,11 +407,11 @@ public class DeployerTest {
assert diff.getChangedFiles().contains(fileB) : diff;
assert diff.getBackedUpFiles().size() == 4 : diff;
assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterAabsolute.getAbsolutePath())) : diff;
- assert diff.getBackedUpFiles().get(diff.convertPath(updaterAabsolute.getAbsolutePath())).equals(
- diff.convertPath(updaterAabsoluteBackupTo2)) : diff;
+ assert diff.getBackedUpFiles().get(diff.convertPath(updaterAabsolute.getAbsolutePath()))
+ .equals(diff.convertPath(updaterAabsoluteBackupTo2)) : diff;
assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff;
- assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())).equals(
- diff.convertPath(updaterBabsoluteBackupTo2)) : diff;
+ assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath()))
+ .equals(diff.convertPath(updaterBabsoluteBackupTo2)) : diff;
assert diff.getBackedUpFiles().containsKey(fileB) : diff;
assert diff.getBackedUpFiles().get(fileB).equals(diff.convertPath(fileBbackupTo2.getAbsolutePath())) : diff;
assert diff.getBackedUpFiles().containsKey(file999) : diff;
@@ -442,8 +453,8 @@ public class DeployerTest {
assert diff.getChangedFiles().contains(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff;
assert diff.getBackedUpFiles().size() == 1 : diff;
assert diff.getBackedUpFiles().containsKey(diff.convertPath(updaterBabsolute.getAbsolutePath())) : diff;
- assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath())).equals(
- diff.convertPath(updaterBabsoluteBackupTo3)) : diff;
+ assert diff.getBackedUpFiles().get(diff.convertPath(updaterBabsolute.getAbsolutePath()))
+ .equals(diff.convertPath(updaterBabsoluteBackupTo3)) : diff;
if (realize) {
assert diff.getRealizedFiles().size() == 1 : diff;
assert diff.getRealizedFiles().containsKey(fileA) : diff;
diff --git a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
index f875576..2736f16 100644
--- a/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
+++ b/modules/core/util/src/test/java/org/rhq/core/util/updater/SimpleDeployerTest.java
@@ -205,7 +205,15 @@ public class SimpleDeployerTest {
baseNoNewWithCurrentDifferentThanOriginal(true);
}
- public void testWithSubdirectories() throws Exception {
+ public void testWithSubdirectoriesManageRootDir() throws Exception {
+ testWithSubdirectories(true);
+ }
+
+ public void testWithSubdirectoriesNoManageRootDir() throws Exception {
+ testWithSubdirectories(false);
+ }
+
+ private void testWithSubdirectories(boolean manageRootDir) throws Exception {
// this test is different than all the rest, start with clean tmp/dest dirs with no beforeMethod buildup
FileUtil.purge(this.tmpDir, false);
FileUtil.purge(this.deployDir, false);
@@ -227,14 +235,40 @@ public class SimpleDeployerTest {
this.originalZipFiles.add(originalZipFile);
this.originalDeployProps = new DeploymentProperties(1, "simple", "1.0", "original test deployment");
DeploymentData dd = new DeploymentData(originalDeployProps, originalZipFiles, null, tmpDir, deployDir, null,
- null, null, null, true, null);
+ null, null, null, manageRootDir, null);
+ this.diff = new DeployDifferences();
Deployer deployer = new Deployer(dd);
- this.originalFileHashcodeMap = deployer.deploy(null);
+ this.originalFileHashcodeMap = deployer.deploy(this.diff);
assert new File(this.deployDir, origFileName1).exists();
assert new File(this.deployDir, origFileName2).exists();
- assert unrelated1.exists() : "the deployment removed unrelated file1";
- assert unrelated2.getParentFile().isDirectory() : "the deployment removed an unrelated dir";
- assert unrelated2.exists() : "the deployment removed unrelated file2";
+ if (manageRootDir) {
+ assert !unrelated1.exists() : "the deployment should have removed unrelated file1";
+ assert !unrelated2.getParentFile().isDirectory() : "the deployment should have removed an unrelated dir";
+ assert !unrelated2.exists() : "the deployment should have removed unrelated file2";
+
+ assert this.diff.getBackedUpFiles().size() == 2 : this.diff;
+ assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName1)).exists() : this.diff;
+ assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName2)).exists() : this.diff;
+ assert this.diff.getDeletedFiles().size() == 2 : this.diff;
+ assert this.diff.getDeletedFiles().contains(unrelatedFileName1) : this.diff;
+ assert this.diff.getDeletedFiles().contains(unrelatedFileName2) : this.diff;
+ } else {
+ assert this.diff.getBackedUpFiles().size() == 0 : this.diff;
+ assert this.diff.getDeletedFiles().size() == 0 : this.diff;
+ assert unrelated1.exists() : "the deployment removed unrelated file1";
+ assert unrelated2.getParentFile().isDirectory() : "the deployment removed an unrelated dir";
+ assert unrelated2.exists() : "the deployment removed unrelated file2";
+ }
+
+ assert this.diff.getAddedFiles().size() == 2 : this.diff;
+ assert this.diff.getAddedFiles().contains(origFileName1) : this.diff;
+ assert this.diff.getAddedFiles().contains(origFileName2) : this.diff;
+ assert this.diff.getChangedFiles().isEmpty() : this.diff;
+ assert this.diff.getIgnoredFiles().isEmpty() : this.diff;
+ assert this.diff.getRealizedFiles().isEmpty() : this.diff;
+ assert this.diff.getRestoredFiles().isEmpty() : this.diff;
+ assert !this.diff.wasCleaned() : this.diff;
+ assert this.diff.getErrors().isEmpty() : this.diff;
// deploy new content
this.newDeployProps = new DeploymentProperties(2, "simple", "2.0", "new test deployment");
@@ -246,19 +280,36 @@ public class SimpleDeployerTest {
new String[] { newFileName1, newFileName2 });
HashSet<File> newZipFiles = new HashSet<File>(1);
newZipFiles.add(newZipFile);
- dd = new DeploymentData(newDeployProps, newZipFiles, null, tmpDir, deployDir, null, null, null, null, true,
- null);
+ dd = new DeploymentData(newDeployProps, newZipFiles, null, tmpDir, deployDir, null, null, null, null,
+ manageRootDir, null);
deployer = new Deployer(dd);
FileHashcodeMap newFileHashcodeMap = deployer.deploy(this.diff);
+ assert newFileHashcodeMap != null;
assert new File(this.deployDir, newFileName1).exists();
assert new File(this.deployDir, newFileName2).exists();
assert !new File(this.deployDir, origFileName1).exists();
assert !new File(this.deployDir, origFileName2).exists();
- assert !unrelated1.exists() : "the deployment did not remove unrelated file1";
- assert !unrelated2.exists() : "the deployment did not remove unrelated file1";
- assert this.diff.getBackedUpFiles().size() == 2 : this.diff;
- assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName1)).exists() : this.diff;
- assert new File(this.diff.getBackedUpFiles().get(unrelatedFileName2)).exists() : this.diff;
+ if (manageRootDir) {
+ assert !unrelated1.exists() : "the deployment did not remove unrelated file1";
+ assert !unrelated2.exists() : "the deployment did not remove unrelated file1";
+ } else {
+ assert unrelated1.exists() : "the deployment removed unrelated file1 but we aren't managing the root dir";
+ assert unrelated2.exists() : "the deployment removed unrelated file1 but we aren't managing the root dir";
+ }
+
+ assert this.diff.getAddedFiles().size() == 2 : this.diff;
+ assert this.diff.getAddedFiles().contains(newFileName1) : this.diff;
+ assert this.diff.getAddedFiles().contains(newFileName2) : this.diff;
+ assert this.diff.getDeletedFiles().size() == 2 : this.diff;
+ assert this.diff.getDeletedFiles().contains(origFileName1) : this.diff;
+ assert this.diff.getDeletedFiles().contains(origFileName2) : this.diff;
+ assert this.diff.getChangedFiles().isEmpty() : this.diff;
+ assert this.diff.getBackedUpFiles().isEmpty() : this.diff;
+ assert this.diff.getIgnoredFiles().isEmpty() : this.diff;
+ assert this.diff.getRealizedFiles().isEmpty() : this.diff;
+ assert this.diff.getRestoredFiles().isEmpty() : this.diff;
+ assert !this.diff.wasCleaned() : this.diff;
+ assert this.diff.getErrors().isEmpty() : this.diff;
}
private void baseX_X_X(boolean dryRun) throws Exception {
diff --git a/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java
index a772ef0..d712401 100644
--- a/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java
+++ b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java
@@ -231,11 +231,17 @@ public class AntBundlePluginComponentTest {
upgrade(true);
}
+ @Test(enabled = true)
+ public void testAntBundleInitialInstall() throws Exception {
+ doAntBundleInitialInstall(true);
+ }
+
/**
* Test deployment of an RHQ bundle recipe with archive file and raw file
+ * @param startClean if true, the destination directory will be non-existent and thus clean
+ * if false, this will put some junk files in the dest directory
*/
- @Test(enabled = true)
- public void testAntBundleInitialInstall() throws Exception {
+ private void doAntBundleInitialInstall(boolean startClean) throws Exception {
ResourceType resourceType = new ResourceType("testSimpleBundle2Type", "plugin", ResourceCategory.SERVER, null);
BundleType bundleType = new BundleType("testSimpleBundle2BType", resourceType);
Repo repo = new Repo("test-bundle-two");
@@ -273,6 +279,25 @@ public class AntBundlePluginComponentTest {
props.store(outputStream, "test.properties comment");
outputStream.close();
+ // if we are not to start clean, create some junk files that will need to be backed up and moved away
+ if (startClean == false) {
+ this.destDir.mkdirs();
+ File junk1 = new File(this.destDir, "junk1.properties");
+ Properties junkProps = new Properties();
+ junkProps.setProperty("junk1", "wot gorilla?");
+ FileOutputStream os = new FileOutputStream(junk1);
+ junkProps.store(os, "junk1.properties comment");
+ os.close();
+
+ File junk2 = new File(this.destDir, "junksubdir" + File.separatorChar + "junk2.properties");
+ junk2.getParentFile().mkdirs();
+ junkProps = new Properties();
+ junkProps.setProperty("junk2", "more junk");
+ os = new FileOutputStream(junk2);
+ junkProps.store(os, "junk2.properties comment");
+ os.close();
+ }
+
BundleDeployRequest request = new BundleDeployRequest();
request.setBundleFilesLocation(this.bundleFilesDir);
request.setResourceDeployment(new BundleResourceDeployment(deployment, null));
@@ -501,8 +526,129 @@ public class AntBundlePluginComponentTest {
assert "2".equals(props.getProperty("external2")) : "bundle purge removed our unmanaged file 2";
}
+ /**
+ * Test deployment of an RHQ bundle recipe where the deploy directory is to be fully managed.
+ * This is the typical use-case and the default behavior.
+ */
+ @Test(enabled = true)
+ public void testAntBundleManageRootDir() throws Exception {
+ ResourceType resourceType = new ResourceType("testManageRootDirBundle", "plugin", ResourceCategory.SERVER, null);
+ BundleType bundleType = new BundleType("testManageRootDirBundle", resourceType);
+ Repo repo = new Repo("testManageRootDirBundle");
+ PackageType packageType = new PackageType("testManageRootDirBundle", resourceType);
+ Bundle bundle = new Bundle("testManageRootDirBundle", bundleType, repo, packageType);
+ BundleVersion bundleVersion = new BundleVersion("testManageRootDirBundle", "1.0", bundle,
+ getRecipeFromFile("test-bundle-manage-root-dir.xml"));
+ BundleDestination destination = new BundleDestination(bundle, "testManageRootDirBundle", new ResourceGroup(
+ "testManageRootDirBundle"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath());
+ Configuration config = new Configuration();
+
+ BundleDeployment deployment = new BundleDeployment();
+ deployment.setName("test bundle deployment name");
+ deployment.setBundleVersion(bundleVersion);
+ deployment.setConfiguration(config);
+ deployment.setDestination(destination);
+
+ // create bundle test files
+ File file0 = new File(this.bundleFilesDir, "zero.properties");
+ Properties props = new Properties();
+ props.setProperty("zero", "0");
+ FileOutputStream outputStream = new FileOutputStream(file0);
+ props.store(outputStream, "zero file");
+ outputStream.close();
+
+ File file1 = new File(this.bundleFilesDir, "one.properties");
+ props.clear();
+ props.setProperty("one", "1");
+ outputStream = new FileOutputStream(file1);
+ props.store(outputStream, "one file");
+ outputStream.close();
+
+ File file2 = new File(this.bundleFilesDir, "two.properties");
+ props.clear();
+ props.setProperty("two", "2");
+ outputStream = new FileOutputStream(file2);
+ props.store(outputStream, "two file");
+ outputStream.close();
+
+ // create some external test files that don't belong to the bundle but are in the dest dir (which is to be managed by the bundle)
+ this.destDir.mkdirs();
+ File external1 = new File(this.destDir, "external1.properties");
+ props.clear();
+ props.setProperty("external1", "1");
+ outputStream = new FileOutputStream(external1);
+ props.store(outputStream, "external1 file");
+ outputStream.close();
+
+ File external2 = new File(this.destDir, "extdir/external2.properties");
+ external2.getParentFile().mkdirs();
+ props.clear();
+ props.setProperty("external2", "2");
+ outputStream = new FileOutputStream(external2);
+ props.store(outputStream, "external2 file");
+ outputStream.close();
+
+ // deploy the bundle
+ BundleDeployRequest request = new BundleDeployRequest();
+ request.setBundleFilesLocation(this.bundleFilesDir);
+ request.setResourceDeployment(new BundleResourceDeployment(deployment, null));
+ request.setBundleManagerProvider(new MockBundleManagerProvider());
+ request.setAbsoluteDestinationDirectory(this.destDir);
+
+ BundleDeployResult results = plugin.deployBundle(request);
+
+ assertResultsSuccess(results);
+
+ // test that files were deployed in the proper place
+ props.clear();
+ loadProperties(props, new FileInputStream(new File(this.destDir, "zero.properties")));
+ assert "0".equals(props.getProperty("zero")) : "did not deploy bundle correctly 0";
+ loadProperties(props, new FileInputStream(new File(this.destDir, "subdir1/one.properties")));
+ assert "1".equals(props.getProperty("one")) : "did not deploy bundle correctly 1";
+ loadProperties(props, new FileInputStream(new File(this.destDir, "subdir2/two.properties")));
+ assert "2".equals(props.getProperty("two")) : "did not deploy bundle correctly 2";
+
+ DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir);
+ assert metadata.isManaged() == true : "missing metadata directory";
+ assert metadata.getCurrentDeploymentProperties().getManageRootDir() == true : "should be managing root dir";
+
+ // make sure our external files/directories were removed because
+ // they aren't part of the bundle and we are fully managing the dest dir
+ props.clear();
+ try {
+ loadProperties(props, new FileInputStream(new File(this.destDir, "external1.properties")));
+ assert false : "bundle deployment did not remove our managed file 1";
+ } catch (Exception ok) {
+ }
+ try {
+ loadProperties(props, new FileInputStream(new File(this.destDir, "extdir/external2.properties")));
+ assert false : "bundle deployment did not remove our managed file 2";
+ } catch (Exception ok) {
+ }
+
+ // now purge the bundle - this should purge everything in the deploy dir because we are fully managing it
+ BundlePurgeRequest purgeRequest = new BundlePurgeRequest();
+ purgeRequest.setLiveResourceDeployment(new BundleResourceDeployment(deployment, null));
+ purgeRequest.setBundleManagerProvider(new MockBundleManagerProvider());
+ purgeRequest.setAbsoluteDestinationDirectory(this.destDir);
+
+ BundlePurgeResult purgeResults = plugin.purgeBundle(purgeRequest);
+ assertResultsSuccess(purgeResults);
+
+ // make sure our bundle files have been completely purged; the metadata directory should have been purged too
+ assert new File(this.destDir, "zero.properties").exists() == false;
+ assert new File(this.destDir, "subdir1/one.properties").exists() == false;
+ assert new File(this.destDir, "subdir2/two.properties").exists() == false;
+ assert new File(this.destDir, "subdir1").exists() == false;
+ assert new File(this.destDir, "subdir2").exists() == false;
+ assert this.destDir.exists() == false : "deploy dir should not exist, we were told to fully manage it";
+
+ metadata = new DeploymentsMetadata(this.destDir);
+ assert metadata.getMetadataDirectory().exists() == false : "metadata directory should not exist";
+ }
+
private void upgrade(boolean clean) throws Exception {
- testAntBundleInitialInstall(); // install a bundle first
+ doAntBundleInitialInstall(clean); // install a bundle first
cleanPluginDirs(); // clean everything but the dest dir - we want to upgrade the destination
prepareBeforeTestMethod(); // prepare for our new test
diff --git a/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml b/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml
new file mode 100644
index 0000000..9b77dd8
--- /dev/null
+++ b/modules/plugins/ant-bundle/src/test/resources/test-bundle-manage-root-dir.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<project name="simple-build" default="main"
+ xmlns:rhq="antlib:org.rhq.bundle">
+
+ <rhq:bundle name="testManageRootDirBundle" version="1.0">
+ <rhq:deployment-unit name="simulated-war" manageRootDir="true">
+ <rhq:file name="zero.properties" destinationFile="zero.properties"/>
+ <rhq:file name="one.properties" destinationFile="subdir1/one.properties"/>
+ <rhq:file name="two.properties" destinationFile="subdir2/two.properties"/>
+ </rhq:deployment-unit>
+ </rhq:bundle>
+
+ <target name="main"/>
+
+</project>
\ No newline at end of file
commit bfa42ba7f59974382e9c79f652926327f3efc28e
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Thu Jan 26 15:23:25 2012 -0600
Add code to reset and reinstall the database after an overwrite or upgrade test is run.
diff --git a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
index 6633cb7..e4fb711 100644
--- a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
+++ b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
@@ -27,6 +27,7 @@ import java.io.File;
import java.net.URL;
import java.util.Properties;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -67,6 +68,12 @@ public class DBInstallationTest {
installer.setLogDirectory(new File(LOG_DIRECTORY));
}
+ @AfterMethod
+ public void afterInstallation() throws Exception {
+ recreateTestDatabase();
+ installer.createNewDatabaseSchema(getInstallProperties());
+ }
+
@Test
public void overwriteJON230Schema() throws Exception {
installSchemaAndData("2.3.0");
commit 3f948097a57f7d20105474f2d2cc9a0e6e9dd892
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Thu Jan 26 11:03:40 2012 -0600
Revert "DBInstallationTest needs to use its own dedicated database"
This reverts commit cf001e9bc410896e57b7767164711fd8f819ccd8.
diff --git a/modules/enterprise/gui/installer-war/pom.xml b/modules/enterprise/gui/installer-war/pom.xml
index bd1474a..7f79832 100644
--- a/modules/enterprise/gui/installer-war/pom.xml
+++ b/modules/enterprise/gui/installer-war/pom.xml
@@ -35,8 +35,6 @@
<product.help.guide.agent>Running+the+RHQ+Agent</product.help.guide.agent>
<product.help.FAQ>FAQ</product.help.FAQ>
<product.help.config.props>http://support.rhq-project.org/display/JOPR2/Startup+Properties#Configuri...</product.help.config.props>
-
- <rhq.db.installation.test.db-name>rhq_installer_test_db</rhq.db.installation.test.db-name>
</properties>
<dependencies>
@@ -151,8 +149,6 @@
<rhq.db.admin.password>${rhq.db.admin.password}</rhq.db.admin.password>
<rhq.test.ds.user-name>${rhq.test.ds.user-name}</rhq.test.ds.user-name>
<rhq.test.ds.password>${rhq.test.ds.password}</rhq.test.ds.password>
- <rhq.db.installation.test.db-name>${rhq.db.installation.test.db-name}</rhq.db.installation.test.db-name>
- <rhq.db.installation.test.connection-url>jdbc:postgresql://${rhq.test.ds.server-name}:5432/${rhq.db.installation.test.db-name}</rhq.db.installation.test.connection-url>
</systemPropertyVariables>
</configuration>
</plugin>
diff --git a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
index 3bff054..6633cb7 100644
--- a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
+++ b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
@@ -23,15 +23,18 @@
package org.rhq.enterprise.installer;
-import org.rhq.core.db.reset.DBReset;
-import org.rhq.core.db.setup.DBSetup;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
import java.io.File;
import java.net.URL;
import java.util.Properties;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import org.rhq.core.db.reset.DBReset;
+import org.rhq.core.db.setup.DBSetup;
+import org.rhq.enterprise.installer.ServerInformation;
+import org.rhq.enterprise.installer.ServerProperties;
+
/**
* The tests in this class exercise the dbsetup/dbupgrade code that is run in the installer. The tests currently only
* run against postgresql. Support needs to be added for oracle. The tests do not do any post-install/upgrade
@@ -43,12 +46,12 @@ import java.util.Properties;
public class DBInstallationTest {
private final String LOG_DIRECTORY = System.getProperty("java.io.tmpdir", "rhq/installer-test");
- private final String DB_NAME = System.getProperty("rhq.db.installation.test.db-name", "rhq_installer_test_db");
+ private final String DB_NAME = System.getProperty("rhq.test.ds.db-name", "rhq_installer_test_db");
private final String USERNAME = System.getProperty("rhq.test.ds.user-name", "rhqadmin");
private final String PASSWORD = System.getProperty("rhq.test.ds.password", "rhqadmin");
private final String SERVER = System.getProperty("rhq.test.ds.server-name", "127.0.0.1");
- private final String DB_URL = System.getProperty("rhq.db.installation.test.connection-url",
- "jdbc:postgresql://" + SERVER + ":5432/" + DB_NAME);
+ private final String DB_URL = System.getProperty("rhq.test.ds.connection-url", "jdbc:postgresql://" + SERVER
+ + ":5432/" + DB_NAME);
private final String ADMIN_USERNAME = System.getProperty("rhq.db.admin.username", "postgres");
private final String ADMIN_PASSWORD = System.getProperty("rhq.db.admin.password", "postgres");
private static final String DB_TYPE_MAPPING = System.getProperty("rhq.test.ds.type-mapping", "PostgreSQL");
commit c1aa992c86006933eb955dc6d90ff9728f897863
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Thu Jan 26 11:02:28 2012 -0600
Revert "Updating the installer test to:"
This reverts commit 842ad5f20b752884d19e55d8f87e0e7252f78154.
diff --git a/modules/enterprise/gui/installer-war/pom.xml b/modules/enterprise/gui/installer-war/pom.xml
index c1dd476..bd1474a 100644
--- a/modules/enterprise/gui/installer-war/pom.xml
+++ b/modules/enterprise/gui/installer-war/pom.xml
@@ -145,13 +145,14 @@
<systemPropertyVariables>
<rhq.test.ds.type-mapping>${rhq.test.ds.type-mapping}</rhq.test.ds.type-mapping>
<rhq.test.ds.server-name>${rhq.test.ds.server-name}</rhq.test.ds.server-name>
- <rhq.test.ds.port>${rhq.test.ds.port}</rhq.test.ds.port>
- <rhq.db.installation.test.db-name>${rhq.db.installation.test.db-name}</rhq.db.installation.test.db-name>
+ <rhq.test.ds.db-name>${rhq.test.ds.db-name}</rhq.test.ds.db-name>
<rhq.test.ds.connection-url>${rhq.test.ds.connection-url}</rhq.test.ds.connection-url>
<rhq.db.admin.username>${rhq.db.admin.username}</rhq.db.admin.username>
<rhq.db.admin.password>${rhq.db.admin.password}</rhq.db.admin.password>
<rhq.test.ds.user-name>${rhq.test.ds.user-name}</rhq.test.ds.user-name>
<rhq.test.ds.password>${rhq.test.ds.password}</rhq.test.ds.password>
+ <rhq.db.installation.test.db-name>${rhq.db.installation.test.db-name}</rhq.db.installation.test.db-name>
+ <rhq.db.installation.test.connection-url>jdbc:postgresql://${rhq.test.ds.server-name}:5432/${rhq.db.installation.test.db-name}</rhq.db.installation.test.connection-url>
</systemPropertyVariables>
</configuration>
</plugin>
@@ -340,8 +341,8 @@
<id>oracle</id>
<activation>
<property>
- <name>rhq.test.ds.type-mapping</name>
- <value>Oracle10g</value>
+ <name>rhq.test.db.type</name>
+ <value>oracle</value>
</property>
</activation>
<build>
diff --git a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
index 81c5664..3bff054 100644
--- a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
+++ b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
@@ -47,9 +47,8 @@ public class DBInstallationTest {
private final String USERNAME = System.getProperty("rhq.test.ds.user-name", "rhqadmin");
private final String PASSWORD = System.getProperty("rhq.test.ds.password", "rhqadmin");
private final String SERVER = System.getProperty("rhq.test.ds.server-name", "127.0.0.1");
- private final String PORT = System.getProperty("rhq.test.ds.port", "5432");
- private final String DB_URL = System.getProperty("rhq.test.ds.connection-url", "jdbc:postgresql://" + SERVER
- + ":" + PORT + "/" + DB_NAME);
+ private final String DB_URL = System.getProperty("rhq.db.installation.test.connection-url",
+ "jdbc:postgresql://" + SERVER + ":5432/" + DB_NAME);
private final String ADMIN_USERNAME = System.getProperty("rhq.db.admin.username", "postgres");
private final String ADMIN_PASSWORD = System.getProperty("rhq.db.admin.password", "postgres");
private static final String DB_TYPE_MAPPING = System.getProperty("rhq.test.ds.type-mapping", "PostgreSQL");
commit 04cd6df03ec0dd2bdd6093c313c55a4ff3cb3110
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Jan 26 21:56:13 2012 +0100
First cut at content-based (re-)deployment
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 6fa678b..9651be2 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
@@ -51,6 +51,8 @@ public class ASConnection {
private ObjectMapper mapper;
public static boolean verbose = false; // This is a variable on purpose, so devs can switch it on in the debugger or in the agent
Authenticator passwordAuthenticator ;
+ private String host;
+ private int port;
/**
* Construct an ASConnection object. The real "physical" connection is done in
@@ -61,6 +63,8 @@ public class ASConnection {
* @param password password needed for authentication
*/
public ASConnection(String host, int port, String user, String password) {
+ this.host = host;
+ this.port = port;
try {
url = new URL("http", host, port, MANAGEMENT);
@@ -258,5 +262,11 @@ public class ASConnection {
}
}
+ public String getHost() {
+ return host;
+ }
+ public int getPort() {
+ return port;
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
index a5b8bdd..ff5aa94 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
@@ -66,8 +66,15 @@ public class ASUploadConnection {
public ASUploadConnection(String dcHost, int port, String user, String password) {
this.host = dcHost;
this.port = port;
- passwordAuthenticator = new AS7Authenticator(user,password);
- Authenticator.setDefault(passwordAuthenticator);
+ if (user!=null) {
+ passwordAuthenticator = new AS7Authenticator(user,password);
+ Authenticator.setDefault(passwordAuthenticator);
+ }
+ }
+
+ public ASUploadConnection(ASConnection asConnection) {
+ this.host=asConnection.getHost();
+ this.port=asConnection.getPort();
}
public OutputStream getOutputStream(String fileName) {
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
index e4fa0e4..7510a8f 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
@@ -70,7 +70,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-public class BaseComponent<T extends ResourceComponent<?>> implements ResourceComponent<T>, MeasurementFacet, ConfigurationFacet, DeleteResourceFacet,
+public class BaseComponent<T extends ResourceComponent<?>> implements ResourceComponent<T>, MeasurementFacet, ConfigurationFacet,
+ DeleteResourceFacet,
CreateChildResourceFacet, OperationFacet
{
private static final String INTERNAL = "_internal:";
@@ -341,13 +342,18 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
if (fileName.startsWith("C:\\fakepath\\")) { // TODO this is a hack as the server adds the fake path somehow
fileName=fileName.substring("C:\\fakepath\\".length());
}
-
- String tmpName = fileName; // TODO figure out the tmp-name biz with the AS guys
+ String runtimeName = fileName;
+ PropertySimple rtNameProp = report.getPackageDetails().getDeploymentTimeConfiguration().getSimple("runtimeName");
+ if (rtNameProp != null) {
+ String rtn = rtNameProp.getStringValue();
+ if (rtn!=null && !rtn.isEmpty())
+ runtimeName = rtn;
+ }
JsonNode resultNode = uploadResult.get("result");
String hash = resultNode.get("BYTES_VALUE").getTextValue();
- return runDeploymentMagicOnServer(report, fileName, tmpName, hash);
+ return runDeploymentMagicOnServer(report, runtimeName, fileName, hash);
}
/**
@@ -367,7 +373,7 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
ASConnection connection = getASConnection();
- Operation step1 = new Operation("add","deployment",deploymentName);
+ Operation step1 = new Operation("add","deployment",runtimeName);
// step1.addAdditionalProperty("hash", new PROPERTY_VALUE("BYTES_VALUE", hash));
List<Object> content = new ArrayList<Object>(1);
Map<String,Object> contentValues = new HashMap<String,Object>();
@@ -429,6 +435,8 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
report.setStatus(CreateResourceStatus.SUCCESS);
report.setResourceName(runtimeName);
report.setResourceKey(resourceKey);
+ report.getPackageDetails().setSHA256(hash);
+ report.getPackageDetails().setInstallationTimestamp(System.currentTimeMillis());
log.info(" ... with success and key [" + resourceKey + "]" );
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
index 56eee84..2e6163d 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
@@ -1,18 +1,46 @@
package org.rhq.modules.plugins.jbossas7;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.JsonNode;
+
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.content.PackageDetailsKey;
+import org.rhq.core.domain.content.PackageType;
+import org.rhq.core.domain.content.transfer.ContentResponseResult;
+import org.rhq.core.domain.content.transfer.DeployPackageStep;
+import org.rhq.core.domain.content.transfer.DeployPackagesResponse;
+import org.rhq.core.domain.content.transfer.RemovePackagesResponse;
+import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.pluginapi.content.ContentFacet;
+import org.rhq.core.pluginapi.content.ContentServices;
+import org.rhq.core.pluginapi.inventory.CreateResourceReport;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.modules.plugins.jbossas7.json.Address;
+import org.rhq.modules.plugins.jbossas7.json.ComplexResult;
import org.rhq.modules.plugins.jbossas7.json.Operation;
+import org.rhq.modules.plugins.jbossas7.json.PROPERTY_VALUE;
import org.rhq.modules.plugins.jbossas7.json.ReadAttribute;
+import org.rhq.modules.plugins.jbossas7.json.ReadChildrenResources;
import org.rhq.modules.plugins.jbossas7.json.Result;
/**
* Deal with deployments
* @author Heiko W. Rupp
*/
-public class DeploymentComponent extends BaseComponent implements OperationFacet{
+public class DeploymentComponent extends BaseComponent implements OperationFacet, ContentFacet {
+
+ private boolean verbose = ASConnection.verbose;
@Override
public AvailabilityType getAvailability() {
@@ -21,7 +49,7 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
if (!res.isSuccess())
return AvailabilityType.DOWN;
- if (!(Boolean)(res.getResult()))
+ if (res.getResult()== null || !(Boolean)(res.getResult()))
return AvailabilityType.DOWN;
return AvailabilityType.UP;
@@ -50,4 +78,121 @@ public class DeploymentComponent extends BaseComponent implements OperationFacet
return result;
}
+
+
+ @Override
+ public List<DeployPackageStep> generateInstallationSteps(ResourcePackageDetails packageDetails) {
+ return new ArrayList<DeployPackageStep>();
+ }
+
+ @Override
+ public DeployPackagesResponse deployPackages(Set<ResourcePackageDetails> packages,
+ ContentServices contentServices) {
+
+ DeployPackagesResponse response = new DeployPackagesResponse();
+
+ if (packages.size()!=1) {
+ response.setOverallRequestResult(ContentResponseResult.FAILURE);
+ response.setOverallRequestErrorMessage("Can only deploy one package at a time");
+ }
+
+ ResourcePackageDetails detail = packages.iterator().next();
+
+ ASUploadConnection uploadConnection = new ASUploadConnection(getASConnection());
+ OutputStream out = uploadConnection.getOutputStream(detail.getFileName());
+ ResourceType resourceType = context.getResourceType();
+
+ log.info("trying " + resourceType.getName() + ", " + detail.getKey() );
+
+ contentServices.downloadPackageBits(context.getContentContext(),
+ detail.getKey(), out, true);
+
+ JsonNode uploadResult = uploadConnection.finishUpload();
+ if (verbose)
+ log.info(uploadResult);
+
+ if (ASUploadConnection.isErrorReply(uploadResult)) {
+ response.setOverallRequestResult(ContentResponseResult.FAILURE);
+ response.setOverallRequestErrorMessage(ASUploadConnection.getFailureDescription(uploadResult));
+
+ return response;
+ }
+ JsonNode resultNode = uploadResult.get("result");
+ String hash = resultNode.get("BYTES_VALUE").getTextValue();
+
+
+ CreateResourceReport report1 = new CreateResourceReport("", resourceType, new Configuration(),
+ new Configuration(), detail);
+ //CreateResourceReport report = runDeploymentMagicOnServer(report1,detail.getKey().getName(),hash, hash);
+
+ try {
+ redeployOnServer(detail.getKey().getName(), hash);
+ response.setOverallRequestResult(ContentResponseResult.SUCCESS);
+ }
+ catch (Exception e) {
+ response.setOverallRequestResult(ContentResponseResult.FAILURE);
+ }
+
+
+ return response;
+ }
+
+ private void redeployOnServer(String name, String hash) throws Exception {
+
+ Operation op = new Operation("full-replace-deployment", new Address());
+ op.addAdditionalProperty("name",name);
+ List<Object> content = new ArrayList<Object>(1);
+ Map<String,Object> contentValues = new HashMap<String,Object>();
+ contentValues.put("hash",new PROPERTY_VALUE("BYTES_VALUE",hash));
+ content.add(contentValues);
+ op.addAdditionalProperty("content",content);
+ Result result = getASConnection().execute(op);
+ if (result.isRolledBack())
+ throw new Exception(result.getFailureDescription());
+ }
+
+ @Override
+ public RemovePackagesResponse removePackages(Set<ResourcePackageDetails> packages) {
+ return null; // TODO: Customise this generated block
+ }
+
+ @Override
+ public Set<ResourcePackageDetails> discoverDeployedPackages(PackageType type) {
+
+ Set<ResourcePackageDetails> details = new HashSet<ResourcePackageDetails>();
+
+ // PackageType = "Deployment"
+ Address address1 = getAddress().getParent();
+ Operation op = new ReadChildrenResources(address1,"deployment");
+ ComplexResult cres = getASConnection().executeComplex(op);
+
+ if (!cres.isSuccess())
+ return details;
+
+ Map<String,Object> deployments = cres.getResult();
+ for (String key : deployments.keySet()) {
+ Map<String,Object> deployment = (Map<String, Object>) deployments.get(key);
+
+ List<Map> contentList = (List<Map>) deployment.get("content");
+ Map<String,Map> hashMap = contentList.get(0);
+ Map<String,String> bvMap = hashMap.get("hash");
+ String content = bvMap.get("BYTES_VALUE");
+ PackageDetailsKey pdKey = new PackageDetailsKey(key,
+ content, // no way to obtain the user defined version from the server
+ type.getName(),
+ "noarch"
+ );
+ ResourcePackageDetails detail = new ResourcePackageDetails(pdKey);
+ detail.setSHA256(content);
+
+ details.add(detail);
+ }
+
+ return details;
+ }
+
+ @Override
+ public InputStream retrievePackageBits(ResourcePackageDetails packageDetails) {
+ return null; // TODO: Customise this generated block
+ }
}
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 b044848..fdebf0a 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
@@ -185,8 +185,6 @@
displayType="summary" measurementType="dynamic" description="Max time for a request since last metric get" units="milliseconds"
displayName="Maximum request time"/>
- <metric property="server-state" dataType="trait" displayName="Server state" description="Detailed server state"
- displayType="summary"/>
<metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
<metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
<metric property="product-name" dataType="trait" displayName="Name of the product"/>
@@ -1108,17 +1106,13 @@
description="The number of times that statements from the cache were used"/>
<metric property="AverageBlockingTime" units="milliseconds"
description="The average time spent blocking for a connection"/>
- <metric property="MaxWaitTime" units="milliseconds"
- description="The maximum wait time for a connection" displayType="summary"/>
<metric property="ActiveCount"
description="The active count"/>
<metric property="CreatedCount" description="The created count" measurementType="trendsup"/>
<metric property="MaxCreationTime" description="The maximum time for creating a physical connection" units="milliseconds"/>
- <metric property="MaxWaitCount" description="The maximum number of threads waiting for a connection" units="milliseconds" displayType="summary"/>
<metric property="TotalCreationTime" description="The total time spent creating physical connections" measurementType="trendsup" units="milliseconds"/>
<metric property="AvailableCount" description="The available count" units="milliseconds"/>
<metric property="MaxUsedCount" description="The maximum number of connections used"/>
- <metric property="TimedOut" description="The timed out count" measurementType="trendsup" displayType="summary"/>
<metric property="TotalBlockingTime" description="The total blocking time" measurementType="trendsup" units="milliseconds"/>
<metric property="AverageCreationTime" description="The average time spent creating a physical connection" units="milliseconds"/>
<metric property="DestroyedCount" description="The destroyed count" measurementType="trendsup"/>
@@ -2155,7 +2149,7 @@ working area for individual server instances</li></ul>"/>
<content name="file" category="deployable" isCreationType="true" description="Deployments on this server group">
<configuration>
<c:group name="deployment" displayName="Deployment Options">
- <c:simple-property name="runtimeName" required="false"/>
+ <c:simple-property name="runtimeName" required="false" description="Runtime name of the uploaded file (e.g. 'my.war'). If not present, the file name is used."/>
</c:group>
</configuration>
</content>
commit 9586f50ca5fa7b8ab9046ee50a29223c2a6d0608
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Jan 26 12:09:16 2012 +0100
BZ 766284 - Follow the type renaming from the plugin descriptor to again correctly detect server state.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
index 0352765..8fdb02e 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASComponent.java
@@ -18,13 +18,10 @@
*/
package org.rhq.modules.plugins.jbossas7;
-import java.util.ArrayList;
-import java.util.List;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.Operation;
-import org.rhq.modules.plugins.jbossas7.json.PROPERTY_VALUE;
import org.rhq.modules.plugins.jbossas7.json.ReadAttribute;
import org.rhq.modules.plugins.jbossas7.json.Result;
@@ -44,13 +41,13 @@ public class ManagedASComponent extends BaseComponent {
@Override
public AvailabilityType getAvailability() {
- if (context.getResourceType().getName().equals("JBossAS7 Managed Server")) {
+ if (context.getResourceType().getName().equals("Managed Server")) {
Address theAddress = new Address();
String host = pluginConfiguration.getSimpleValue("domainHost","local");
theAddress.add("host",host);
theAddress.add("server-config", myServerName);
Operation getStatus = new ReadAttribute(theAddress,"status");
- Result result = null;
+ Result result;
try {
result = connection.execute(getStatus);
} catch (Exception e) {
commit 667e32201f8701e6e0ebf04e2b57ff5f1570505b
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Jan 26 11:38:30 2012 +0100
Add a getParent() method to addresses.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
index 51fc3a2..ad0d6cf 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
@@ -195,4 +195,23 @@ public class Address {
PROPERTY_VALUE property_value = path.get(n);
return property_value.getKey() + "=" + property_value.getValue();
}
+
+ /**
+ * Return the parent Address of the current one. That is the address with one
+ * path segment less.
+ * If the current address is empty (the root), an empty address is returned.
+ * @return parent Address
+ */
+ public Address getParent() {
+ Address tmp = new Address();
+ int l = path.size();
+ if (l<1)
+ return tmp;
+
+ for (int i = 0; i < l-1 ; i++) {
+ tmp.path.add(path.get(i));
+ }
+
+ return tmp;
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/PathHandlingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/PathHandlingTest.java
index 113bc53..882d377 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/PathHandlingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/PathHandlingTest.java
@@ -60,4 +60,31 @@ public class PathHandlingTest {
assert a.size()==3 : "Size was not 3, but "+ a.size();
assert !a.isEmpty();
}
+
+ public void getParent1() throws Exception {
+ String path = "subsystem=jms,profile=default,queue=foo";
+ Address a = new Address(path);
+ Address b = a.getParent();
+ assert b!=null;
+ assert b.size()==2;
+ assert b.get(0).equals("subsystem=jms");
+ assert b.get(1).equals("profile=default");
+ }
+
+ public void getParent2() throws Exception {
+ Address a = new Address();
+ Address b = a.getParent();
+ assert b!=null;
+ assert b.isEmpty();
+ assert b.size()==0;
+ }
+
+ public void getParent3() throws Exception {
+ Address a = new Address("foo=bar");
+ Address b = a.getParent();
+ assert b!=null;
+ assert b.isEmpty();
+ assert b.size()==0;
+ }
+
}
commit 12f4bb20d501b49093710dd9b86e28e884618989
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Jan 25 13:10:45 2012 +0100
If the result is not a string, try to convert it accordingly.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
index 3f03e52..e4fa0e4 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
@@ -168,14 +168,14 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
continue;
}
- String val = (String) res.getResult();
+ Object val = res.getResult();
if (val==null) // One of the AS7 ways of telling "This is not implemented" See also AS7-1454
continue;
if (req.getDataType()== DataType.MEASUREMENT) {
if (!val.equals("no metrics available")) { // AS 7 returns this
try {
- Double d = Double.parseDouble(val);
+ Double d = Double.parseDouble((String)val);
MeasurementDataNumeric data = new MeasurementDataNumeric(req,d);
report.addData(data);
} catch (NumberFormatException e) {
@@ -183,7 +183,14 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
}
}
} else if (req.getDataType()== DataType.TRAIT) {
- MeasurementDataTrait data = new MeasurementDataTrait(req,val);
+
+ String realVal;
+ if (val instanceof String)
+ realVal = (String)val;
+ else
+ realVal = String.valueOf(val);
+
+ MeasurementDataTrait data = new MeasurementDataTrait(req,realVal);
report.addData(data);
}
}
commit 2967bf90637cc80e7d43484adfc7826bb7b9c033
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Wed Jan 25 14:33:40 2012 -0600
Use a more direct approach to disable tests. The tests will now run only oracle-test profile is explictly invoked.
Also corrected property bindings for database connection settings.
diff --git a/modules/plugins/oracle/pom.xml b/modules/plugins/oracle/pom.xml
index 9a1f93e..509a614 100644
--- a/modules/plugins/oracle/pom.xml
+++ b/modules/plugins/oracle/pom.xml
@@ -26,24 +26,11 @@
</dependencies>
- <profiles>
- <profile>
- <id>default</id>
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skipTests>true</skipTests>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
+ <properties>
+ <skipTests>true</skipTests>
+ </properties>
+ <profiles>
<profile>
<id>ojdbc-driver</id>
@@ -53,7 +40,7 @@
</property>
</activation>
- <!-- Make sure the Oracle JDBC jar gets included in the plugin jar's lib dir. -->
+ <!-- Make sure the Oracle JDBC jar gets included in the plugin jar's lib dir. -->
<build>
<plugins>
@@ -166,6 +153,11 @@
<activation>
<activeByDefault>false</activeByDefault>
</activation>
+
+ <properties>
+ <skipTests>false</skipTests>
+ </properties>
+
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
@@ -181,15 +173,15 @@
<systemProperties>
<property>
<name>oracle.url</name>
- <value>${oracle.url}</value>
+ <value>${rhq.test.ds.connection-url}</value>
</property>
<property>
- <name>oracle.userid</name>
- <value>${oracle.userid}</value>
+ <name>oracle.username</name>
+ <value>${rhq.test.ds.user-name}</value>
</property>
<property>
<name>oracle.password</name>
- <value>${oracle.password}</value>
+ <value>${rhq.test.ds.password}</value>
</property>
</systemProperties>
<!-- The below is required for tests to run against Oracle.
@@ -209,6 +201,7 @@
<activation>
<activeByDefault>false</activeByDefault>
</activation>
+
<build>
<plugins>
<plugin>
diff --git a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
index 949aaae..d9d2fb0 100644
--- a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
+++ b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
@@ -49,7 +49,7 @@ public class OracleServerComponentTest extends ComponentTest {
protected void setConfiguration(Configuration configuration, ResourceType resourceType) {
if (resourceType.getName().equals(ORACLE_SERVER)) {
log.info(configuration.getProperties());
- Pattern p = Pattern.compile("jdbc:.*:@(.*):(\\d+)/(\\w++)");
+ Pattern p = Pattern.compile("jdbc:.*:@(.*):(\\d+):(\\w++)");
String url = System.getProperty("oracle.url");
if (url == null)
throw new IllegalStateException("oracle.url system property not set");
commit 842ad5f20b752884d19e55d8f87e0e7252f78154
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Jan 25 13:23:25 2012 +0100
Updating the installer test to:
1) Not execute on Oracle
2) Support port specification (in case connection url is missing)
3) Pass the rhq.db.installation.test.db-name to the TestNG test
diff --git a/modules/enterprise/gui/installer-war/pom.xml b/modules/enterprise/gui/installer-war/pom.xml
index bd1474a..c1dd476 100644
--- a/modules/enterprise/gui/installer-war/pom.xml
+++ b/modules/enterprise/gui/installer-war/pom.xml
@@ -145,14 +145,13 @@
<systemPropertyVariables>
<rhq.test.ds.type-mapping>${rhq.test.ds.type-mapping}</rhq.test.ds.type-mapping>
<rhq.test.ds.server-name>${rhq.test.ds.server-name}</rhq.test.ds.server-name>
- <rhq.test.ds.db-name>${rhq.test.ds.db-name}</rhq.test.ds.db-name>
+ <rhq.test.ds.port>${rhq.test.ds.port}</rhq.test.ds.port>
+ <rhq.db.installation.test.db-name>${rhq.db.installation.test.db-name}</rhq.db.installation.test.db-name>
<rhq.test.ds.connection-url>${rhq.test.ds.connection-url}</rhq.test.ds.connection-url>
<rhq.db.admin.username>${rhq.db.admin.username}</rhq.db.admin.username>
<rhq.db.admin.password>${rhq.db.admin.password}</rhq.db.admin.password>
<rhq.test.ds.user-name>${rhq.test.ds.user-name}</rhq.test.ds.user-name>
<rhq.test.ds.password>${rhq.test.ds.password}</rhq.test.ds.password>
- <rhq.db.installation.test.db-name>${rhq.db.installation.test.db-name}</rhq.db.installation.test.db-name>
- <rhq.db.installation.test.connection-url>jdbc:postgresql://${rhq.test.ds.server-name}:5432/${rhq.db.installation.test.db-name}</rhq.db.installation.test.connection-url>
</systemPropertyVariables>
</configuration>
</plugin>
@@ -341,8 +340,8 @@
<id>oracle</id>
<activation>
<property>
- <name>rhq.test.db.type</name>
- <value>oracle</value>
+ <name>rhq.test.ds.type-mapping</name>
+ <value>Oracle10g</value>
</property>
</activation>
<build>
diff --git a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
index 3bff054..81c5664 100644
--- a/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
+++ b/modules/enterprise/gui/installer-war/src/test/java/org/rhq/enterprise/installer/DBInstallationTest.java
@@ -47,8 +47,9 @@ public class DBInstallationTest {
private final String USERNAME = System.getProperty("rhq.test.ds.user-name", "rhqadmin");
private final String PASSWORD = System.getProperty("rhq.test.ds.password", "rhqadmin");
private final String SERVER = System.getProperty("rhq.test.ds.server-name", "127.0.0.1");
- private final String DB_URL = System.getProperty("rhq.db.installation.test.connection-url",
- "jdbc:postgresql://" + SERVER + ":5432/" + DB_NAME);
+ private final String PORT = System.getProperty("rhq.test.ds.port", "5432");
+ private final String DB_URL = System.getProperty("rhq.test.ds.connection-url", "jdbc:postgresql://" + SERVER
+ + ":" + PORT + "/" + DB_NAME);
private final String ADMIN_USERNAME = System.getProperty("rhq.db.admin.username", "postgres");
private final String ADMIN_PASSWORD = System.getProperty("rhq.db.admin.password", "postgres");
private static final String DB_TYPE_MAPPING = System.getProperty("rhq.test.ds.type-mapping", "PostgreSQL");
commit 812590209506a08087bdd1127d0322367e36d2a1
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Tue Jan 24 16:31:12 2012 -0500
[BZ 703557] add support for building and running the jmx plugin on
Mac OS X / Apple JDK
(https://bugzilla.redhat.com/show_bug.cgi?id=703557)
diff --git a/modules/enterprise/agent/src/etc/rhq-agent.sh b/modules/enterprise/agent/src/etc/rhq-agent.sh
index 45b99a2..19a0ae6 100755
--- a/modules/enterprise/agent/src/etc/rhq-agent.sh
+++ b/modules/enterprise/agent/src/etc/rhq-agent.sh
@@ -141,6 +141,10 @@ fi
# ----------------------------------------------------------------------
CLASSPATH="${RHQ_AGENT_HOME}/conf"
+if [ ! -d "${RHQ_AGENT_HOME}/lib" ]; then
+ echo "lib subdirectory does not exist under RHQ_AGENT_HOME directory: ${RHQ_AGENT_HOME}"
+ exit 1
+fi
_JAR_FILES=`cd "${RHQ_AGENT_HOME}/lib";ls -1 *.jar`
for _JAR in $_JAR_FILES ; do
_JAR="${RHQ_AGENT_HOME}/lib/${_JAR}"
@@ -151,7 +155,7 @@ for _JAR in $_JAR_FILES ; do
fi
debug_msg "CLASSPATH entry: $_JAR"
done
-for _TOOLS_JAR in "${RHQ_AGENT_JAVA_HOME}/lib/tools.jar" "${RHQ_AGENT_JAVA_HOME}/../lib/tools.jar"; do
+for _TOOLS_JAR in "${RHQ_AGENT_JAVA_HOME}/lib/tools.jar" "${RHQ_AGENT_JAVA_HOME}/../lib/tools.jar" "${RHQ_AGENT_JAVA_HOME}/Classes/classes.jar" "${RHQ_AGENT_JAVA_HOME}/../Classes/classes.jar"; do
if [ -f "${_TOOLS_JAR}" ]; then
debug_msg "CLASSPATH entry: ${_TOOLS_JAR}"
CLASSPATH="${CLASSPATH}:${_TOOLS_JAR}"
diff --git a/modules/plugins/jmx/pom.xml b/modules/plugins/jmx/pom.xml
index 8780b32..bcf0cf1 100644
--- a/modules/plugins/jmx/pom.xml
+++ b/modules/plugins/jmx/pom.xml
@@ -23,14 +23,14 @@
<!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
</dependency>
- <!-- needed for the JVM Attach API. NOTE: we do not include tools.jar in the plugin jar's lib dir, because if it
+ <!-- needed for the JVM Attach API. NOTE: we do not package tools.jar in the plugin jar's lib dir, because if it
is available at runtime, rhq-agent.sh/rhq-agent.bat will add it to the Agent's classpath. -->
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.6.0</version>
<scope>system</scope>
- <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ <systemPath>${jdkToolsJar}</systemPath>
</dependency>
</dependencies>
@@ -64,6 +64,31 @@
</build>
<profiles>
+
+ <profile>
+ <id>sun_jdk</id>
+ <activation>
+ <file>
+ <exists>${java.home}/../lib/tools.jar</exists>
+ </file>
+ </activation>
+ <properties>
+ <jdkToolsJar>${java.home}/../lib/tools.jar</jdkToolsJar>
+ </properties>
+ </profile>
+
+ <profile>
+ <id>osx_jdk</id>
+ <activation>
+ <file>
+ <exists>${java.home}/../Classes/classes.jar</exists>
+ </file>
+ </activation>
+ <properties>
+ <jdkToolsJar>${java.home}/../Classes/classes.jar</jdkToolsJar>
+ </properties>
+ </profile>
+
<profile>
<id>integration-tests</id>
<activation>
@@ -232,6 +257,7 @@
</plugins>
</build>
</profile>
+
<profile>
<id>cobertura-plugins</id>
<activation>
commit c862b9c470fe112c39f73215f807c39b1de034b6
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 24 22:11:07 2012 +0100
BZ 783507 - allow to enable/disable deployments on server-group level.
Availability follows enabled state.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
new file mode 100644
index 0000000..56eee84
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DeploymentComponent.java
@@ -0,0 +1,53 @@
+package org.rhq.modules.plugins.jbossas7;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.core.pluginapi.operation.OperationFacet;
+import org.rhq.core.pluginapi.operation.OperationResult;
+import org.rhq.modules.plugins.jbossas7.json.Operation;
+import org.rhq.modules.plugins.jbossas7.json.ReadAttribute;
+import org.rhq.modules.plugins.jbossas7.json.Result;
+
+/**
+ * Deal with deployments
+ * @author Heiko W. Rupp
+ */
+public class DeploymentComponent extends BaseComponent implements OperationFacet{
+
+ @Override
+ public AvailabilityType getAvailability() {
+ Operation op = new ReadAttribute(getAddress(),"enabled");
+ Result res = getASConnection().execute(op);
+ if (!res.isSuccess())
+ return AvailabilityType.DOWN;
+
+ if (!(Boolean)(res.getResult()))
+ return AvailabilityType.DOWN;
+
+ return AvailabilityType.UP;
+ }
+
+ @Override
+ public OperationResult invokeOperation(String name,
+ Configuration parameters) throws InterruptedException, Exception {
+
+ String action;
+ if (name.equals("enable")) {
+ action = "deploy";
+ } else if (name.equals("disable")) {
+ action = "undeploy";
+ } else {
+ return super.invokeOperation(name, parameters);
+ }
+
+ Operation op = new Operation(action,getAddress());
+ Result res = getASConnection().execute(op);
+ OperationResult result = new OperationResult();
+ if (res.isSuccess())
+ result.setSimpleResult("Success");
+ else
+ result.setErrorMessage(res.getFailureDescription());
+
+ return result;
+ }
+}
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 f80ac3c..b044848 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
@@ -141,7 +141,7 @@
<operation name="managed-server:remove" displayName="Remove managed server" description="Remove a managed server">
<parameters>
<c:simple-property name="servername" displayName="Name of the server to remove" required="true">
- <c:option-source target="resource" expression="type=JBossAS7 Managed Server"/>
+ <c:option-source target="resource" expression="type=Managed Server"/>
</c:simple-property>
<c:simple-property name="hostname" displayName="Name of the host where the server is on" required="true">
<c:option-source target="resource" expression="type=^Host$ plugin=jboss-as-7"/>
@@ -563,7 +563,7 @@
description="Information about the underlying JVM"
singleton="true">
<runs-inside>
- <parent-resource-type name="JBossAS7 Managed Server" plugin="jboss-as-7"/>
+ <parent-resource-type name="Managed Server" plugin="jboss-as-7"/>
<parent-resource-type name="JBossAS7 Standalone Server" plugin="jboss-as-7"/>
</runs-inside>
@@ -2126,7 +2126,7 @@ working area for individual server instances</li></ul>"/>
</service>
<service name="Deployment"
- class="BaseComponent"
+ class="DeploymentComponent"
discovery="SubsystemDiscovery"
createDeletePolicy="both"
creationDataType="content">
@@ -2135,11 +2135,23 @@ working area for individual server instances</li></ul>"/>
<runs-inside>
<parent-resource-type name="ServerGroup" plugin="jboss-as-7"/>
<parent-resource-type name="JBossAS7 Standalone Server" plugin="jboss-as-7"/>
+ <parent-resource-type name="Managed Server" plugin="jboss-as-7"/>
</runs-inside>
<plugin-configuration>
<c:simple-property name="path" default="deployment" readOnly="true"/>
</plugin-configuration>
+ <operation name="enable">
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+ <operation name="disable">
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+
<content name="file" category="deployable" isCreationType="true" description="Deployments on this server group">
<configuration>
<c:group name="deployment" displayName="Deployment Options">
commit fe55609882928da8855f0d4382b4a8509430e5bb
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 24 16:46:06 2012 +0100
BZ 782780, BZ 766284 - properly detect management ports on the HC, move managed hosts below HC in the resource tree,
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
index 0e58078..c464e4b 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
@@ -127,9 +127,20 @@ public class AbstractBaseDiscovery {
String portString;
String interfaceExpession;
- String socketBindingName = obtainXmlPropertyViaXPath(
+ String socketBindingName;
+
+ socketBindingName = obtainXmlPropertyViaXPath(
"//management/management-interfaces/http-interface/socket-binding/@http");
- if (socketBindingName==null || socketBindingName.isEmpty()) {
+ String socketInterface = obtainXmlPropertyViaXPath(
+ "//management/management-interfaces/http-interface/socket/@interface");
+
+ if (!socketInterface.isEmpty()) {
+ interfaceExpession = obtainXmlPropertyViaXPath(
+ "//interfaces/interface[@name='" + socketInterface + "']/inet-address/@value");
+ portString = obtainXmlPropertyViaXPath(
+ "//management/management-interfaces/http-interface/socket/@port");
+ }
+ else if (socketBindingName.isEmpty()) {
// old AS7.0, early 7.1 style
portString = obtainXmlPropertyViaXPath("//management/management-interfaces/http-interface/@port");
String interfaceName = obtainXmlPropertyViaXPath(
@@ -138,7 +149,7 @@ public class AbstractBaseDiscovery {
"/server/interfaces/interface[@name='" + interfaceName + "']/inet-address/@value");
}
else {
- // later AS7.1 and EAP6
+ // later AS7.1 and EAP6 standalone.xml
portString = obtainXmlPropertyViaXPath(
"/server/socket-binding-group/socket-binding[@name='" + socketBindingName + "']/@port");
String interfaceName = obtainXmlPropertyViaXPath(
@@ -152,13 +163,13 @@ public class AbstractBaseDiscovery {
HostPort hp = new HostPort();
if (!interfaceExpession.isEmpty())
- hp.host = replaceDollarExpression(interfaceExpession, commandLine);
+ hp.host = replaceDollarExpression(interfaceExpession, commandLine, "localhost");
else
hp.host = "localhost"; // Fallback
if (portString!=null && !portString.isEmpty()) {
- String tmp = replaceDollarExpression(portString,commandLine);
+ String tmp = replaceDollarExpression(portString,commandLine, "9990");
hp.port = Integer.valueOf(tmp);
}
else
@@ -172,17 +183,19 @@ public class AbstractBaseDiscovery {
* try to resolve it. Resolution is done by looking at the command line to see if
* there are -bmanagement or -Djboss.bind.address.management arguments present
*
+ *
* @param value a hostname or hostname expression
* @param commandLine The command line from the process
+ * @param lastResort
* @return resolved value
*/
- private String replaceDollarExpression(String value, String[] commandLine) {
+ private String replaceDollarExpression(String value, String[] commandLine, String lastResort) {
if (!value.contains("${"))
return value;
// remove ${ }
value = value.substring(2,value.length()-1);
- String fallback = "localhost";
+ String fallback = lastResort;
String expression;
if (value.contains(":")) {
int i = value.indexOf(":");
@@ -202,16 +215,19 @@ public class AbstractBaseDiscovery {
*/
String ret=null;
- for (String line: commandLine) {
+ for (int i = 0, commandLineLength = commandLine.length; i < commandLineLength; i++) {
+ String line = commandLine[i];
if (expression.contains("address")) {
if (line.contains("-bmanagement") || line.contains("jboss.bind.address.management")) {
- ret = line.substring(line.indexOf("=")+1);
+ if (line.contains("="))
+ ret = line.substring(line.indexOf("=") + 1); // -bmanagement=1.2.3.4
+ else
+ ret = commandLine[i+1]; // -bmanagement 1.2.3.4
break;
}
- }
- else if (expression.contains("port")) {
+ } else if (expression.contains("port")) {
if (line.contains(expression)) {
- ret = line.substring(line.indexOf("=")+1);
+ ret = line.substring(line.indexOf("=") + 1);
break;
}
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
index f4fa473..f21e598 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
@@ -39,6 +39,10 @@ public class HostControllerComponent extends BaseServerComponent implements Oper
private final Log log = LogFactory.getLog(HostControllerComponent.class);
+ public Configuration getHCConfig() {
+ return pluginConfiguration;
+ }
+
@Override
public OperationResult invokeOperation(String name,
Configuration parameters) throws InterruptedException, Exception {
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
index 53afe21..050aef0 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
@@ -20,14 +20,11 @@ package org.rhq.modules.plugins.jbossas7;
import java.io.File;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
@@ -37,200 +34,156 @@ import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.system.ProcessInfo;
import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.ComplexResult;
import org.rhq.modules.plugins.jbossas7.json.Operation;
-import org.rhq.modules.plugins.jbossas7.json.PROPERTY_VALUE;
+import org.rhq.modules.plugins.jbossas7.json.ReadAttribute;
+import org.rhq.modules.plugins.jbossas7.json.ReadChildrenNames;
import org.rhq.modules.plugins.jbossas7.json.ReadResource;
+import org.rhq.modules.plugins.jbossas7.json.Result;
/**
* Discovery class for managed AS 7 instances.
*
* @author Heiko W. Rupp
*/
-@SuppressWarnings("unused")
public class ManagedASDiscovery extends AbstractBaseDiscovery implements ResourceDiscoveryComponent
{
+ private HostControllerComponent parentComponent;
+
/**
* Run the auto-discovery
*/
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext discoveryContext) throws Exception {
Set<DiscoveredResourceDetails> discoveredResources = new HashSet<DiscoveredResourceDetails>();
- List<ProcessScanResult> scans = discoveryContext.getAutoDiscoveredProcesses();
-
- for (ProcessScanResult psr : scans) {
-
- try {
- // get the HostController, as this is an indicator for managed AS
- String psName = psr.getProcessScan().getName();
- if (!psName.equals("HostController"))
- continue;
-
- // Now we have the host controller, lets get the host.xml file
- // and obtain the servers from there.
- ProcessInfo processInfo = psr.getProcessInfo();
- readStandaloneOrHostXml(processInfo, true);
- String hostName = findHostName();
- HostPort managementHostPort = getManagementPortFromHostXml(processInfo.getCommandLine());
-
- List<ServerInfo> serverNames = getServersFromHostXml();
- for (ServerInfo serverInfo : serverNames) {
-
- Configuration config = discoveryContext.getDefaultPluginConfiguration();
- config.put(new PropertySimple("domainHost", hostName));
- config.put(new PropertySimple("group", serverInfo.group));
- config.put(new PropertySimple("port", managementHostPort.port));
- config.put(new PropertySimple("hostname", managementHostPort.host));
- if (serverInfo.bindingGroup != null) {
- config.put(new PropertySimple("socket-binding-group", serverInfo.bindingGroup));
- config.put(new PropertySimple("socket-binding-port-offset", serverInfo.portOffset));
- } else {
- HostPort dcHP = getDomainControllerFromHostXml();
- if (dcHP.port == 9999)
- dcHP.port = 9990; // TODO Hack until JBAS-9306 is solved
-
- ServerInfo dcInfo = getBindingsFromDC(dcHP, serverInfo.group);
- config.put(new PropertySimple("socket-binding-group", dcInfo.bindingGroup));
- config.put(new PropertySimple("socket-binding-port-offset", dcInfo.portOffset));
- }
- config.put(new PropertySimple("socket-binding-port-offset", serverInfo.portOffset));
-
- String path = "host=" + hostName + ",server-config=" + serverInfo.name;
- config.put(new PropertySimple("path", path));
-
- // TODO this fails for the downed servers.
- // get from the domain or other place as soon as the domain provides it.
- String homeDir = getHomeDirFromCommandLine(processInfo.getCommandLine());
- initLogFile(scans, serverInfo.name, config, homeDir);
-
- String version = determineServerVersionFromHomeDir(homeDir);
- String resourceDescription;
-
- String resourceName = serverInfo.name;
-
- if (homeDir.contains("eap")) {
- version = "EAP " + version;
- resourceDescription = "Managed JBoss Enterprise Application Platform 6 server";
- resourceName = "EAP " + resourceName;
- }
- else {
- resourceDescription = "Managed AS7 server";
- }
-
- DiscoveredResourceDetails detail = new DiscoveredResourceDetails(discoveryContext.getResourceType(), // ResourceType
+ parentComponent = (HostControllerComponent) discoveryContext.getParentResourceComponent();
+ Configuration hcConfig = parentComponent.getHCConfig();
+ String hostName = hcConfig.getSimpleValue("domainHost", "master"); // TODO good default?
+
+ HostInfo hostInfo = getHostInfo(hostName);
+ if (hostInfo==null)
+ return discoveredResources;
+
+
+ try {
+ // get the HostController, as this is an indicator for managed AS
+
+ // Now we have the host controller, lets get the host.xml file
+ // and obtain the servers from there.
+
+ List<ServerInfo> serverNames;
+ serverNames = getManagedServers(hostName);
+ for (ServerInfo serverInfo : serverNames) {
+
+ Configuration config = discoveryContext.getDefaultPluginConfiguration();
+ config.put(new PropertySimple("domainHost", hostName));
+ config.put(new PropertySimple("group", serverInfo.group));
+ if (serverInfo.bindingGroup != null) {
+ config.put(new PropertySimple("socket-binding-group", serverInfo.bindingGroup));
+ } else {
+ String group = resolveSocketBindingGroup(serverInfo.group);
+ config.put(new PropertySimple("socket-binding-group",group));
+
+ }
+ config.put(new PropertySimple("socket-binding-port-offset", serverInfo.portOffset));
+
+ String path = "host=" + hostName + ",server-config=" + serverInfo.name;
+ config.put(new PropertySimple("path", path));
+
+ // get from the domain or other place as soon as the domain provides it.
+ String serverLog = hcConfig.getSimpleValue("baseDir","/tmp")+File.separator+"domain/servers/"+serverInfo.name+"/log/server.log";
+ initLogEventSourcesConfigProp(serverLog,config);
+
+ String version;
+ String resourceDescription;
+
+ String resourceName = serverInfo.name;
+
+ if (hostInfo.productName.equalsIgnoreCase("eap")) {
+ version = "EAP " + hostInfo.productVersion;
+ resourceDescription = "Managed JBoss Enterprise Application Platform 6 server";
+ resourceName = "EAP " + resourceName;
+ }
+ else if (hostInfo.productName.equalsIgnoreCase("EDG")) {
+ version = "EDG " + hostInfo.productVersion;
+ resourceDescription = "Managed JBoss Enterprise Data Grid 6 server";
+ }
+ else {
+ resourceDescription = "Managed AS7 server";
+ version = hostInfo.releaseVersion;
+ }
+
+ DiscoveredResourceDetails detail = new DiscoveredResourceDetails(discoveryContext.getResourceType(), // ResourceType
hostName + "/" + serverInfo.name, // key
resourceName, // Name
version, // TODO get from Domain as soon as it is provided
- resourceDescription, // Description
+ resourceDescription, // Description
config, null);
- // Add to return values
- discoveredResources.add(detail);
- log.info("Discovered new ... " + discoveryContext.getResourceType() + ", " + serverInfo);
- }
- } catch (Exception e) {
- log.warn("Discovery for a " + discoveryContext.getResourceType() + " failed for process " + psr + " :" + e.getMessage());
+ // Add to return values
+ discoveredResources.add(detail);
+ log.info("Discovered new ... " + discoveryContext.getResourceType() + ", " + serverInfo);
}
+ } catch (Exception e) {
+ log.warn("Discovery for a " + discoveryContext.getResourceType() + " failed for process " + " :" + e.getMessage());
}
return discoveredResources;
}
- private ServerInfo getBindingsFromDC(HostPort domainController, String serverGroup) {
- ASConnection dcConnection = new ASConnection(domainController.host, domainController.port, "-TODO-", "-TODO-"); // TODO where do we get these from?
- List<PROPERTY_VALUE> address = new ArrayList<PROPERTY_VALUE>();
- Address theAddress = new Address("server-group", serverGroup);
- Operation op = new ReadResource(theAddress);
- ComplexResult res = (ComplexResult) dcConnection.execute(op, true);
- if (res!=null && res.isSuccess()) {
- if (res.getResult().containsKey("socket-binding-group")) {
- String sbg = (String) res.getResult().get("socket-binding-group");
-
- ServerInfo serverInfo = new ServerInfo();
- serverInfo.bindingGroup = sbg;
- return serverInfo;
- }
- }
-
- return new ServerInfo();
+ private String resolveSocketBindingGroup(String serverGroup) {
+ Address address = new Address("server-group",serverGroup);
+ Operation operation = new ReadAttribute(address,"socket-binding-group");
+ Result result = parentComponent.getASConnection().execute(operation);
+ return (String) result.getResult();
}
- /**
- * Loop through the Process scans for ManagedAS and if found extract the logfile path.
- * @param scans process scan results
- * @param name server name to look for
- * @param config config to put the info in
- * @param basePath
- */
- private void initLogFile(List<ProcessScanResult> scans, String name, Configuration config, String basePath) {
-
- for (ProcessScanResult psr : scans) {
- if (!psr.getProcessScan().getName().equals("ManagedAS"))
- continue;
-
- String[] commandLine = psr.getProcessInfo().getCommandLine();
-
- //preload server.log file for event log monitoring
- String bootLogFile = getLogFileFromCommandLine(commandLine);
- String logFile = bootLogFile.substring(0, bootLogFile.lastIndexOf("/")) + File.separator + "server.log";
-
- if (logFile.contains(name))
- initLogEventSourcesConfigProp(logFile, config);
+ private List<ServerInfo> getManagedServers(String domainHost) {
+ Address address = new Address("host",domainHost);
+ Operation operation = new ReadChildrenNames(address,"server-config");
+ ASConnection connection = parentComponent.getASConnection();
+ Result res = connection.execute(operation);
+ List<String> servers = (List<String>) res.getResult();
+ List<ServerInfo> ret = new ArrayList<ServerInfo>(servers.size());
+ for (String server : servers) {
+ ServerInfo info = new ServerInfo();
+ info.name = server;
+ ret.add(info);
+
+ address= new Address("host",domainHost);
+ address.add("server-config",server);
+ operation = new ReadResource(address);
+ ComplexResult cres = connection.executeComplex(operation);
+ Map<String,Object> map = cres.getResult();
+ info.group = (String) map.get("group");
+ info.autoStart = (Boolean)map.get("auto-start");
+ Integer offset = (Integer) map.get("socket-binding-port-offset");
+ if (offset!=null)
+ info.portOffset = offset;
+ info.bindingGroup = (String) map.get("socket-binding-group");
}
+
+ return ret;
}
- private List<ServerInfo> getServersFromHostXml() {
+ private HostInfo getHostInfo(String domainHost) {
+ Address address = new Address("host",domainHost);
+ Operation operation = new ReadResource(address);
+ HostInfo info = new HostInfo();
- Element host = hostXml.getDocumentElement();
- NodeList serversElement = host.getElementsByTagName("servers");
- if (serversElement == null || serversElement.getLength() == 0) {
- log.warn("No <servers> found in host.xml");
- return Collections.emptyList();
- }
- NodeList servers = serversElement.item(0).getChildNodes();
- if (servers == null || servers.getLength() == 0) {
- log.warn("No <server> found in host.xml");
- return Collections.emptyList();
- }
- List<ServerInfo> result = new ArrayList<ServerInfo>();
- for (int i = 0; i < servers.getLength(); i++) {
- if (!(servers.item(i) instanceof Element))
- continue;
-
- ServerInfo info = new ServerInfo();
- Element server = (Element) servers.item(i);
- info.name = server.getAttribute("name");
- info.group = server.getAttribute("group");
- String autoStart = server.getAttribute("autoStart");
- if (autoStart == null || autoStart.isEmpty())
- autoStart = "false";
- info.autoStart = Boolean.getBoolean(autoStart);
-
- // Look for <socket-binding-group ref="standard-sockets" port-offset="250"/>
- NodeList sbgs = server.getChildNodes();
- if (sbgs != null) {
- for (int j = 0; j < sbgs.getLength(); j++) {
- if (!(sbgs.item(j) instanceof Element))
- continue;
-
- Element sbg = (Element) sbgs.item(j);
- if (!sbg.getNodeName().equals("socket-binding-group"))
- continue;
-
- info.bindingGroup = sbg.getAttribute("ref");
- String portOffset = sbg.getAttribute("port-offset");
- if (portOffset != null && !portOffset.isEmpty())
- info.portOffset = Integer.parseInt(portOffset);
+ ComplexResult cres = parentComponent.getASConnection().executeComplex(operation);
+ if (!cres.isSuccess())
+ return null;
- }
- }
- result.add(info);
- }
+ Map<String,Object> map = cres.getResult();
+ info.releaseCodeName = (String) map.get("release-codename");
+ info.releaseVersion = (String)map.get("release-version");
+ info.productName = (String) map.get("product-name");
+ info.productVersion = (String)map.get("product-version");
- return result;
+ return info;
}
private void initLogEventSourcesConfigProp(String fileName, Configuration pluginConfiguration) {
@@ -266,4 +219,11 @@ public class ManagedASDiscovery extends AbstractBaseDiscovery implements Resourc
}
}
+ private static class HostInfo {
+ String name;
+ String productVersion;
+ String releaseVersion;
+ String productName;
+ String releaseCodeName;
+ }
}
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 0474772..f80ac3c 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
@@ -328,6 +328,45 @@
</resource-configuration>
</server>
+ <server name="Managed Server"
+ discovery="ManagedASDiscovery"
+ class="ManagedASComponent"
+ >
+ <plugin-configuration>
+ <c:simple-property name="hostname" default="localhost" displayName="Management host" required="true"/>
+ <c:simple-property name="port" default="9990" type="integer" displayName="Management port" required="true"/>
+ <c:simple-property name="domainHost" readOnly="true" description="Hostname in the domain"/>
+ <c:simple-property name="group" readOnly="true" displayName="Server Group" description="Server Group this instance belongs to."/>
+ <c:simple-property name="socket-binding-group" readOnly="true" displayName="Socket binding group" description="Socket bindings to use" required="false"/>
+ <c:simple-property name="socket-binding-port-offset" readOnly="true" displayName="Port Offset" type="integer" default="0" description="Offset to the base ports"/>
+ <c:simple-property name="path" readOnly="true" />
+
+ &logSources;
+ </plugin-configuration>
+
+ <operation name="server:start" description="Start this server instance." displayName="Start">
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+ <operation name="server:stop" description="Stop this server instance." displayName="Stop">
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+ <operation name="server:restart" description="Restart this server instance." displayName="Restart">
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+
+ <metric property="status" dataType="trait" displayName="Server state" description="Detailed server state"
+ displayType="summary"/>
+
+ <event name="logEntry" description="an entry in a log file"/>
+
+ </server>
+
<service name="DomainDeployment"
class="BaseComponent"
discovery="SubsystemDiscovery"
@@ -517,83 +556,6 @@
</server>
- <server name="JBossAS7 Managed Server"
- discovery="ManagedASDiscovery"
- class="ManagedASComponent"
- >
- <plugin-configuration>
- <c:simple-property name="hostname" default="localhost" displayName="Management host" required="true"/>
- <c:simple-property name="port" default="9990" type="integer" displayName="Management port" required="true"/>
- <c:simple-property name="domainHost" readOnly="true" description="Hostname in the domain"/>
- <c:simple-property name="group" readOnly="true" displayName="Server Group" description="Server Group this instance belongs to."/>
- <c:simple-property name="socket-binding-group" readOnly="true" displayName="Socket binding group" description="Socket bindings to use"/>
- <c:simple-property name="socket-binding-port-offset" readOnly="true" displayName="Port Offset" type="integer" default="0" description="Offset to the base ports"/>
- <c:simple-property name="path" readOnly="true" />
-
- &logSources;
- <c:group name="event" displayName="Events">
- <c:list-property name="logEventSources">
- <c:map-property name="logEventSource">
- <c:simple-property name="logFilePath" type="file" summary="true"
- description="The absolute path to the source log file."/>
- <c:simple-property name="enabled" type="boolean" summary="true"
- description="A flag indicating whether of not this log Event source is currently
- enabled (i.e. whether the associated log file should be tailed for
- new entries)."/>
- <c:simple-property name="dateFormat" required="false"
- description="The date format to use when parsing the dates in log entries. The
- format must be in the syntax defined by the Java SimpleDateFormat
- class. If not specified, the three date formats that are predefined
- by Log4J (ISO8601, DATE, and ABSOLUTE) will be tried."/>
- <c:simple-property name="includesPattern" required="false"
- description="A regular expression against which a log entry's detail is matched
- to determine if an Event should be fired for that entry. If not
- specified, no filtering of log entries will be done based on their
- detail."/>
- <c:simple-property name="minimumSeverity" required="false" default="error"
- description="The minimum severity of Events that should be collected for this
- source. If not specified, there is no minimum severity (i.e. all
- events will be collected).">
- <c:property-options>
- <c:option name="debug" value="debug"/>
- <c:option name="info" value="info"/>
- <c:option name="warn" value="warn"/>
- <c:option name="error" value="error"/>
- <c:option name="fatal" value="fatal"/>
- </c:property-options>
- </c:simple-property>
- </c:map-property>
- </c:list-property>
- </c:group>
- </plugin-configuration>
-
- <!-- Scan for host controller is intentional -->
- <process-scan name="HostController" query="process|basename|match=^java.*,arg|org.jboss.as.host-controller|match=.*"/>
- <process-scan name="ManagedAS" query="process|basename|match=^java.*,arg|org.jboss.as.server|match=.*"/>
-
- <operation name="server:start" description="Start this server instance." displayName="Start">
- <results>
- <c:simple-property name="operationResult"/>
- </results>
- </operation>
- <operation name="server:stop" description="Stop this server instance." displayName="Stop">
- <results>
- <c:simple-property name="operationResult"/>
- </results>
- </operation>
- <operation name="server:restart" description="Restart this server instance." displayName="Restart">
- <results>
- <c:simple-property name="operationResult"/>
- </results>
- </operation>
-
- <metric property="status" dataType="trait" displayName="Server state" description="Detailed server state"
- displayType="summary"/>
-
- <event name="logEntry" description="an entry in a log file"/>
-
- </server>
-
<server name="JVM"
discovery="SubsystemDiscovery"
commit f300158a2d31739222ca21a43cf6284891de7c10
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 23 11:32:56 2012 +0100
Add product-release and product-version traits (relates to BZ 734488).
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 7198463..0474772 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
@@ -189,6 +189,8 @@
displayType="summary"/>
<metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
<metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
+ <metric property="product-name" dataType="trait" displayName="Name of the product"/>
+ <metric property="product-version" dataType="trait" displayName="Version of the product" displayType="summary"/>
<event name="logEntry" description="an entry in a log file"/>
@@ -471,6 +473,8 @@
displayType="summary"/>
<metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
<metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
+ <metric property="product-name" dataType="trait" displayName="Name of the product"/>
+ <metric property="product-version" dataType="trait" displayName="Version of the product" displayType="summary"/>
<event name="logEntry" description="an entry in a log file"/>
commit 4db65364eba2f3327a0d8f13c7ac079497718388
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 23 17:49:51 2012 +0100
[BZ 767170] - The permissions are already known, don't try to fetch them
asynchronously again in the role and user views.
This simplifies the rendering of those views tremendously making them work
reliably and without possible race conditions.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
index 53bd86d..7d4810b 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/AdministrationView.java
@@ -117,13 +117,13 @@ public class AdministrationView extends AbstractSectionedLeftNavigationView {
private NavigationSection buildSecuritySection() {
NavigationItem usersItem = new NavigationItem(UsersView.VIEW_ID, "global/User_16.png", new ViewFactory() {
public Canvas createView() {
- return new UsersView(extendLocatorId("Users"));
+ return new UsersView(extendLocatorId("Users"), getGlobalPermissions().contains(Permission.MANAGE_SECURITY));
}
});
NavigationItem rolesItem = new NavigationItem(RolesView.VIEW_ID, "global/Role_16.png", new ViewFactory() {
public Canvas createView() {
- return new RolesView(extendLocatorId("Roles"));
+ return new RolesView(extendLocatorId("Roles"), getGlobalPermissions().contains(Permission.MANAGE_SECURITY));
}
});
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
index 3c3e91d..91f2c2f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/roles/RolesView.java
@@ -20,7 +20,6 @@ package org.rhq.enterprise.gui.coregui.client.admin.roles;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.widgets.Canvas;
@@ -29,10 +28,7 @@ import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.CellClickEvent;
import com.smartgwt.client.widgets.grid.events.CellClickHandler;
-import org.rhq.core.domain.authz.Permission;
import org.rhq.enterprise.gui.coregui.client.BookmarkableView;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoader;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter;
import org.rhq.enterprise.gui.coregui.client.components.table.TableAction;
@@ -46,7 +42,7 @@ import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
* @author Greg Hinkle
* @author Ian Springer
*/
-public class RolesView extends TableSection<RolesDataSource> implements BookmarkableView {
+public class RolesView extends TableSection<RolesDataSource> {
public static final ViewName VIEW_ID = new ViewName("Roles", MSG.common_title_roles());
public static final String VIEW_PATH = AdministrationView.VIEW_ID + "/"
@@ -55,22 +51,18 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark
private static final String HEADER_ICON = "global/Role_24.png";
private boolean hasManageSecurity;
- private boolean initialized;
- public RolesView(String locatorId) {
+ public RolesView(String locatorId, boolean hasManageSecurity) {
super(locatorId, MSG.common_title_roles());
final RolesDataSource datasource = RolesDataSource.getInstance();
setDataSource(datasource);
setHeaderIcon(HEADER_ICON);
setEscapeHtmlInDetailsLinkColumn(true);
+
+ this.hasManageSecurity = hasManageSecurity;
}
-
- @Override
- protected void onDraw() {
- fetchManageSecurityPermissionAsync();
- }
-
+
@Override
protected void configureTable() {
updateSelectionStyle();
@@ -156,31 +148,12 @@ public class RolesView extends TableSection<RolesDataSource> implements Bookmark
};
}
- private void fetchManageSecurityPermissionAsync() {
- new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- if (permissions != null) {
- hasManageSecurity = permissions.contains(Permission.MANAGE_SECURITY);
- refreshTableInfo();
- } else {
- hasManageSecurity = false;
- }
- if (!initialized) {
- RolesView.super.onDraw();
- }
- initialized = true;
- }
- });
- }
-
private void updateSelectionStyle() {
- if (initialized) {
- if (!hasManageSecurity) {
- getListGrid().deselectAllRecords();
- }
- SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
- getListGrid().setSelectionType(selectionStyle);
+ if (!hasManageSecurity) {
+ getListGrid().deselectAllRecords();
}
+ SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
+ getListGrid().setSelectionType(selectionStyle);
}
@Override
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
index a8b35fd..18213f1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/users/UsersView.java
@@ -20,7 +20,6 @@ package org.rhq.enterprise.gui.coregui.client.admin.users;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.SelectionStyle;
@@ -32,8 +31,6 @@ import com.smartgwt.client.widgets.grid.events.CellClickHandler;
import org.rhq.core.domain.authz.Permission;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoader;
import org.rhq.enterprise.gui.coregui.client.admin.AdministrationView;
import org.rhq.enterprise.gui.coregui.client.components.table.EscapedHtmlCellFormatter;
import org.rhq.enterprise.gui.coregui.client.components.table.TableAction;
@@ -61,9 +58,8 @@ public class UsersView extends TableSection<UsersDataSource> {
private static final String HEADER_ICON = "global/User_24.png";
private boolean hasManageSecurity;
- private boolean initialized;
- public UsersView(String locatorId) {
+ public UsersView(String locatorId, boolean hasManageSecurity) {
super(locatorId, MSG.common_title_users());
final UsersDataSource dataSource = UsersDataSource.getInstance();
@@ -71,8 +67,8 @@ public class UsersView extends TableSection<UsersDataSource> {
setDataSource(dataSource);
setHeaderIcon(HEADER_ICON);
setEscapeHtmlInDetailsLinkColumn(true);
-
- fetchManageSecurityPermissionAsync();
+
+ this.hasManageSecurity = hasManageSecurity;
}
@Override
@@ -101,28 +97,12 @@ public class UsersView extends TableSection<UsersDataSource> {
updateSelectionStyle();
}
- private void fetchManageSecurityPermissionAsync() {
- new PermissionsLoader().loadExplicitGlobalPermissions(new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- if (permissions != null) {
- hasManageSecurity = permissions.contains(Permission.MANAGE_SECURITY);
- refreshTableInfo();
- } else {
- hasManageSecurity = false;
- }
- initialized = true;
- }
- });
- }
-
private void updateSelectionStyle() {
- if (initialized) {
- if (!hasManageSecurity) {
- getListGrid().deselectAllRecords();
- }
- SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
- getListGrid().setSelectionType(selectionStyle);
+ if (!hasManageSecurity) {
+ getListGrid().deselectAllRecords();
}
+ SelectionStyle selectionStyle = hasManageSecurity ? getDefaultSelectionStyle() : SelectionStyle.NONE;
+ getListGrid().setSelectionType(selectionStyle);
}
private List<ListGridField> createFields() {
commit f585a36371486dd5d2aa2639f6c17be53e33e0a1
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 23 17:45:46 2012 +0100
Added some clarification to the javadocs of InitializableView to lower
the expectations one might have about it.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
index b5fc3b9..f503d99 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/InitializableView.java
@@ -33,7 +33,12 @@ public interface InitializableView {
/**
* Return true if this widget's {@link BaseWidget#init() initialization} has completed, or false otherwise.
- *
+ * <p>
+ * Don't expect this to work automagically if the result of this method is dependent on some asynchronous call.
+ * The consumers of this method need in that case loop and check this method periodically. If you cannot guarantee
+ * all the callers of this method on your instance actually do that, you can't assume that the results of
+ * the asynchronous call will be taken into account correctly.
+ *
* @return true if this widget's {@link BaseWidget#init() initialization} has completed, or false otherwise
*/
boolean isInitialized();
commit 5c0202533709fe382b7db4d10c7d55834f9400c4
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 21:20:11 2012 -0500
if an exception occurs when discoverResource() calls ProcessComponent.getProcessForConfiguration(), include it as the cause of the RuntimeException that is thrown, rather than swallowing it; set a description on the details object returned by discoverResource()
diff --git a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessDiscoveryComponent.java b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessDiscoveryComponent.java
index f30f923..1f506aa 100644
--- a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessDiscoveryComponent.java
+++ b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/ProcessDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -52,22 +52,25 @@ public class ProcessDiscoveryComponent implements ResourceDiscoveryComponent, Ma
resourceDiscoveryContext.getSystemInformation());
}
catch (Exception e) {
- throw new RuntimeException("Failed to create process based on plugin config: " + pluginConfig);
+ throw new RuntimeException("Failed to manually add process Resource based on plugin config: "
+ + pluginConfig.toString(true), e);
}
String type = pluginConfig.getSimpleValue("type", "pidFile");
String resourceKey = pluginConfig.getSimpleValue(type, null);
if (resourceKey == null || resourceKey.length() == 0) {
- throw new InvalidPluginConfigurationException("Invalid type [" + type + "] value [" + resourceKey + "]");
+ throw new InvalidPluginConfigurationException("Invalid type [" + type + "] value: [" + resourceKey + "]");
}
ResourceType resourceType = resourceDiscoveryContext.getResourceType();
String resourceName = processInfo.getBaseName();
String resourceVersion = null;
- String resourceDescription = null;
+ String resourceDescription = processInfo.getBaseName() + " process with "
+ + (type.equals("pidFile") ? "PID file" : "PIQL expression") + " [" + resourceKey + "]";
DiscoveredResourceDetails detail = new DiscoveredResourceDetails(resourceType, resourceKey, resourceName,
resourceVersion, resourceDescription, pluginConfig, processInfo);
return detail;
}
+
}
commit dbe929c0ce98c4acb513a9c35dd94113f309a7ea
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 21:17:18 2012 -0500
fix generics-related compiler warning
diff --git a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/PlatformDiscoveryComponent.java b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/PlatformDiscoveryComponent.java
index d7e9ef9..e795810 100644
--- a/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/PlatformDiscoveryComponent.java
+++ b/modules/plugins/platform/src/main/java/org/rhq/plugins/platform/PlatformDiscoveryComponent.java
@@ -1,4 +1,4 @@
- /*
+/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
@@ -51,7 +51,7 @@ public abstract class PlatformDiscoveryComponent implements ResourceDiscoveryCom
*/
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) {
if (!isPlatformSupported(context)) {
- return Collections.EMPTY_SET;
+ return Collections.emptySet();
}
SystemInfo systemInfo = context.getSystemInformation();
commit 459fa871d3808fc03c56bc7930c827a29ade6587
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 15:04:02 2012 -0500
change the line endings back to Windows format (CRLF) (IntelliJ
converted them to Unix format (LF) on my last commit)
diff --git a/modules/enterprise/agent/src/etc/rhq-agent.bat b/modules/enterprise/agent/src/etc/rhq-agent.bat
index fc8bdf1..005e535 100644
--- a/modules/enterprise/agent/src/etc/rhq-agent.bat
+++ b/modules/enterprise/agent/src/etc/rhq-agent.bat
@@ -1,227 +1,227 @@
-@echo off
-
-rem ===========================================================================
-rem RHQ Agent Windows Startup Script
-rem
-rem This file is used to execute the RHQ Agent on a Windows platform.
-rem Run this script with the --help option for the runtime options.
-rem
-rem Note that this script can also be used to simply set environment variables
-rem that define the agent's environment but it will not actually run the agent.
-rem Pass in _SETENV_ONLY as the first argument to this script if you want this
-rem behavior.
-rem
-rem This script is customizable by setting certain environment variables, which
-rem are described in comments in rhq-agent-env.bat. The variables can also be
-rem set via rhq-agent-env.bat, which is sourced by this script.
-rem
-rem If the embedded JRE is to be used but is not available, the fallback
-rem JRE to be used will be determined by the JAVA_HOME environment variable.
-rem ===========================================================================
-
-setlocal
-
-if "%1"=="_SETENV_ONLY" (
- set _SETENV_ONLY=true
-) else (
- title RHQ Agent
-)
-
-rem if debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_DEBUG%" == "false" (
- set RHQ_AGENT_DEBUG=
-)
-
-rem ----------------------------------------------------------------------
-rem Change directory so the current directory is the Agent home.
-rem Here we assume this script is a child directory of the Agent home
-rem We also assume our custom environment script is located in the same
-rem place as this script.
-rem ----------------------------------------------------------------------
-
-set RHQ_AGENT_BIN_DIR_PATH=%~dp0
-
-if exist "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" (
- if defined RHQ_AGENT_DEBUG echo Loading environment script: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
- call "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" %*
-) else (
- if defined RHQ_AGENT_DEBUG echo No environment script found at: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
-)
-
-rem if debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_DEBUG%" == "false" (
- set RHQ_AGENT_DEBUG=
-)
-
-rem if sigar debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_SIGAR_DEBUG%" == "false" (
- set RHQ_AGENT_SIGAR_DEBUG=
-)
-
-if not defined RHQ_AGENT_HOME (
- cd "%RHQ_AGENT_BIN_DIR_PATH%\.."
-) else (
- cd "%RHQ_AGENT_HOME%" || (
- echo Cannot go to the RHQ_AGENT_HOME directory: %RHQ_AGENT_HOME%
- exit /B 1
- )
-)
-
-set RHQ_AGENT_HOME=%CD%
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_HOME: %RHQ_AGENT_HOME%
-
-rem ----------------------------------------------------------------------
-rem Find the Java executable and verify we have a VM available
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
- if not defined RHQ_AGENT_JAVA_HOME call :prepare_embedded_jre
-)
-
-if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
- set RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_HOME%\bin\java.exe
-)
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_HOME: %RHQ_AGENT_JAVA_HOME%
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_EXE_FILE_PATH: %RHQ_AGENT_JAVA_EXE_FILE_PATH%
-
-if not exist "%RHQ_AGENT_JAVA_EXE_FILE_PATH%" (
- echo There is no JVM available.
- echo Please set RHQ_AGENT_JAVA_HOME or RHQ_AGENT_JAVA_EXE_FILE_PATH appropriately.
- exit /B 1
-)
-
-rem ----------------------------------------------------------------------
-rem Prepare the classpath
-rem ----------------------------------------------------------------------
-
-set CLASSPATH=
-call :append_classpath "%RHQ_AGENT_HOME%\conf"
-for /R "%RHQ_AGENT_HOME%\lib" %%G in ("*.jar") do (
- call :append_classpath "%%G"
- if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
-)
-for %%G in ("%RHQ_AGENT_JAVA_HOME%\lib\tools.jar" "%RHQ_AGENT_JAVA_HOME%\..\lib\tools.jar") do (
- if exist "%%G" (
- call :append_classpath "%%G"
- if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
- goto end_classpath
- )
-)
-:end_classpath
-
-rem ----------------------------------------------------------------------
-rem Prepare the VM command line options to be passed in
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_JAVA_OPTS (
- set RHQ_AGENT_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-)
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_OPTS: %RHQ_AGENT_JAVA_OPTS%
-
-if "%RHQ_AGENT_JAVA_ENDORSED_DIRS%" == "none" (
- if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.endorsed.dirs
- goto :skip_java_endorsed_dirs
-)
-if not defined RHQ_AGENT_JAVA_ENDORSED_DIRS set RHQ_AGENT_JAVA_ENDORSED_DIRS=%RHQ_AGENT_HOME%\lib\endorsed
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_ENDORSED_DIRS: %RHQ_AGENT_JAVA_ENDORSED_DIRS%
-set _JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=%RHQ_AGENT_JAVA_ENDORSED_DIRS%"
-:skip_java_endorsed_dirs
-
-if "%RHQ_AGENT_JAVA_LIBRARY_PATH%" == "none" (
- if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.library.path
- goto :skip_java_library_path
-)
-if not defined RHQ_AGENT_JAVA_LIBRARY_PATH set RHQ_AGENT_JAVA_LIBRARY_PATH=%RHQ_AGENT_HOME%\lib
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_LIBRARY_PATH: %RHQ_AGENT_JAVA_LIBRARY_PATH%
-set _JAVA_LIBRARY_PATH_OPT="-Djava.library.path=%RHQ_AGENT_JAVA_LIBRARY_PATH%"
-:skip_java_library_path
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_ADDITIONAL_JAVA_OPTS: %RHQ_AGENT_ADDITIONAL_JAVA_OPTS%
-
-rem ----------------------------------------------------------------------
-rem Prepare the command line arguments passed to the RHQ Agent
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_CMDLINE_OPTS (
- set RHQ_AGENT_CMDLINE_OPTS=%*
-)
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_CMDLINE_OPTS: %RHQ_AGENT_CMDLINE_OPTS%
-
-rem ----------------------------------------------------------------------
-rem Execute the VM which starts the agent
-rem ----------------------------------------------------------------------
-
-if defined RHQ_AGENT_DEBUG (
- set _LOG_CONFIG=-Dlog4j.configuration=log4j-debug.xml -Di18nlog.dump-stack-traces=true
-) else (
- set _LOG_CONFIG=-Dlog4j.configuration=log4j.xml
-)
-
-rem if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so it has its own debug var
-if defined RHQ_AGENT_SIGAR_DEBUG (
- set _LOG_CONFIG=%_LOG_CONFIG% -Dsigar.nativeLogging=true
-)
-
-rem to support other agents/plugin containers, allow the caller to override the main classname
-if not defined RHQ_AGENT_MAINCLASS (
- set RHQ_AGENT_MAINCLASS=org.rhq.enterprise.agent.AgentMain
-)
-
-set CMD="%RHQ_AGENT_JAVA_EXE_FILE_PATH%" %_JAVA_ENDORSED_DIRS_OPT% %_JAVA_LIBRARY_PATH_OPT% %RHQ_AGENT_JAVA_OPTS% %RHQ_AGENT_ADDITIONAL_JAVA_OPTS% %_LOG_CONFIG% -cp "%CLASSPATH%" %RHQ_AGENT_MAINCLASS% %RHQ_AGENT_CMDLINE_OPTS%
-
-if not defined _SETENV_ONLY (
- rem log4j 1.2.8 does not create the directory for us (later versions do)
- if not exist "%RHQ_AGENT_HOME%\logs" (
- mkdir "%RHQ_AGENT_HOME%\logs"
- )
- if defined RHQ_AGENT_DEBUG (
- echo Executing the agent with this command line:
- echo %CMD%
- )
- cmd.exe /S /C "%CMD%"
-)
-
-goto :done
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that appends the first argument to CLASSPATH
-rem ----------------------------------------------------------------------
-
-:append_classpath
-set _entry=%1
-if not defined CLASSPATH (
- set CLASSPATH=%_entry:"=%
-) else (
- set CLASSPATH=%CLASSPATH%;%_entry:"=%
-)
-goto :eof
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that prepares to use the embedded JRE
-rem ----------------------------------------------------------------------
-
-:prepare_embedded_jre
-set RHQ_AGENT_JAVA_HOME=%RHQ_AGENT_HOME%\jre
-if defined RHQ_AGENT_DEBUG echo Using the embedded JRE
-if not exist "%RHQ_AGENT_JAVA_HOME%" (
- if defined RHQ_AGENT_DEBUG echo No embedded JRE found - will try to use JAVA_HOME: %JAVA_HOME%
- set RHQ_AGENT_JAVA_HOME=%JAVA_HOME%
-)
-goto :eof
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that exits this script normally
-rem ----------------------------------------------------------------------
-
-:done
-if defined RHQ_AGENT_DEBUG echo %0 done.
-if defined _SETENV_ONLY (
-endlocal & SET "RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" & SET "RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_EXE_FILE_PATH%" & SET "RHQ_AGENT_JAVA_OPTS=%RHQ_AGENT_JAVA_OPTS%" & SET "RHQ_AGENT_ADDITIONAL_JAVA_OPTS=%RHQ_AGENT_ADDITIONAL_JAVA_OPTS%" & SET "RHQ_AGENT_BIN_DIR_PATH=%RHQ_AGENT_BIN_DIR_PATH%"
-) else (
-endlocal
-)
-
-exit /B 0
+@echo off
+
+rem ===========================================================================
+rem RHQ Agent Windows Startup Script
+rem
+rem This file is used to execute the RHQ Agent on a Windows platform.
+rem Run this script with the --help option for the runtime options.
+rem
+rem Note that this script can also be used to simply set environment variables
+rem that define the agent's environment but it will not actually run the agent.
+rem Pass in _SETENV_ONLY as the first argument to this script if you want this
+rem behavior.
+rem
+rem This script is customizable by setting certain environment variables, which
+rem are described in comments in rhq-agent-env.bat. The variables can also be
+rem set via rhq-agent-env.bat, which is sourced by this script.
+rem
+rem If the embedded JRE is to be used but is not available, the fallback
+rem JRE to be used will be determined by the JAVA_HOME environment variable.
+rem ===========================================================================
+
+setlocal
+
+if "%1"=="_SETENV_ONLY" (
+ set _SETENV_ONLY=true
+) else (
+ title RHQ Agent
+)
+
+rem if debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_DEBUG%" == "false" (
+ set RHQ_AGENT_DEBUG=
+)
+
+rem ----------------------------------------------------------------------
+rem Change directory so the current directory is the Agent home.
+rem Here we assume this script is a child directory of the Agent home
+rem We also assume our custom environment script is located in the same
+rem place as this script.
+rem ----------------------------------------------------------------------
+
+set RHQ_AGENT_BIN_DIR_PATH=%~dp0
+
+if exist "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" (
+ if defined RHQ_AGENT_DEBUG echo Loading environment script: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
+ call "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" %*
+) else (
+ if defined RHQ_AGENT_DEBUG echo No environment script found at: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
+)
+
+rem if debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_DEBUG%" == "false" (
+ set RHQ_AGENT_DEBUG=
+)
+
+rem if sigar debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_SIGAR_DEBUG%" == "false" (
+ set RHQ_AGENT_SIGAR_DEBUG=
+)
+
+if not defined RHQ_AGENT_HOME (
+ cd "%RHQ_AGENT_BIN_DIR_PATH%\.."
+) else (
+ cd "%RHQ_AGENT_HOME%" || (
+ echo Cannot go to the RHQ_AGENT_HOME directory: %RHQ_AGENT_HOME%
+ exit /B 1
+ )
+)
+
+set RHQ_AGENT_HOME=%CD%
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_HOME: %RHQ_AGENT_HOME%
+
+rem ----------------------------------------------------------------------
+rem Find the Java executable and verify we have a VM available
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
+ if not defined RHQ_AGENT_JAVA_HOME call :prepare_embedded_jre
+)
+
+if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
+ set RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_HOME%\bin\java.exe
+)
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_HOME: %RHQ_AGENT_JAVA_HOME%
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_EXE_FILE_PATH: %RHQ_AGENT_JAVA_EXE_FILE_PATH%
+
+if not exist "%RHQ_AGENT_JAVA_EXE_FILE_PATH%" (
+ echo There is no JVM available.
+ echo Please set RHQ_AGENT_JAVA_HOME or RHQ_AGENT_JAVA_EXE_FILE_PATH appropriately.
+ exit /B 1
+)
+
+rem ----------------------------------------------------------------------
+rem Prepare the classpath
+rem ----------------------------------------------------------------------
+
+set CLASSPATH=
+call :append_classpath "%RHQ_AGENT_HOME%\conf"
+for /R "%RHQ_AGENT_HOME%\lib" %%G in ("*.jar") do (
+ call :append_classpath "%%G"
+ if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
+)
+for %%G in ("%RHQ_AGENT_JAVA_HOME%\lib\tools.jar" "%RHQ_AGENT_JAVA_HOME%\..\lib\tools.jar") do (
+ if exist "%%G" (
+ call :append_classpath "%%G"
+ if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
+ goto end_classpath
+ )
+)
+:end_classpath
+
+rem ----------------------------------------------------------------------
+rem Prepare the VM command line options to be passed in
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_JAVA_OPTS (
+ set RHQ_AGENT_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
+)
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_OPTS: %RHQ_AGENT_JAVA_OPTS%
+
+if "%RHQ_AGENT_JAVA_ENDORSED_DIRS%" == "none" (
+ if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.endorsed.dirs
+ goto :skip_java_endorsed_dirs
+)
+if not defined RHQ_AGENT_JAVA_ENDORSED_DIRS set RHQ_AGENT_JAVA_ENDORSED_DIRS=%RHQ_AGENT_HOME%\lib\endorsed
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_ENDORSED_DIRS: %RHQ_AGENT_JAVA_ENDORSED_DIRS%
+set _JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=%RHQ_AGENT_JAVA_ENDORSED_DIRS%"
+:skip_java_endorsed_dirs
+
+if "%RHQ_AGENT_JAVA_LIBRARY_PATH%" == "none" (
+ if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.library.path
+ goto :skip_java_library_path
+)
+if not defined RHQ_AGENT_JAVA_LIBRARY_PATH set RHQ_AGENT_JAVA_LIBRARY_PATH=%RHQ_AGENT_HOME%\lib
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_LIBRARY_PATH: %RHQ_AGENT_JAVA_LIBRARY_PATH%
+set _JAVA_LIBRARY_PATH_OPT="-Djava.library.path=%RHQ_AGENT_JAVA_LIBRARY_PATH%"
+:skip_java_library_path
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_ADDITIONAL_JAVA_OPTS: %RHQ_AGENT_ADDITIONAL_JAVA_OPTS%
+
+rem ----------------------------------------------------------------------
+rem Prepare the command line arguments passed to the RHQ Agent
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_CMDLINE_OPTS (
+ set RHQ_AGENT_CMDLINE_OPTS=%*
+)
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_CMDLINE_OPTS: %RHQ_AGENT_CMDLINE_OPTS%
+
+rem ----------------------------------------------------------------------
+rem Execute the VM which starts the agent
+rem ----------------------------------------------------------------------
+
+if defined RHQ_AGENT_DEBUG (
+ set _LOG_CONFIG=-Dlog4j.configuration=log4j-debug.xml -Di18nlog.dump-stack-traces=true
+) else (
+ set _LOG_CONFIG=-Dlog4j.configuration=log4j.xml
+)
+
+rem if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so it has its own debug var
+if defined RHQ_AGENT_SIGAR_DEBUG (
+ set _LOG_CONFIG=%_LOG_CONFIG% -Dsigar.nativeLogging=true
+)
+
+rem to support other agents/plugin containers, allow the caller to override the main classname
+if not defined RHQ_AGENT_MAINCLASS (
+ set RHQ_AGENT_MAINCLASS=org.rhq.enterprise.agent.AgentMain
+)
+
+set CMD="%RHQ_AGENT_JAVA_EXE_FILE_PATH%" %_JAVA_ENDORSED_DIRS_OPT% %_JAVA_LIBRARY_PATH_OPT% %RHQ_AGENT_JAVA_OPTS% %RHQ_AGENT_ADDITIONAL_JAVA_OPTS% %_LOG_CONFIG% -cp "%CLASSPATH%" %RHQ_AGENT_MAINCLASS% %RHQ_AGENT_CMDLINE_OPTS%
+
+if not defined _SETENV_ONLY (
+ rem log4j 1.2.8 does not create the directory for us (later versions do)
+ if not exist "%RHQ_AGENT_HOME%\logs" (
+ mkdir "%RHQ_AGENT_HOME%\logs"
+ )
+ if defined RHQ_AGENT_DEBUG (
+ echo Executing the agent with this command line:
+ echo %CMD%
+ )
+ cmd.exe /S /C "%CMD%"
+)
+
+goto :done
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that appends the first argument to CLASSPATH
+rem ----------------------------------------------------------------------
+
+:append_classpath
+set _entry=%1
+if not defined CLASSPATH (
+ set CLASSPATH=%_entry:"=%
+) else (
+ set CLASSPATH=%CLASSPATH%;%_entry:"=%
+)
+goto :eof
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that prepares to use the embedded JRE
+rem ----------------------------------------------------------------------
+
+:prepare_embedded_jre
+set RHQ_AGENT_JAVA_HOME=%RHQ_AGENT_HOME%\jre
+if defined RHQ_AGENT_DEBUG echo Using the embedded JRE
+if not exist "%RHQ_AGENT_JAVA_HOME%" (
+ if defined RHQ_AGENT_DEBUG echo No embedded JRE found - will try to use JAVA_HOME: %JAVA_HOME%
+ set RHQ_AGENT_JAVA_HOME=%JAVA_HOME%
+)
+goto :eof
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that exits this script normally
+rem ----------------------------------------------------------------------
+
+:done
+if defined RHQ_AGENT_DEBUG echo %0 done.
+if defined _SETENV_ONLY (
+endlocal & SET "RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" & SET "RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_EXE_FILE_PATH%" & SET "RHQ_AGENT_JAVA_OPTS=%RHQ_AGENT_JAVA_OPTS%" & SET "RHQ_AGENT_ADDITIONAL_JAVA_OPTS=%RHQ_AGENT_ADDITIONAL_JAVA_OPTS%" & SET "RHQ_AGENT_BIN_DIR_PATH=%RHQ_AGENT_BIN_DIR_PATH%"
+) else (
+endlocal
+)
+
+exit /B 0
commit 4673ea4fd280f1073bd92d2aed26ea34c8c23474
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 14:20:29 2012 -0500
[BZ 703557] when possible, auto-discover JVM's not exposing JMX Remoting; as part of this, include the JDK tools.jar in the Agent's classpath when it's available from the Agent's JDK (https://bugzilla.redhat.com/show_bug.cgi?id=703557)
diff --git a/modules/enterprise/agent/src/etc/rhq-agent.bat b/modules/enterprise/agent/src/etc/rhq-agent.bat
index 59b7676..fc8bdf1 100644
--- a/modules/enterprise/agent/src/etc/rhq-agent.bat
+++ b/modules/enterprise/agent/src/etc/rhq-agent.bat
@@ -1,219 +1,227 @@
-@echo off
-
-rem ===========================================================================
-rem RHQ Agent Windows Startup Script
-rem
-rem This file is used to execute the RHQ Agent on a Windows platform.
-rem Run this script with the --help option for the runtime options.
-rem
-rem Note that this script can also be used to simply set environment variables
-rem that define the agent's environment but it will not actually run the agent.
-rem Pass in _SETENV_ONLY as the first argument to this script if you want this
-rem behavior.
-rem
-rem This script is customizable by setting certain environment variables, which
-rem are described in comments in rhq-agent-env.bat. The variables can also be
-rem set via rhq-agent-env.bat, which is sourced by this script.
-rem
-rem If the embedded JRE is to be used but is not available, the fallback
-rem JRE to be used will be determined by the JAVA_HOME environment variable.
-rem ===========================================================================
-
-setlocal
-
-if "%1"=="_SETENV_ONLY" (
- set _SETENV_ONLY=true
-) else (
- title RHQ Agent
-)
-
-rem if debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_DEBUG%" == "false" (
- set RHQ_AGENT_DEBUG=
-)
-
-rem ----------------------------------------------------------------------
-rem Change directory so the current directory is the Agent home.
-rem Here we assume this script is a child directory of the Agent home
-rem We also assume our custom environment script is located in the same
-rem place as this script.
-rem ----------------------------------------------------------------------
-
-set RHQ_AGENT_BIN_DIR_PATH=%~dp0
-
-if exist "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" (
- if defined RHQ_AGENT_DEBUG echo Loading environment script: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
- call "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" %*
-) else (
- if defined RHQ_AGENT_DEBUG echo No environment script found at: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
-)
-
-rem if debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_DEBUG%" == "false" (
- set RHQ_AGENT_DEBUG=
-)
-
-rem if sigar debug variable is set, it is assumed to be on, unless its value is false
-if "%RHQ_AGENT_SIGAR_DEBUG%" == "false" (
- set RHQ_AGENT_SIGAR_DEBUG=
-)
-
-if not defined RHQ_AGENT_HOME (
- cd "%RHQ_AGENT_BIN_DIR_PATH%\.."
-) else (
- cd "%RHQ_AGENT_HOME%" || (
- echo Cannot go to the RHQ_AGENT_HOME directory: %RHQ_AGENT_HOME%
- exit /B 1
- )
-)
-
-set RHQ_AGENT_HOME=%CD%
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_HOME: %RHQ_AGENT_HOME%
-
-rem ----------------------------------------------------------------------
-rem Find the Java executable and verify we have a VM available
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
- if not defined RHQ_AGENT_JAVA_HOME call :prepare_embedded_jre
-)
-
-if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
- set RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_HOME%\bin\java.exe
-)
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_HOME: %RHQ_AGENT_JAVA_HOME%
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_EXE_FILE_PATH: %RHQ_AGENT_JAVA_EXE_FILE_PATH%
-
-if not exist "%RHQ_AGENT_JAVA_EXE_FILE_PATH%" (
- echo There is no JVM available.
- echo Please set RHQ_AGENT_JAVA_HOME or RHQ_AGENT_JAVA_EXE_FILE_PATH appropriately.
- exit /B 1
-)
-
-rem ----------------------------------------------------------------------
-rem Prepare the classpath
-rem ----------------------------------------------------------------------
-
-set CLASSPATH=
-call :append_classpath "%RHQ_AGENT_HOME%\conf"
-for /R "%RHQ_AGENT_HOME%\lib" %%G in ("*.jar") do (
- call :append_classpath "%%G"
- if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
-)
-
-rem ----------------------------------------------------------------------
-rem Prepare the VM command line options to be passed in
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_JAVA_OPTS (
- set RHQ_AGENT_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
-)
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_OPTS: %RHQ_AGENT_JAVA_OPTS%
-
-if "%RHQ_AGENT_JAVA_ENDORSED_DIRS%" == "none" (
- if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.endorsed.dirs
- goto :skip_java_endorsed_dirs
-)
-if not defined RHQ_AGENT_JAVA_ENDORSED_DIRS set RHQ_AGENT_JAVA_ENDORSED_DIRS=%RHQ_AGENT_HOME%\lib\endorsed
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_ENDORSED_DIRS: %RHQ_AGENT_JAVA_ENDORSED_DIRS%
-set _JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=%RHQ_AGENT_JAVA_ENDORSED_DIRS%"
-:skip_java_endorsed_dirs
-
-if "%RHQ_AGENT_JAVA_LIBRARY_PATH%" == "none" (
- if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.library.path
- goto :skip_java_library_path
-)
-if not defined RHQ_AGENT_JAVA_LIBRARY_PATH set RHQ_AGENT_JAVA_LIBRARY_PATH=%RHQ_AGENT_HOME%\lib
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_LIBRARY_PATH: %RHQ_AGENT_JAVA_LIBRARY_PATH%
-set _JAVA_LIBRARY_PATH_OPT="-Djava.library.path=%RHQ_AGENT_JAVA_LIBRARY_PATH%"
-:skip_java_library_path
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_ADDITIONAL_JAVA_OPTS: %RHQ_AGENT_ADDITIONAL_JAVA_OPTS%
-
-rem ----------------------------------------------------------------------
-rem Prepare the command line arguments passed to the RHQ Agent
-rem ----------------------------------------------------------------------
-
-if not defined RHQ_AGENT_CMDLINE_OPTS (
- set RHQ_AGENT_CMDLINE_OPTS=%*
-)
-
-if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_CMDLINE_OPTS: %RHQ_AGENT_CMDLINE_OPTS%
-
-rem ----------------------------------------------------------------------
-rem Execute the VM which starts the agent
-rem ----------------------------------------------------------------------
-
-if defined RHQ_AGENT_DEBUG (
- set _LOG_CONFIG=-Dlog4j.configuration=log4j-debug.xml -Di18nlog.dump-stack-traces=true
-) else (
- set _LOG_CONFIG=-Dlog4j.configuration=log4j.xml
-)
-
-rem if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so its got its own debug var
-if defined RHQ_AGENT_SIGAR_DEBUG (
- set _LOG_CONFIG=%_LOG_CONFIG% -Dsigar.nativeLogging=true
-)
-
-rem to support other agents/plugin containers, allow the caller to override the main classname
-if not defined RHQ_AGENT_MAINCLASS (
- set RHQ_AGENT_MAINCLASS=org.rhq.enterprise.agent.AgentMain
-)
-
-set CMD="%RHQ_AGENT_JAVA_EXE_FILE_PATH%" %_JAVA_ENDORSED_DIRS_OPT% %_JAVA_LIBRARY_PATH_OPT% %RHQ_AGENT_JAVA_OPTS% %RHQ_AGENT_ADDITIONAL_JAVA_OPTS% %_LOG_CONFIG% -cp "%CLASSPATH%" %RHQ_AGENT_MAINCLASS% %RHQ_AGENT_CMDLINE_OPTS%
-
-if not defined _SETENV_ONLY (
- rem log4j 1.2.8 does not create the directory for us (later versions do)
- if not exist "%RHQ_AGENT_HOME%\logs" (
- mkdir "%RHQ_AGENT_HOME%\logs"
- )
- if defined RHQ_AGENT_DEBUG (
- echo Executing the agent with this command line:
- echo %CMD%
- )
- cmd.exe /S /C "%CMD%"
-)
-
-goto :done
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that appends the first argument to CLASSPATH
-rem ----------------------------------------------------------------------
-
-:append_classpath
-set _entry=%1
-if not defined CLASSPATH (
- set CLASSPATH=%_entry:"=%
-) else (
- set CLASSPATH=%CLASSPATH%;%_entry:"=%
-)
-goto :eof
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that prepares to use the embedded JRE
-rem ----------------------------------------------------------------------
-
-:prepare_embedded_jre
-set RHQ_AGENT_JAVA_HOME=%RHQ_AGENT_HOME%\jre
-if defined RHQ_AGENT_DEBUG echo Using the embedded JRE
-if not exist "%RHQ_AGENT_JAVA_HOME%" (
- if defined RHQ_AGENT_DEBUG echo No embedded JRE found - will try to use JAVA_HOME: %JAVA_HOME%
- set RHQ_AGENT_JAVA_HOME=%JAVA_HOME%
-)
-goto :eof
-
-rem ----------------------------------------------------------------------
-rem CALL subroutine that exits this script normally
-rem ----------------------------------------------------------------------
-
-:done
-if defined RHQ_AGENT_DEBUG echo %0 done.
-if defined _SETENV_ONLY (
-endlocal & SET "RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" & SET "RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_EXE_FILE_PATH%" & SET "RHQ_AGENT_JAVA_OPTS=%RHQ_AGENT_JAVA_OPTS%" & SET "RHQ_AGENT_ADDITIONAL_JAVA_OPTS=%RHQ_AGENT_ADDITIONAL_JAVA_OPTS%" & SET "RHQ_AGENT_BIN_DIR_PATH=%RHQ_AGENT_BIN_DIR_PATH%"
-) else (
-endlocal
-)
-
-exit /B 0
+@echo off
+
+rem ===========================================================================
+rem RHQ Agent Windows Startup Script
+rem
+rem This file is used to execute the RHQ Agent on a Windows platform.
+rem Run this script with the --help option for the runtime options.
+rem
+rem Note that this script can also be used to simply set environment variables
+rem that define the agent's environment but it will not actually run the agent.
+rem Pass in _SETENV_ONLY as the first argument to this script if you want this
+rem behavior.
+rem
+rem This script is customizable by setting certain environment variables, which
+rem are described in comments in rhq-agent-env.bat. The variables can also be
+rem set via rhq-agent-env.bat, which is sourced by this script.
+rem
+rem If the embedded JRE is to be used but is not available, the fallback
+rem JRE to be used will be determined by the JAVA_HOME environment variable.
+rem ===========================================================================
+
+setlocal
+
+if "%1"=="_SETENV_ONLY" (
+ set _SETENV_ONLY=true
+) else (
+ title RHQ Agent
+)
+
+rem if debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_DEBUG%" == "false" (
+ set RHQ_AGENT_DEBUG=
+)
+
+rem ----------------------------------------------------------------------
+rem Change directory so the current directory is the Agent home.
+rem Here we assume this script is a child directory of the Agent home
+rem We also assume our custom environment script is located in the same
+rem place as this script.
+rem ----------------------------------------------------------------------
+
+set RHQ_AGENT_BIN_DIR_PATH=%~dp0
+
+if exist "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" (
+ if defined RHQ_AGENT_DEBUG echo Loading environment script: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
+ call "%RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat" %*
+) else (
+ if defined RHQ_AGENT_DEBUG echo No environment script found at: %RHQ_AGENT_BIN_DIR_PATH%\rhq-agent-env.bat
+)
+
+rem if debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_DEBUG%" == "false" (
+ set RHQ_AGENT_DEBUG=
+)
+
+rem if sigar debug variable is set, it is assumed to be on, unless its value is false
+if "%RHQ_AGENT_SIGAR_DEBUG%" == "false" (
+ set RHQ_AGENT_SIGAR_DEBUG=
+)
+
+if not defined RHQ_AGENT_HOME (
+ cd "%RHQ_AGENT_BIN_DIR_PATH%\.."
+) else (
+ cd "%RHQ_AGENT_HOME%" || (
+ echo Cannot go to the RHQ_AGENT_HOME directory: %RHQ_AGENT_HOME%
+ exit /B 1
+ )
+)
+
+set RHQ_AGENT_HOME=%CD%
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_HOME: %RHQ_AGENT_HOME%
+
+rem ----------------------------------------------------------------------
+rem Find the Java executable and verify we have a VM available
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
+ if not defined RHQ_AGENT_JAVA_HOME call :prepare_embedded_jre
+)
+
+if not defined RHQ_AGENT_JAVA_EXE_FILE_PATH (
+ set RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_HOME%\bin\java.exe
+)
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_HOME: %RHQ_AGENT_JAVA_HOME%
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_EXE_FILE_PATH: %RHQ_AGENT_JAVA_EXE_FILE_PATH%
+
+if not exist "%RHQ_AGENT_JAVA_EXE_FILE_PATH%" (
+ echo There is no JVM available.
+ echo Please set RHQ_AGENT_JAVA_HOME or RHQ_AGENT_JAVA_EXE_FILE_PATH appropriately.
+ exit /B 1
+)
+
+rem ----------------------------------------------------------------------
+rem Prepare the classpath
+rem ----------------------------------------------------------------------
+
+set CLASSPATH=
+call :append_classpath "%RHQ_AGENT_HOME%\conf"
+for /R "%RHQ_AGENT_HOME%\lib" %%G in ("*.jar") do (
+ call :append_classpath "%%G"
+ if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
+)
+for %%G in ("%RHQ_AGENT_JAVA_HOME%\lib\tools.jar" "%RHQ_AGENT_JAVA_HOME%\..\lib\tools.jar") do (
+ if exist "%%G" (
+ call :append_classpath "%%G"
+ if defined RHQ_AGENT_DEBUG echo CLASSPATH entry: %%G
+ goto end_classpath
+ )
+)
+:end_classpath
+
+rem ----------------------------------------------------------------------
+rem Prepare the VM command line options to be passed in
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_JAVA_OPTS (
+ set RHQ_AGENT_JAVA_OPTS=-Xms64m -Xmx128m -Djava.net.preferIPv4Stack=true
+)
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_OPTS: %RHQ_AGENT_JAVA_OPTS%
+
+if "%RHQ_AGENT_JAVA_ENDORSED_DIRS%" == "none" (
+ if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.endorsed.dirs
+ goto :skip_java_endorsed_dirs
+)
+if not defined RHQ_AGENT_JAVA_ENDORSED_DIRS set RHQ_AGENT_JAVA_ENDORSED_DIRS=%RHQ_AGENT_HOME%\lib\endorsed
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_ENDORSED_DIRS: %RHQ_AGENT_JAVA_ENDORSED_DIRS%
+set _JAVA_ENDORSED_DIRS_OPT="-Djava.endorsed.dirs=%RHQ_AGENT_JAVA_ENDORSED_DIRS%"
+:skip_java_endorsed_dirs
+
+if "%RHQ_AGENT_JAVA_LIBRARY_PATH%" == "none" (
+ if defined RHQ_AGENT_DEBUG echo Not explicitly setting java.library.path
+ goto :skip_java_library_path
+)
+if not defined RHQ_AGENT_JAVA_LIBRARY_PATH set RHQ_AGENT_JAVA_LIBRARY_PATH=%RHQ_AGENT_HOME%\lib
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_JAVA_LIBRARY_PATH: %RHQ_AGENT_JAVA_LIBRARY_PATH%
+set _JAVA_LIBRARY_PATH_OPT="-Djava.library.path=%RHQ_AGENT_JAVA_LIBRARY_PATH%"
+:skip_java_library_path
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_ADDITIONAL_JAVA_OPTS: %RHQ_AGENT_ADDITIONAL_JAVA_OPTS%
+
+rem ----------------------------------------------------------------------
+rem Prepare the command line arguments passed to the RHQ Agent
+rem ----------------------------------------------------------------------
+
+if not defined RHQ_AGENT_CMDLINE_OPTS (
+ set RHQ_AGENT_CMDLINE_OPTS=%*
+)
+
+if defined RHQ_AGENT_DEBUG echo RHQ_AGENT_CMDLINE_OPTS: %RHQ_AGENT_CMDLINE_OPTS%
+
+rem ----------------------------------------------------------------------
+rem Execute the VM which starts the agent
+rem ----------------------------------------------------------------------
+
+if defined RHQ_AGENT_DEBUG (
+ set _LOG_CONFIG=-Dlog4j.configuration=log4j-debug.xml -Di18nlog.dump-stack-traces=true
+) else (
+ set _LOG_CONFIG=-Dlog4j.configuration=log4j.xml
+)
+
+rem if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so it has its own debug var
+if defined RHQ_AGENT_SIGAR_DEBUG (
+ set _LOG_CONFIG=%_LOG_CONFIG% -Dsigar.nativeLogging=true
+)
+
+rem to support other agents/plugin containers, allow the caller to override the main classname
+if not defined RHQ_AGENT_MAINCLASS (
+ set RHQ_AGENT_MAINCLASS=org.rhq.enterprise.agent.AgentMain
+)
+
+set CMD="%RHQ_AGENT_JAVA_EXE_FILE_PATH%" %_JAVA_ENDORSED_DIRS_OPT% %_JAVA_LIBRARY_PATH_OPT% %RHQ_AGENT_JAVA_OPTS% %RHQ_AGENT_ADDITIONAL_JAVA_OPTS% %_LOG_CONFIG% -cp "%CLASSPATH%" %RHQ_AGENT_MAINCLASS% %RHQ_AGENT_CMDLINE_OPTS%
+
+if not defined _SETENV_ONLY (
+ rem log4j 1.2.8 does not create the directory for us (later versions do)
+ if not exist "%RHQ_AGENT_HOME%\logs" (
+ mkdir "%RHQ_AGENT_HOME%\logs"
+ )
+ if defined RHQ_AGENT_DEBUG (
+ echo Executing the agent with this command line:
+ echo %CMD%
+ )
+ cmd.exe /S /C "%CMD%"
+)
+
+goto :done
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that appends the first argument to CLASSPATH
+rem ----------------------------------------------------------------------
+
+:append_classpath
+set _entry=%1
+if not defined CLASSPATH (
+ set CLASSPATH=%_entry:"=%
+) else (
+ set CLASSPATH=%CLASSPATH%;%_entry:"=%
+)
+goto :eof
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that prepares to use the embedded JRE
+rem ----------------------------------------------------------------------
+
+:prepare_embedded_jre
+set RHQ_AGENT_JAVA_HOME=%RHQ_AGENT_HOME%\jre
+if defined RHQ_AGENT_DEBUG echo Using the embedded JRE
+if not exist "%RHQ_AGENT_JAVA_HOME%" (
+ if defined RHQ_AGENT_DEBUG echo No embedded JRE found - will try to use JAVA_HOME: %JAVA_HOME%
+ set RHQ_AGENT_JAVA_HOME=%JAVA_HOME%
+)
+goto :eof
+
+rem ----------------------------------------------------------------------
+rem CALL subroutine that exits this script normally
+rem ----------------------------------------------------------------------
+
+:done
+if defined RHQ_AGENT_DEBUG echo %0 done.
+if defined _SETENV_ONLY (
+endlocal & SET "RHQ_AGENT_HOME=%RHQ_AGENT_HOME%" & SET "RHQ_AGENT_JAVA_EXE_FILE_PATH=%RHQ_AGENT_JAVA_EXE_FILE_PATH%" & SET "RHQ_AGENT_JAVA_OPTS=%RHQ_AGENT_JAVA_OPTS%" & SET "RHQ_AGENT_ADDITIONAL_JAVA_OPTS=%RHQ_AGENT_ADDITIONAL_JAVA_OPTS%" & SET "RHQ_AGENT_BIN_DIR_PATH=%RHQ_AGENT_BIN_DIR_PATH%"
+) else (
+endlocal
+)
+
+exit /B 0
diff --git a/modules/enterprise/agent/src/etc/rhq-agent.sh b/modules/enterprise/agent/src/etc/rhq-agent.sh
index e0122bd..45b99a2 100755
--- a/modules/enterprise/agent/src/etc/rhq-agent.sh
+++ b/modules/enterprise/agent/src/etc/rhq-agent.sh
@@ -151,6 +151,13 @@ for _JAR in $_JAR_FILES ; do
fi
debug_msg "CLASSPATH entry: $_JAR"
done
+for _TOOLS_JAR in "${RHQ_AGENT_JAVA_HOME}/lib/tools.jar" "${RHQ_AGENT_JAVA_HOME}/../lib/tools.jar"; do
+ if [ -f "${_TOOLS_JAR}" ]; then
+ debug_msg "CLASSPATH entry: ${_TOOLS_JAR}"
+ CLASSPATH="${CLASSPATH}:${_TOOLS_JAR}"
+ break
+ fi
+done
# ----------------------------------------------------------------------
# Prepare the VM command line options to be passed in
@@ -236,7 +243,7 @@ if [ "x$RHQ_AGENT_DEBUG" != "x" ]; then
fi
fi
-# if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so its got its own debug var
+# if sigar debug is enabled, the log configuration is different - sigar debugging is noisy, so it has its own debug var
if [ "x$RHQ_AGENT_SIGAR_DEBUG" != "x" ]; then
if [ "$RHQ_AGENT_SIGAR_DEBUG" != "false" ]; then
_LOG_CONFIG="$_LOG_CONFIG -Dsigar.nativeLogging=true"
diff --git a/modules/plugins/jmx/pom.xml b/modules/plugins/jmx/pom.xml
index e92eb21..8780b32 100644
--- a/modules/plugins/jmx/pom.xml
+++ b/modules/plugins/jmx/pom.xml
@@ -16,11 +16,23 @@
<description>a plugin for managing a generic JMX-enabled application</description>
<dependencies>
+
<dependency>
<groupId>mc4j</groupId>
<artifactId>org-mc4j-ems</artifactId>
<!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
</dependency>
+
+ <!-- needed for the JVM Attach API. NOTE: we do not include tools.jar in the plugin jar's lib dir, because if it
+ is available at runtime, rhq-agent.sh/rhq-agent.bat will add it to the Agent's classpath. -->
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ <version>1.6.0</version>
+ <scope>system</scope>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+
</dependencies>
<build>
@@ -48,8 +60,8 @@
</execution>
</executions>
</plugin>
-</plugins>
- </build>
+ </plugins>
+ </build>
<profiles>
<profile>
@@ -146,28 +158,7 @@
</plugins>
</build>
-</profile>
- <!-- This includes the tools.jar in the system classpath to avoid the unsatisfied link error on
- tools.jar dependencies that EMS was trying to load multiple times. -->
- <profile>
- <id>default-tools.jar</id>
- <activation>
- <property>
- <name>java.vendor</name>
- <value>Sun Microsystems Inc.</value>
- </property>
- </activation>
-
- <dependencies>
- <dependency>
- <groupId>com.sun</groupId>
- <artifactId>tools</artifactId>
- <version>1.4.2</version>
- <scope>system</scope>
- <systemPath>${java.home}/../lib/tools.jar</systemPath>
- </dependency>
- </dependencies>
- </profile>
+ </profile>
<profile>
<id>dev</id>
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXDiscoveryComponent.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXDiscoveryComponent.java
index ce8631a..a61208d 100644
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXDiscoveryComponent.java
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2010 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -23,37 +23,84 @@
package org.rhq.plugins.jmx;
import java.io.File;
-import java.io.FilenameFilter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
+import org.hyperic.sigar.NetConnection;
+import org.hyperic.sigar.NetFlags;
+import org.hyperic.sigar.Sigar;
+import org.hyperic.sigar.SigarException;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.resource.ResourceUpgradeReport;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.ManualAddFacet;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-import org.rhq.core.pluginapi.inventory.ManualAddFacet;
-import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.upgrade.ResourceUpgradeContext;
+import org.rhq.core.pluginapi.upgrade.ResourceUpgradeFacet;
import org.rhq.core.system.ProcessInfo;
+import org.rhq.plugins.jmx.util.ConnectionProviderFactory;
+import org.rhq.plugins.jmx.util.JvmResourceKey;
+import org.rhq.plugins.jmx.util.JvmUtility;
+import org.rhq.plugins.jmx.util.Socket;
+
+import org.mc4j.ems.connection.EmsConnection;
+import org.mc4j.ems.connection.bean.EmsBean;
+import org.mc4j.ems.connection.bean.attribute.EmsAttribute;
+import org.mc4j.ems.connection.support.ConnectionProvider;
+import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
/**
- * This component will discover JDK 5 agents running locally that have active JSR-160 connectors defined via system
- * properties.
+ * This component will discover JVM processes that appear to be long-running (i.e. "servers"). Specifically, it will
+ * discover java processes that:
+ * <ul>
+ * <li>have enabled JMX Remoting (JSR-160) via com.sun.management.jmxremote* system properties on their command lines, or</li>
+ * <li>are Sun/Oracle-compatible java processes accessible via the com.sun.tools.attach API AND specify the
+ * org.rhq.resourceKey system property on their command lines (e.g. -Dorg.rhq.resourceKey=FOO); the attach API uses IPC
+ * under the covers, so for a process to be accessible, it either must be running as the same user as the RHQ Agent,
+ * or the Agent must be running as root<li>
+ * </ul>
+ * Some other java processes that do not meet these criteria can be manually added if they expose JMX remotely in
+ * another supported form (WebLogic, WebSphere, etc.).
*
* @author Greg Hinkle
+ * @author Ian Springer
*/
-public class JMXDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet { //, ClassLoaderFacet {
+public class JMXDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet, ResourceUpgradeFacet { //, ClassLoaderFacet {
+
private static final Log log = LogFactory.getLog(JMXDiscoveryComponent.class);
- public static final String VMID_CONFIG_PROPERTY = "vmid";
+ // our own private SIGAR
+ // TODO (ips, 01/05/12): enhance native-system API, then use that instead of using SIGAR directly
+ private static Sigar SIGAR;
+ static {
+ try {
+ SIGAR = new Sigar();
+ } catch (RuntimeException re) {
+ SIGAR = null;
+ }
+ }
public static final String COMMAND_LINE_CONFIG_PROPERTY = "commandLine";
@@ -67,120 +114,162 @@ public class JMXDiscoveryComponent implements ResourceDiscoveryComponent, Manual
public static final String ADDITIONAL_CLASSPATH_ENTRIES = "additionalClassPathEntries";
- /* Ignore certain processes that are managed by their own plugin. For example, the Tomcat plugin will
+ private static final String SYSPROP_JMXREMOTE_PORT = "com.sun.management.jmxremote.port";
+ private static final String SYSPROP_RHQ_JMXPLUGIN_PROCESS_FILTERS = "rhq.jmxplugin.process-filters";
+ public static final String SYSPROP_RHQ_RESOURCE_KEY = "org.rhq.resourceKey";
+ private static final String SYSPROP_JAVA_VERSION = "java.version";
+
+ /*
+ * Ignore certain processes that are managed by their own plugin. For example, the Tomcat plugin will
* handle Tomcat processes configured for JMX management.
*/
- private static final String[] PROCESS_FILTERS;
-
- static {
- String[] processFilters = new String[] { "catalina.startup.Bootstrap", "org.jboss.Main" };
- try {
- String env = System.getProperty("rhq.jmxplugin.process-filters");
- if (env != null) {
- processFilters = env.split(",");
- }
- } catch (Throwable t) {
- log.error("Can't determine process filters; using default... Cause: " + t);
- } finally {
- PROCESS_FILTERS = processFilters;
- }
- }
+ private static final String[] DEFAULT_PROCESS_EXCLUDES = new String[]{"org.jboss.Main", "catalina.startup.Bootstrap"};
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) {
+ Set<DiscoveredResourceDetails> discoveredResources = new LinkedHashSet<DiscoveredResourceDetails>();
+ Map<String, List<DiscoveredResourceDetails>> duplicatesByKey = new LinkedHashMap<String, List<DiscoveredResourceDetails>>();
- Set<DiscoveredResourceDetails> found = new HashSet<DiscoveredResourceDetails>();
-
- // This model of discovery is of questionable usefulness since if you restart your process you'll get a new resource
- // Works only on JDK6 and maybe some 64 bit JDK5 See JBNADM-3332.
- //
- // Map<Integer, LocalVirtualMachine> vms;
- //
- // try {
- // vms = LocalVMFinder.getManageableVirtualMachines();
- // } catch (Exception e) {
- // log.info("JMX Platform Autodiscovery only supported on JDK6 and above");
- // return null;
- // }
- //
- // if (vms != null) {
- // for (LocalVirtualMachine vm : vms.values()) {
- // // TODO: Might want to limit to vms already managed as the other kind are temporary connector addresses
- // String resourceKey = (vm.getCommandLine() != null) ? vm.getCommandLine() : vm.getConnectorAddress();
- // DiscoveredResourceDetails s = new DiscoveredResourceDetails(context.getResourceType(), resourceKey,
- // "Java VM [" + vm.getVmid() + "]", System.getProperty("java.version"), // TODO Get the vm's version
- // vm.getCommandLine(), null, null);
- //
- // Configuration configuration = s.getPluginConfiguration();
- // configuration.setNotes("Auto-discovered");
- // configuration.put(new PropertySimple(VMID_CONFIG_PROPERTY, String.valueOf(vm.getVmid())));
- // configuration.put(new PropertySimple(CONNECTOR_ADDRESS_CONFIG_PROPERTY, String.valueOf(vm
- // .getConnectorAddress())));
- // configuration
- // .put(new PropertySimple(COMMAND_LINE_CONFIG_PROPERTY, String.valueOf(vm.getCommandLine())));
- // configuration.put(new PropertySimple(CONNECTION_TYPE, LocalVMTypeDescriptor.class.getName()));
- //
- // found.add(s);
- // }
- //
- // /* GH: Disabling discovery of the internal VM... Other plugins should probably embed via the internal
- // * component above
- // * DiscoveredResourceDetails localVM = new DiscoveredResourceDetails(context.getResourceType(),
- // * "InternalVM",
- // * "Internal Java VM",
- // * System.getProperty("java.version"), "VM of
- // * plugin container", null, null); Configuration configuration = localVM.getPluginConfiguration();
- // * configuration.put(new PropertySimple(CONNECTOR_ADDRESS_CONFIG_PROPERTY, "Local Connection"));
- // * configuration.put(new PropertySimple(CONNECTION_TYPE, InternalVMTypeDescriptor.class.getName()));
- // *
- // *found.add(localVM);*/
- // }
-
- try {
- List<ProcessScanResult> processes = context.getAutoDiscoveredProcesses();
+ // Filter out JBoss, Tomcat, etc. processes, which will be represented by more specific types of Resources
+ // discovered by other plugins.
+ List<ProcessScanResult> nonExcludedProcesses = getNonExcludedJavaProcesses(context);
- for (ProcessScanResult process : processes) {
+ for (ProcessScanResult process : nonExcludedProcesses) {
+ try {
ProcessInfo processInfo = process.getProcessInfo();
- DiscoveredResourceDetails details = discoverProcess(context, processInfo);
+ DiscoveredResourceDetails details = discoverResourceDetails(context, processInfo);
if (details != null) {
- boolean isFiltered = false;
- for (String filter : PROCESS_FILTERS) {
- if (details.getResourceName().contains(filter)) {
- isFiltered = true;
- break;
+ if (discoveredResources.contains(details)) {
+ List<DiscoveredResourceDetails> duplicates = duplicatesByKey.get(details.getResourceKey());
+ if (duplicates == null) {
+ duplicates = new ArrayList<DiscoveredResourceDetails>();
+ duplicatesByKey.put(details.getResourceKey(), duplicates);
}
- }
- if (!isFiltered) {
- found.add(details);
- }
+ duplicates.add(details);
+ }
+ discoveredResources.add(details);
+ }
+ } catch (RuntimeException re) {
+ // Don't let a runtime exception for a particular ProcessInfo cause the entire discovery scan to fail.
+ if (log.isDebugEnabled()) {
+ log.debug("Error when trying to discover JVM process [" + process + "].", re);
+ } else {
+ log.warn("Error when trying to discover JVM process [" + process + "] (enable DEBUG for stack trace): " + re);
}
}
- } catch (Exception e) {
- if (log.isDebugEnabled()) {
- log.debug("Unable to complete base JMX server discovery.", e);
+ }
+
+ for (String duplicateKey : duplicatesByKey.keySet()) {
+ List<DiscoveredResourceDetails> duplicates = duplicatesByKey.get(duplicateKey);
+ log.error("Multiple Resources with the same key (" + duplicateKey
+ + ") were discovered - none will be reported to the plugin container! This most likely means that there are multiple java processes running with the same value for the "
+ + SYSPROP_RHQ_RESOURCE_KEY + " system property specified on their command lines. Here is the list of Resources: "
+ + duplicates);
+ discoveredResources.remove(duplicates.get(0));
+ }
+
+ return discoveredResources;
+ }
+
+ private List<ProcessScanResult> getNonExcludedJavaProcesses(ResourceDiscoveryContext context) {
+ // This is the list of all currently running java processes.
+ List<ProcessScanResult> javaProcesses = context.getAutoDiscoveredProcesses();
+
+ List<ProcessScanResult> nonExcludedJavaProcesses = new ArrayList<ProcessScanResult>();
+ Set<String> processExcludes = getProcessExcludes();
+ for (ProcessScanResult javaProcess : javaProcesses) {
+ if (javaProcess.getProcessInfo().equals(context.getSystemInformation().getThisProcess())) {
+ // If the process is our own process (i.e. the RHQ Agent JVM), then skip it, since the rhq-agent
+ // plugin will handle discovering that.
+ continue;
+ }
+ String[] args = javaProcess.getProcessInfo().getCommandLine();
+ StringBuilder buffer = new StringBuilder();
+ for (String arg : args) {
+ buffer.append(arg).append(" ");
+ }
+ String commandLine = buffer.toString();
+ if (!isExcluded(commandLine, processExcludes)) {
+ nonExcludedJavaProcesses.add(javaProcess);
} else {
- log.warn("Unable to complete base JMX server discovery (enable DEBUG for stack): " + e);
+ if (log.isDebugEnabled()) {
+ log.debug("Process [" + javaProcess.getProcessInfo()
+ + "] excluded since its command line contains one of the following: " + processExcludes);
+ }
+ }
+ }
+ return nonExcludedJavaProcesses;
+ }
+
+ private boolean isExcluded(String commandLine, Set<String> processExcludes) {
+ for (String processExclude : processExcludes) {
+ if (commandLine.contains(processExclude)) {
+ return true;
}
}
+ return false;
+ }
- return found;
+ protected Set<String> getProcessExcludes() {
+ Set<String> processExcludes;
+ String overrideProcessExcludes = System.getProperty(SYSPROP_RHQ_JMXPLUGIN_PROCESS_FILTERS);
+ if (overrideProcessExcludes != null) {
+ processExcludes = new HashSet<String>(Arrays.asList(overrideProcessExcludes.split(",")));
+ } else {
+ processExcludes = new HashSet<String>(Arrays.asList(DEFAULT_PROCESS_EXCLUDES));
+ }
+ return processExcludes;
}
+ // MANUAL ADD
public DiscoveredResourceDetails discoverResource(Configuration pluginConfig,
ResourceDiscoveryContext discoveryContext)
throws InvalidPluginConfigurationException {
- // TODO: Connect to the remote JVM to verify the user-specified conn props are valid, and if connecting
- // fails, throw an exception.
- String resourceKey = pluginConfig.getSimpleValue(CONNECTOR_ADDRESS_CONFIG_PROPERTY, null);
- String connectionType = pluginConfig.getSimpleValue(CONNECTION_TYPE, null);
+
+ String connectorAddress = pluginConfig.getSimpleValue(CONNECTOR_ADDRESS_CONFIG_PROPERTY, null);
+ if (connectorAddress == null) {
+ throw new InvalidPluginConfigurationException("A connector address must be specified when manually adding a JMX Server.");
+ }
+
+ ConnectionProvider connectionProvider;
+ EmsConnection connection;
+ try {
+ connectionProvider = ConnectionProviderFactory.createConnectionProvider(pluginConfig, null,
+ discoveryContext.getParentResourceContext().getTemporaryDirectory());
+ connection = connectionProvider.connect();
+ connection.loadSynchronous(false);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to connection to connector address [" + connectorAddress + "].", e);
+ }
+
+ String key = connectorAddress;
+ String name = connectorAddress;
- // TODO (ips, 09/04/09): We should connect to the remote JVM in order to obtain its version.
- String version = null;
+ String version = getJavaVersion(connection);
+ if (version == null) {
+ log.warn("Unable to determine version of JVM with connector address [" + connectorAddress + "].");
+ }
+
+ String connectionType = pluginConfig.getSimpleValue(CONNECTION_TYPE, null);
+ String description = connectionType + " JVM (" + connectorAddress + ")";
DiscoveredResourceDetails resourceDetails = new DiscoveredResourceDetails(discoveryContext.getResourceType(),
- resourceKey, "Java VM", version, connectionType + " [" + resourceKey + "]", pluginConfig, null);
+ key, name, version, description, pluginConfig, null);
return resourceDetails;
}
+ private String getJavaVersion(EmsConnection connection) {
+ String version = null;
+ EmsBean runtimeMXBean = connection.getBean(ManagementFactory.RUNTIME_MXBEAN_NAME);
+ if (runtimeMXBean != null) {
+ EmsAttribute systemPropertiesAttribute = runtimeMXBean.getAttribute("systemProperties");
+ if (systemPropertiesAttribute != null) {
+ Map<String, String> systemProperties = (Map<String, String>) systemPropertiesAttribute.getValue();
+ version = systemProperties.get("java.version");
+ }
+ }
+ return version;
+ }
+
// For now, this method is not used. This method is the ClassLoaderFacet method, but I commented
// out the fact that this class implements that interface. As of today, 7/20/2009, I'm not sure we really
// need to implement the classloader facet since EMS's ability to use additionalClasspathEntries in its
@@ -191,11 +280,10 @@ public class JMXDiscoveryComponent implements ResourceDiscoveryComponent, Manual
// be changed other than to add "implements ClassLoaderFacet" to the class definition).
// For now, since we don't want the additional overhead of calling into this method when we currently have
// no need for it, we do not implement the ClassLoaderFacet.
- public List<URL> getAdditionalClasspathUrls(ResourceDiscoveryContext context, DiscoveredResourceDetails details)
- throws Exception {
-
- List<File> jars = getAdditionalJarsFromConfig(details.getPluginConfiguration());
- if (jars == null || jars.size() == 0) {
+ public List<URL> getAdditionalClasspathUrls(ResourceDiscoveryContext<ResourceComponent<?>> context,
+ DiscoveredResourceDetails details) throws Exception {
+ List<File> jars = ConnectionProviderFactory.getAdditionalJarsFromConfig(details.getPluginConfiguration());
+ if (jars == null || jars.isEmpty()) {
return null;
}
@@ -207,113 +295,256 @@ public class JMXDiscoveryComponent implements ResourceDiscoveryComponent, Manual
return urls;
}
- protected DiscoveredResourceDetails discoverProcess(ResourceDiscoveryContext context, ProcessInfo process) {
- String portProp = "com.sun.management.jmxremote.port";
+ @Override
+ public ResourceUpgradeReport upgrade(ResourceUpgradeContext inventoriedResource) {
+ JvmResourceKey oldKey = JvmResourceKey.valueOf(inventoriedResource.getResourceKey());
+ JvmResourceKey.Type oldKeyType = oldKey.getType();
+ if (oldKeyType == JvmResourceKey.Type.Legacy || oldKeyType == JvmResourceKey.Type.JmxRemotingPort) {
+ if (!inventoriedResource.getSystemInformation().isNative()) {
+ log.warn("Cannot attempt to upgrade Resource key [" + inventoriedResource.getResourceKey()
+ + "] of JVM Resource, because this Agent is not running with native system info support (i.e. SIGAR).");
+ return null;
+ }
- String port = null;
- for (String argument : process.getCommandLine()) {
- String cmdLineArg = "-D" + portProp + "=";
- if (argument.startsWith(cmdLineArg)) {
- port = argument.substring(cmdLineArg.length());
- break;
+ Configuration pluginConfig = inventoriedResource.getPluginConfiguration();
+ String connectorAddress = pluginConfig.getSimpleValue(CONNECTOR_ADDRESS_CONFIG_PROPERTY, null);
+ JMXServiceURL jmxServiceURL;
+ try {
+ jmxServiceURL = new JMXServiceURL(connectorAddress);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Failed to parse connector address: " + connectorAddress, e);
+ }
+
+ Long pid;
+ try {
+ JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL);
+ MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
+ RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy(mbeanServerConnection,
+ ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
+ pid = getJvmPid(runtimeMXBean);
+ if (pid == null) {
+ throw new RuntimeException("Failed to determine JVM pid by parsing JVM name.");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to determine JVM pid.", e);
}
- }
- if (port == null) {
- port = process.getEnvironmentVariable(portProp);
+ List<ProcessInfo> processes = inventoriedResource.getSystemInformation().getProcesses(
+ "process|pid|match=" + pid);
+ if (processes.size() != 1) {
+ throw new IllegalStateException("Failed to find process with PID [" + pid + "].");
+ }
+ ProcessInfo process = processes.get(0);
+ String mainClassName = getJavaMainClassName(process);
+ String explicitKeyValue = getSystemPropertyValue(process, SYSPROP_RHQ_RESOURCE_KEY);
+ if (oldKeyType == JvmResourceKey.Type.Legacy || explicitKeyValue != null) {
+ // We need to upgrade the key.
+ JvmResourceKey newKey;
+ if (explicitKeyValue != null) {
+ newKey = JvmResourceKey.fromExplicitValue(mainClassName, explicitKeyValue);
+ } else {
+ newKey = JvmResourceKey.fromJmxRemotingPort(mainClassName, oldKey.getJmxRemotingPort());
+ }
+
+ ResourceUpgradeReport resourceUpgradeReport = new ResourceUpgradeReport();
+ resourceUpgradeReport.setNewResourceKey(newKey.toString());
+ return resourceUpgradeReport;
+ }
}
- DiscoveredResourceDetails details = null;
- if (port != null) {
+ return null;
+ }
- String name = "JMX Server";
- for (int i = 1; i < process.getCommandLine().length; i++) {
- String arg = process.getCommandLine()[i];
+ private static Long getJvmPid(RuntimeMXBean runtimeMXBean) {
+ Long pid;
+ String jvmName = runtimeMXBean.getName();
+ int atIndex = jvmName.indexOf('@');
+ pid = (atIndex != -1) ? Long.valueOf(jvmName.substring(0, atIndex)) : null;
+ return pid;
+ }
- if (!arg.startsWith("-")) {
- if (arg.length() <= 200) {
- name = arg;
- } else {
- // Truncate it if it's really long for a more palatable Resource name.
- name = arg.substring(arg.length() - 200);
- }
- break;
- } else if (arg.equals("-cp") || arg.equals("-classpath")) {
- // Skip the next arg - it's the classpath, and we don't want that as the name.
- i++;
+ protected DiscoveredResourceDetails discoverResourceDetails(ResourceDiscoveryContext context, ProcessInfo process) {
+ Integer jmxRemotingPort = getJmxRemotingPort(process);
+ JMXServiceURL jmxServiceURL;
+ Set<Socket> serverSockets;
+ if (jmxRemotingPort != null) {
+ // Use JMX Remoting when possible, since it doesn't require the RHQ Agent to have OS-level permissions to
+ // communicate with the remote JVM via IPC.
+ try {
+ jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.1:" + jmxRemotingPort + "/jmxrmi");
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ // If JMX Remoting is not enabled, it's required that a Resource key is explicitly specified via the org.rhq.resourceKey sysprop.
+ String keyString = getSystemPropertyValue(process, SYSPROP_RHQ_RESOURCE_KEY);
+ if (keyString == null || keyString.equals("")) {
+ serverSockets = getServerSockets(process);
+ if (!serverSockets.isEmpty()) {
+ log.info("Server JVM process [" + process.getPid() + "] with command line ["
+ + Arrays.asList(process.getCommandLine())
+ + "] cannot be discovered, because it does not specify either of the following system properties: -D"
+ + SYSPROP_JMXREMOTE_PORT + "=JMX_REMOTING_PORT, -D" + SYSPROP_RHQ_RESOURCE_KEY + "=UNIQUE_KEY");
+ return null;
}
}
- name += " (" + port + ")";
+ // Start up a JMX agent within the JVM via the Sun Attach API, and return a URL that can be used to connect
+ // to that agent.
+ // Note, this will only work if the remote JVM is Java 6 or later, and maybe some 64 bit Java 5 - see
+ // JBNADM-3332. Also, the RHQ Agent will have to be running on a JDK, not a JRE, so that we can access
+ // the JDK's tools.jar, which contains the Sun JVM Attach API classes.
+ jmxServiceURL = JvmUtility.extractJMXServiceURL(process.getPid());
+ }
- Configuration config = context.getDefaultPluginConfiguration();
- config.put(new PropertySimple(CONNECTION_TYPE,
- "org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor"));
- config.put(new PropertySimple(CONNECTOR_ADDRESS_CONFIG_PROPERTY, "service:jmx:rmi:///jndi/rmi://localhost:"
- + port + "/jmxrmi"));
- // config.put(new PropertySimple(INSTALL_URI, process.getCurrentWorkingDirectory()));
+ if (jmxServiceURL != null) {
+ log.debug("JMX service URL for process [" + process + "] is [" + jmxServiceURL + "].");
+ return buildResourceDetails(context, process, jmxServiceURL, jmxRemotingPort);
+ } else {
+ return null;
+ }
+ }
- // TODO (ips, 09/04/09): I think we should connect to the remote JVM in order to obtain its version.
- String version = null;
+ protected DiscoveredResourceDetails buildResourceDetails(ResourceDiscoveryContext context, ProcessInfo process,
+ JMXServiceURL jmxServiceURL, Integer jmxRemotingPort) {
+ JvmResourceKey key;
+ String mainClassName = getJavaMainClassName(process);
+ String value = getSystemPropertyValue(process, SYSPROP_RHQ_RESOURCE_KEY);
+ if (value != null && !value.equals("")) {
+ log.debug("Using explicitly specified Resource key: [" + value + "]...");
+ key = JvmResourceKey.fromExplicitValue(mainClassName, value);
+ } else {
+ if (jmxRemotingPort != null) {
+ log.debug("Using JMX remoting port [" + jmxRemotingPort + "] as Resource key...");
+ key = JvmResourceKey.fromJmxRemotingPort(mainClassName, jmxRemotingPort);
+ } else {
+ log.info("Process [" + process.getPid() + "] with command line [" + Arrays.asList(process.getCommandLine()) + "] cannot be discovered, because it does not specify either of the following system properties: -Dcom.sun.management.jmxremote, -D" + SYSPROP_RHQ_RESOURCE_KEY + "=UNIQUE_KEY");
+ return null;
+ }
+ }
+
+ String name = buildResourceName(key);
- details = new DiscoveredResourceDetails(context.getResourceType(), port, name, version,
- "Standalone JVM Process", config, null);
+ String version;
+ try {
+ JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL);
+ MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
+ RuntimeMXBean runtimeMXBean = ManagementFactory.newPlatformMXBeanProxy(mbeanServerConnection,
+ ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
+ version = runtimeMXBean.getSystemProperties().get(SYSPROP_JAVA_VERSION);
+ if (version == null) {
+ throw new IllegalStateException("System property " + SYSPROP_JAVA_VERSION + " is not defined.");
+ }
+ } catch (Exception e) {
+ log.error("Failed to determine JVM version.", e);
+ version = null;
}
- return details;
+ String description = "JVM, monitored via " + ((jmxRemotingPort != null) ? "JMX Remoting" : "Sun JVM Attach API");
+
+ Configuration pluginConfig = context.getDefaultPluginConfiguration();
+ pluginConfig.put(new PropertySimple(CONNECTION_TYPE, J2SE5ConnectionTypeDescriptor.class.getName()));
+ if (jmxRemotingPort != null) {
+ pluginConfig.put(new PropertySimple(CONNECTOR_ADDRESS_CONFIG_PROPERTY, jmxServiceURL));
+ }
+
+ return new DiscoveredResourceDetails(context.getResourceType(), key.toString(), name, version, description,
+ pluginConfig, process);
}
- /**
- * Examines the plugin configuration and if it defines additional classpath entries, this
- * will return a list of files that point to all the jars that need to be added to a classloader
- * to support the managed JMX resource.
- *
- * Note: this is package static scoped so the resource component can use this method.
- *
- * @param pluginConfiguration
- *
- * @return list of files pointing to additional jars; will be empty if no additional jars are to be added
- */
- static List<File> getAdditionalJarsFromConfig(Configuration pluginConfiguration) {
- List<File> jarFiles = new ArrayList<File>();
-
- // get the plugin config setting that contains comma-separated list of files/dirs to additional jars
- // if no additional classpath entries are specified, we'll return an empty list
- PropertySimple prop = pluginConfiguration.getSimple(JMXDiscoveryComponent.ADDITIONAL_CLASSPATH_ENTRIES);
- if (prop == null || prop.getStringValue() == null || prop.getStringValue().trim().length() == 0) {
- return jarFiles;
- }
- String[] paths = prop.getStringValue().trim().split(",");
- if (paths == null || paths.length == 0) {
- return jarFiles;
+ private String buildResourceName(JvmResourceKey key) {
+ StringBuilder name = new StringBuilder();
+ String mainClassName = key.getMainClassName();
+ if (mainClassName != null) {
+ if (mainClassName.length() <= 200) {
+ name.append(mainClassName);
+ } else {
+ // Truncate it if it's really long for a more palatable Resource name.
+ name.append(mainClassName.substring(mainClassName.length() - 200));
+ }
}
- // Get all additional classpath entries which can be listed as jar filenames or directories.
- // If a directory has "/*.jar" at the end, all jar files found in that directory will be added
- // as class path entries.
- final class JarFilenameFilter implements FilenameFilter {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
+ switch (key.getType()) {
+ case JmxRemotingPort:
+ name.append(':').append(key.getJmxRemotingPort()); break;
+ case Explicit:
+ name.append(' ').append(key.getExplicitValue()); break;
+ default:
+ throw new IllegalStateException("Unsupported key type: " + key.getType());
}
- for (String path : paths) {
- path = path.trim();
- if (path.length() > 0) {
- if (path.endsWith("*.jar")) {
- path = path.substring(0, path.length() - 5);
- File dir = new File(path);
- File[] jars = dir.listFiles(new JarFilenameFilter());
- if (jars != null && jars.length > 0) {
- jarFiles.addAll(Arrays.asList(jars));
+ return name.toString();
+ }
+
+ private Set<Socket> getServerSockets(ProcessInfo process) {
+ Set<Socket> serverSockets = new HashSet<Socket>();
+ if (SIGAR != null) {
+ // Only request the type of connections we are interested in - TCP and UDP listen sockets.
+ int netFlags = (NetFlags.CONN_TCP | NetFlags.CONN_UDP | NetFlags.CONN_SERVER);
+ NetConnection[] connections;
+ try {
+ connections = SIGAR.getNetConnectionList(netFlags);
+ } catch (SigarException e) {
+ log.debug("Failed to get net connections.", e);
+ connections = new NetConnection[0];
+ }
+ for (NetConnection connection : connections) {
+ if (connection.getState() == NetFlags.TCP_LISTEN) {
+ try {
+ long pid = SIGAR.getProcPort(connection.getType(), connection.getLocalPort());
+ if (pid == process.getPid()) {
+ Socket.Protocol protocol = (connection.getType() == NetFlags.CONN_UDP) ?
+ Socket.Protocol.UDP : Socket.Protocol.TCP;
+ serverSockets.add(new Socket(protocol, connection.getLocalAddress(),
+ connection.getLocalPort()));
+ }
+ } catch (SigarException e) {
+ log.debug("Failed to get pid for connection [" + connection + "].", e);
}
- } else {
- File pathFile = new File(path);
- jarFiles.add(pathFile);
}
}
}
+ return serverSockets;
+ }
- return jarFiles;
+ protected String getJavaMainClassName(ProcessInfo process) {
+ String className = null;
+ for (int i = 1; i < process.getCommandLine().length; i++) {
+ String arg = process.getCommandLine()[i];
+
+ if (!arg.startsWith("-")) {
+ className = arg;
+ break;
+ } else if (arg.equals("-cp") || arg.equals("-classpath")) {
+ // The next arg is the classpath - skip it.
+ i++;
+ }
+ }
+ return className;
}
+
+ protected Integer getJmxRemotingPort(ProcessInfo process) {
+ String value = getSystemPropertyValue(process, SYSPROP_JMXREMOTE_PORT);
+ if (value != null) {
+ try {
+ return Integer.valueOf(value);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ protected String getSystemPropertyValue(ProcessInfo process, String systemPropertyName) {
+ for (String argument : process.getCommandLine()) {
+ String prefix = "-D" + systemPropertyName + "=";
+ if (argument.startsWith(prefix)) {
+ return argument.substring(prefix.length());
+ }
+ }
+ return null;
+ }
+
+
}
\ No newline at end of file
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXServerComponent.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXServerComponent.java
index 1f77f48..a5a7a13 100644
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXServerComponent.java
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/JMXServerComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -22,30 +22,17 @@
*/
package org.rhq.plugins.jmx;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.mc4j.ems.connection.ConnectionFactory;
+
import org.mc4j.ems.connection.EmsConnection;
-import org.mc4j.ems.connection.local.LocalVMFinder;
-import org.mc4j.ems.connection.local.LocalVirtualMachine;
-import org.mc4j.ems.connection.settings.ConnectionSettings;
import org.mc4j.ems.connection.support.ConnectionProvider;
-import org.mc4j.ems.connection.support.metadata.ConnectionTypeDescriptor;
-import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
-import org.mc4j.ems.connection.support.metadata.LocalVMTypeDescriptor;
import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.measurement.AvailabilityType;
-import org.rhq.core.domain.resource.Resource;
-import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.ResourceComponent;
import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.plugins.jmx.util.ConnectionProviderFactory;
/**
* The generic JMX server component used to create and cache a connection to a local or
@@ -61,124 +48,50 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
* @author John Mazzitelli
*/
public class JMXServerComponent<T extends ResourceComponent<?>> implements JMXComponent<T> {
+
private static Log log = LogFactory.getLog(JMXServerComponent.class);
private EmsConnection connection;
private ConnectionProvider connectionProvider;
/**
- * Access to this is deprecated, use #getResourceContext() instead.
+ * The context of a component that is started. Note, other classes should use #getResourceContext(), rather than
+ * this field.
*/
ResourceContext context;
public void start(ResourceContext context) throws Exception {
this.context = context;
- log.info("Starting connection to JMX Server " + context.getResourceKey());
+ log.debug("Starting connection to " + context.getResourceType() + "[" + context.getResourceKey() + "]...");
+ // If connecting to the EMS fails, log a warning but still succeed in starting. getAvailablity() will keep
+ // trying to connect each time it is called.
try {
internalStart();
} catch (Exception e) {
- log.warn("JMX Plugin connection failure", e);
- // The new model is to always succeed in starting, but warn about the errors (we only do this the first request)
- /*throw new Exception("Unable to connect to Java VM ["
- + configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY).getStringValue()
- + "]", e);*/
+ log.warn("Failed to connect to " + context.getResourceType() + "[" + context.getResourceKey() + "].", e);
+
}
if (connection == null) {
- log.warn("Unable to connect to JMX Server " + context.getResourceKey());
+ log.warn("Unable to connect to " + context.getResourceType() + "[" + context.getResourceKey() + "].");
}
}
protected void internalStart() throws Exception {
- Configuration configuration = context.getPluginConfiguration();
-
- String connectionTypeDescriptorClass = configuration.getSimple(JMXDiscoveryComponent.CONNECTION_TYPE)
+ Configuration pluginConfig = context.getPluginConfiguration();
+ String connectionTypeDescriptorClassName = pluginConfig.getSimple(JMXDiscoveryComponent.CONNECTION_TYPE)
.getStringValue();
-
- if (LocalVMTypeDescriptor.class.getName().equals(connectionTypeDescriptorClass)) {
- String commandLine = configuration.getSimple(JMXDiscoveryComponent.COMMAND_LINE_CONFIG_PROPERTY)
- .getStringValue();
-
- Map<Integer, LocalVirtualMachine> vms = LocalVMFinder.getManageableVirtualMachines();
- if (vms != null) {
- for (LocalVirtualMachine vm : vms.values()) {
- if (vm.getCommandLine().equals(commandLine)) {
- connectLocal(vm.getVmid());
- }
- }
- }
- } else if (JMXDiscoveryComponent.PARENT_TYPE.equals(connectionTypeDescriptorClass)) {
- // We're embedded in another jmx server component without jmxremoting set so just use the parent's connection
+ if (JMXDiscoveryComponent.PARENT_TYPE.equals(connectionTypeDescriptorClassName)) {
+ // Our parent is itself a JMX component, so just reuse its connection.
this.connection = ((JMXComponent) context.getParentResourceComponent()).getEmsConnection();
this.connectionProvider = this.connection.getConnectionProvider();
- } else if (J2SE5ConnectionTypeDescriptor.class.getName().equals(connectionTypeDescriptorClass)) {
- // We're embedded in a J2SE VM with jmxremote defined (e.g. for jconsole usage)
- String principal = null;
- String credentials = null;
- PropertySimple o = configuration.getSimple(JMXComponent.PRINCIPAL_CONFIG_PROP);
- if (o != null) {
- principal = o.getStringValue();
- }
- o = configuration.getSimple(JMXComponent.CREDENTIALS_CONFIG_PROP);
- if (o != null) {
- credentials = o.getStringValue();
- }
-
- ConnectionSettings settings = new ConnectionSettings();
- J2SE5ConnectionTypeDescriptor desc = new J2SE5ConnectionTypeDescriptor();
- settings.setConnectionType(desc);
- settings.setServerUrl(configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY)
- .getStringValue());
- if (principal != null) {
- settings.setPrincipal(principal);
- }
- if (credentials != null) {
- settings.setCredentials(credentials);
- }
-
- prepareConnection(settings);
-
} else {
- // This can handle internal connections (within the same vm as the plugin container) as well as
- // any remote connections
- ConnectionSettings settings = new ConnectionSettings();
-
- String principal = null;
- String credentials = null;
- PropertySimple o = configuration.getSimple(JMXComponent.PRINCIPAL_CONFIG_PROP);
- if (o != null) {
- principal = o.getStringValue();
- }
- o = configuration.getSimple(JMXComponent.CREDENTIALS_CONFIG_PROP);
- if (o != null) {
- credentials = o.getStringValue();
- }
-
- settings.initializeConnectionType((ConnectionTypeDescriptor) Class.forName(connectionTypeDescriptorClass)
- .newInstance());
-
- settings.setConnectionType((ConnectionTypeDescriptor) Class.forName(connectionTypeDescriptorClass)
- .newInstance());
- settings.setServerUrl(configuration.getSimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY)
- .getStringValue());
-
- String installPath = configuration.getSimpleValue(JMXDiscoveryComponent.INSTALL_URI, null);
- if (installPath != null) {
- settings.setLibraryURI(configuration.getSimple(JMXDiscoveryComponent.INSTALL_URI).getStringValue());
- }
-
- if (principal != null) {
- settings.setPrincipal(principal);
- }
- if (credentials != null) {
- settings.setCredentials(credentials);
- }
- prepareConnection(settings);
+ this.connectionProvider = ConnectionProviderFactory.createConnectionProvider(pluginConfig,
+ this.context.getNativeProcess(), this.context.getTemporaryDirectory());
+ this.connection = this.connectionProvider.connect();
+ this.connection.loadSynchronous(false);
}
-
- this.connection.loadSynchronous(false);
-
}
public void stop() {
@@ -192,28 +105,6 @@ public class JMXServerComponent<T extends ResourceComponent<?>> implements JMXCo
}
}
- protected void connectLocal(int vmid) {
- // TODO GH: Refactor ems to also accept the vm itself
- ConnectionSettings settings = new ConnectionSettings();
- settings.setConnectionType(new LocalVMTypeDescriptor());
- settings.setServerUrl(String.valueOf(vmid));
- prepareConnection(settings);
- }
-
- protected void prepareConnection(ConnectionSettings settings) {
- settings.getControlProperties().setProperty(ConnectionFactory.COPY_JARS_TO_TEMP, String.valueOf(Boolean.TRUE));
- settings.getControlProperties().setProperty(ConnectionFactory.JAR_TEMP_DIR,
- this.context.getTemporaryDirectory().getAbsolutePath());
-
- addAdditionalJarsToConnectionSettings(settings);
-
- ConnectionFactory cf = new ConnectionFactory();
- cf.discoverServerClasses(settings);
-
- this.connectionProvider = cf.getConnectionProvider(settings);
- this.connection = this.connectionProvider.connect();
- }
-
public EmsConnection getEmsConnection() {
return this.connection;
}
@@ -223,8 +114,8 @@ public class JMXServerComponent<T extends ResourceComponent<?>> implements JMXCo
try {
internalStart();
} catch (Exception e) {
- log.debug("Still unable to reconnect resource: " + context.getResourceKey() + " due to error: "
- + e.getMessage());
+ log.debug("Still unable to reconnect to " + context.getResourceType() + "[" + context.getResourceKey()
+ + "] due to error: " + e);
}
}
@@ -236,32 +127,4 @@ public class JMXServerComponent<T extends ResourceComponent<?>> implements JMXCo
return this.context;
}
- public List<Resource> discoverServices(ResourceType type, Configuration defaultPluginConfiguration) {
- defaultPluginConfiguration.getSimple("objectName").getStringValue();
-
- return null;
- }
-
- private void addAdditionalJarsToConnectionSettings(ConnectionSettings settings) {
- // get the additional jars from the config
- Configuration pluginConfiguration = getResourceContext().getPluginConfiguration();
- List<File> additionalEntries = JMXDiscoveryComponent.getAdditionalJarsFromConfig(pluginConfiguration);
- if (additionalEntries == null || additionalEntries.size() == 0) {
- return; // nothing to do, there are no additional entries to add
- }
-
- // get the setting's current list of classpath entries - we are going to add to these
- List<File> settingsEntries = settings.getClassPathEntries();
- if (settingsEntries == null) {
- settingsEntries = new ArrayList<File>();
- }
-
- // append the additional entries to the end of the setting's current entries
- settingsEntries.addAll(additionalEntries);
-
- // now that we've appended our additional jars, tell the connection settings about the new list
- settings.setClassPathEntries(settingsEntries);
-
- return;
- }
}
\ No newline at end of file
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ConnectionProviderFactory.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ConnectionProviderFactory.java
new file mode 100644
index 0000000..5c29673
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ConnectionProviderFactory.java
@@ -0,0 +1,218 @@
+package org.rhq.plugins.jmx.util;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.system.ProcessInfo;
+import org.rhq.plugins.jmx.JMXComponent;
+import org.rhq.plugins.jmx.JMXDiscoveryComponent;
+
+import org.mc4j.ems.connection.ConnectionFactory;
+import org.mc4j.ems.connection.local.LocalVMFinder;
+import org.mc4j.ems.connection.local.LocalVirtualMachine;
+import org.mc4j.ems.connection.settings.ConnectionSettings;
+import org.mc4j.ems.connection.support.ConnectionProvider;
+import org.mc4j.ems.connection.support.metadata.ConnectionTypeDescriptor;
+import org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor;
+import org.mc4j.ems.connection.support.metadata.LocalVMTypeDescriptor;
+
+/**
+ * A factory that can construct an EMS {@link ConnectionProvider} for a JMX Server Resource from that Resource's plugin
+ * configuration.
+ *
+ * @author Ian Springer
+ */
+public class ConnectionProviderFactory {
+
+ public static ConnectionProvider createConnectionProvider(Configuration pluginConfig, ProcessInfo process,
+ File tempDir) throws Exception {
+ String connectionTypeDescriptorClassName = pluginConfig.getSimple(JMXDiscoveryComponent.CONNECTION_TYPE)
+ .getStringValue();
+
+ Class<?> connectionTypeDescriptorClass;
+ try {
+ connectionTypeDescriptorClass = Class.forName(connectionTypeDescriptorClassName);
+ } catch (ClassNotFoundException e) {
+ throw new InvalidPluginConfigurationException("Invalid connection type - class [" + connectionTypeDescriptorClassName
+ + "] not found.");
+ }
+ if (!(ConnectionTypeDescriptor.class.isAssignableFrom(connectionTypeDescriptorClass))) {
+ throw new InvalidPluginConfigurationException("Invalid connection type - class [" + connectionTypeDescriptorClassName
+ + "] does not implement the " + ConnectionTypeDescriptor.class.getName() + " interface.");
+ }
+ ConnectionTypeDescriptor connectionTypeDescriptor;
+ try {
+ connectionTypeDescriptor = (ConnectionTypeDescriptor) connectionTypeDescriptorClass.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to instantiate connection type descriptor of type [" + connectionTypeDescriptorClassName + "].", e);
+ }
+
+ ConnectionSettings settings = new ConnectionSettings();
+ settings.initializeConnectionType(connectionTypeDescriptor);
+
+ // Set principal and credentials.
+ String principal = pluginConfig.getSimpleValue(JMXComponent.PRINCIPAL_CONFIG_PROP, null);
+ settings.setPrincipal(principal);
+ String credentials = pluginConfig.getSimpleValue(JMXComponent.CREDENTIALS_CONFIG_PROP, null);
+ settings.setCredentials(credentials);
+
+ if (connectionTypeDescriptor instanceof LocalVMTypeDescriptor) {
+ // NOTE (ips, 01/19/12): This is not very reliable for long-term management of a JVM, since it uses the
+ // command line from the time the JVM was originally discovered, which may have changed.
+ String commandLine = pluginConfig.getSimpleValue(JMXDiscoveryComponent.COMMAND_LINE_CONFIG_PROPERTY, null);
+ if (commandLine == null) {
+ throw new InvalidPluginConfigurationException("A command line is required for the "
+ + connectionTypeDescriptorClassName + " connection type.");
+ }
+
+ Map<Integer, LocalVirtualMachine> vms = LocalVMFinder.getManageableVirtualMachines();
+ LocalVirtualMachine targetVm = null;
+ if (vms != null) {
+ for (LocalVirtualMachine vm : vms.values()) {
+ if (vm.getCommandLine().equals(commandLine)) {
+ targetVm = vm;
+ break;
+ }
+ }
+ }
+ if (targetVm == null) {
+ // This could just be because the JVM is not currently running.
+ throw new Exception("JVM with command line [" + commandLine + "] not found.");
+ }
+ String vmId = String.valueOf(targetVm.getVmid());
+ settings.setServerUrl(vmId);
+ } else if (connectionTypeDescriptor instanceof J2SE5ConnectionTypeDescriptor) {
+ // Connect via JMX Remoting, using the JVM Attach API to start up a JMX Remoting Agent if necessary.
+ String jmxConnectorAddress = getJmxConnectorAddress(pluginConfig, process);
+ settings.setServerUrl(jmxConnectorAddress);
+ } else {
+ // Handle internal connections (InternalVMTypeDescriptor) (i.e. the RHQ plugin container's own JVM), as
+ // well as miscellaneous types of remote connections - WebSphere, WebLogic, etc.
+ String connectorAddress = pluginConfig.getSimpleValue(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY,
+ null);
+ if (connectorAddress == null) {
+ throw new InvalidPluginConfigurationException("A connector address is required for the "
+ + connectionTypeDescriptorClassName + " connection type.");
+ }
+ settings.setServerUrl(connectorAddress);
+ String installURI = pluginConfig.getSimpleValue(JMXDiscoveryComponent.INSTALL_URI, null);
+ settings.setLibraryURI(installURI);
+ }
+
+ addAdditionalJarsToConnectionSettings(settings, pluginConfig);
+
+ return createConnectionProvider(settings, tempDir);
+ }
+
+ private static ConnectionProvider createConnectionProvider(ConnectionSettings settings, File tempDir) {
+ settings.getControlProperties().setProperty(ConnectionFactory.COPY_JARS_TO_TEMP, String.valueOf(Boolean.TRUE));
+ settings.getControlProperties().setProperty(ConnectionFactory.JAR_TEMP_DIR,
+ tempDir.getAbsolutePath());
+
+ ConnectionFactory connectionFactory = new ConnectionFactory();
+ connectionFactory.discoverServerClasses(settings);
+
+ return connectionFactory.getConnectionProvider(settings);
+ }
+
+ private static void addAdditionalJarsToConnectionSettings(ConnectionSettings settings, Configuration pluginConfig) {
+
+ List<File> additionalEntries = getAdditionalJarsFromConfig(pluginConfig);
+ if (additionalEntries == null || additionalEntries.size() == 0) {
+ return; // nothing to do, there are no additional entries to add
+ }
+
+ // get the setting's current list of classpath entries - we are going to add to these
+ List<File> settingsEntries = settings.getClassPathEntries();
+ if (settingsEntries == null) {
+ settingsEntries = new ArrayList<File>();
+ }
+
+ // append the additional entries to the end of the setting's current entries
+ settingsEntries.addAll(additionalEntries);
+
+ // now that we've appended our additional jars, tell the connection settings about the new list
+ settings.setClassPathEntries(settingsEntries);
+ }
+
+ private static String getJmxConnectorAddress(Configuration pluginConfig, ProcessInfo process) throws Exception {
+ String connectorAddress = pluginConfig.getSimpleValue(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY,
+ null);
+ if (connectorAddress == null) {
+ // No JMX connector address defined - try to connect via Attach API.
+ if (process == null) {
+ throw new Exception("Could not find java process for JVM.");
+ }
+ JMXServiceURL jmxServiceURL = JvmUtility.extractJMXServiceURL(process.getPid());
+ if (jmxServiceURL == null) {
+ throw new Exception("Could not obtain JMX service URL via Attach API for JVM [" + process + "].");
+ }
+ connectorAddress = jmxServiceURL.toString();
+ }
+ return connectorAddress;
+ }
+
+ /**
+ * Examines the plugin configuration and if it defines additional classpath entries, this
+ * will return a list of files that point to all the jars that need to be added to a classloader
+ * to support the managed JMX resource.
+ *
+ * Note: this is package static scoped so the resource component can use this method.
+ *
+ * @param pluginConfiguration
+ *
+ * @return list of files pointing to additional jars; will be empty if no additional jars are to be added
+ */
+ public static List<File> getAdditionalJarsFromConfig(Configuration pluginConfiguration) {
+ List<File> jarFiles = new ArrayList<File>();
+
+ // get the plugin config setting that contains comma-separated list of files/dirs to additional jars
+ // if no additional classpath entries are specified, we'll return an empty list
+ PropertySimple prop = pluginConfiguration.getSimple(JMXDiscoveryComponent.ADDITIONAL_CLASSPATH_ENTRIES);
+ if (prop == null || prop.getStringValue() == null || prop.getStringValue().trim().length() == 0) {
+ return jarFiles;
+ }
+ String[] paths = prop.getStringValue().trim().split(",");
+ if (paths == null || paths.length == 0) {
+ return jarFiles;
+ }
+
+ // Get all additional classpath entries which can be listed as jar file names or directories.
+ // If a directory has ".jar" at the end, all jar files found in that directory will be added
+ // as class path entries.
+ final class JarFilenameFilter implements FilenameFilter {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar");
+ }
+ }
+
+ for (String path : paths) {
+ path = path.trim();
+ if (path.length() > 0) {
+ if (path.endsWith("*.jar")) {
+ path = path.substring(0, path.length() - 5);
+ File dir = new File(path);
+ File[] jars = dir.listFiles(new JarFilenameFilter());
+ if (jars != null && jars.length > 0) {
+ jarFiles.addAll(Arrays.asList(jars));
+ }
+ } else {
+ File pathFile = new File(path);
+ jarFiles.add(pathFile);
+ }
+ }
+ }
+
+ return jarFiles;
+ }
+
+}
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmResourceKey.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmResourceKey.java
new file mode 100644
index 0000000..70053cb
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmResourceKey.java
@@ -0,0 +1,179 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.plugins.jmx.util;
+
+/**
+ * @author Ian Springer
+ */
+public class JvmResourceKey {
+
+ private String mainClassName;
+ private String explicitValue;
+ private Integer jmxRemotingPort;
+ private String connectorAddress;
+ private transient Type type;
+
+ public static JvmResourceKey fromExplicitValue(String mainClassName, String explicitValue) {
+ JvmResourceKey instance = new JvmResourceKey(mainClassName);
+ instance.explicitValue = explicitValue;
+ instance.type = Type.Explicit;
+ return instance;
+ }
+
+ public static JvmResourceKey fromJmxRemotingPort(String mainClassName, int jmxRemotingPort) {
+ JvmResourceKey instance = new JvmResourceKey(mainClassName);
+ instance.jmxRemotingPort = jmxRemotingPort;
+ instance.type = (mainClassName != null) ? Type.JmxRemotingPort : Type.Legacy;
+ return instance;
+ }
+
+ public static JvmResourceKey fromConnectorAddress(String connectorAddress) {
+ JvmResourceKey instance = new JvmResourceKey(null);
+ instance.connectorAddress = connectorAddress;
+ instance.type = Type.ConnectorAddress;
+ return instance;
+ }
+
+ public static JvmResourceKey valueOf(String string) {
+ JvmResourceKey instance;
+ if (string.contains("{") && string.endsWith("}")) {
+ String mainClassName = string.substring(0, string.indexOf('{'));
+ String explicitValue = string.substring(string.indexOf('{') + 1, string.length() - 1);
+ instance = JvmResourceKey.fromExplicitValue(mainClassName, explicitValue);
+ } else if (string.contains("(") && string.endsWith(")")) {
+ String mainClassName = string.substring(0, string.indexOf('('));
+ String value = string.substring(string.indexOf('(') + 1, string.length() - 1);
+ int jmxRemotingPort = Integer.parseInt(value);
+ instance = JvmResourceKey.fromJmxRemotingPort(mainClassName, jmxRemotingPort);
+ } else {
+
+ try {
+ int jmxRemotingPort = Integer.parseInt(string);
+ // It's a legacy key, e.g. "9999".
+ instance = JvmResourceKey.fromJmxRemotingPort(null, jmxRemotingPort);
+ } catch (NumberFormatException e) {
+ // At this point, assume it's a connector address, e.g.
+ // "service:jmx:iiop://127.0.0.1:7001/jndi/weblogic.management.mbeanservers.runtime".
+ instance = JvmResourceKey.fromConnectorAddress(string);
+ }
+ }
+ return instance;
+ }
+
+ public String getMainClassName() {
+ return mainClassName;
+ }
+
+ public String getExplicitValue() {
+ return explicitValue;
+ }
+
+ public Integer getJmxRemotingPort() {
+ return jmxRemotingPort;
+ }
+
+ public String getConnectorAddress() {
+ return connectorAddress;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ JvmResourceKey that = (JvmResourceKey) o;
+
+ if (connectorAddress != null ? !connectorAddress.equals(that.connectorAddress) : that.connectorAddress != null)
+ return false;
+ if (explicitValue != null ? !explicitValue.equals(that.explicitValue) : that.explicitValue != null)
+ return false;
+ if (jmxRemotingPort != null ? !jmxRemotingPort.equals(that.jmxRemotingPort) : that.jmxRemotingPort != null)
+ return false;
+ if (mainClassName != null ? !mainClassName.equals(that.mainClassName) : that.mainClassName != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mainClassName != null ? mainClassName.hashCode() : 0;
+ result = 31 * result + (explicitValue != null ? explicitValue.hashCode() : 0);
+ result = 31 * result + (jmxRemotingPort != null ? jmxRemotingPort.hashCode() : 0);
+ result = 31 * result + (connectorAddress != null ? connectorAddress.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ String string;
+ switch (this.type) {
+ case Legacy:
+ string = this.jmxRemotingPort.toString();
+ break;
+ case ConnectorAddress:
+ string = this.connectorAddress;
+ break;
+ case JmxRemotingPort:
+ string = this.mainClassName + "(" + this.jmxRemotingPort + ")";
+ break;
+ case Explicit:
+ string = this.mainClassName + "{" + this.explicitValue + "}";
+ break;
+ default:
+ throw new IllegalStateException("Unsupported key type: " + this.type);
+ }
+ return string;
+ }
+
+ public enum Type {
+ /**
+ * The legacy format is a simple integer representing the JVM's JMX remoting port, e.g. "9999"
+ */
+ Legacy,
+ /**
+ * Manually added JVM's use the JMX connector address as the key, e.g.
+ * "service:jmx:iiop://127.0.0.1:7001/jndi/weblogic.management.mbeanservers.runtime"
+ */
+ ConnectorAddress,
+ /**
+ * The successor of the legacy format; includes the main class name in addition to the JMX remoting port,
+ * e.g. "org.example.Main(9999)"
+ */
+ JmxRemotingPort,
+ /**
+ * This format is used when a key is explicitly specified on the JVM's command line via the org.rhq.resourceKey
+ * sysprop; the main class name is also included, e.g. "org.example.Main{foo}"
+ */
+ Explicit
+ }
+
+ private JvmResourceKey(String mainClassName) {
+ this.mainClassName = mainClassName;
+ }
+
+}
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmUtility.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmUtility.java
new file mode 100644
index 0000000..c4c93b3
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/JvmUtility.java
@@ -0,0 +1,118 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.plugins.jmx.util;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.management.remote.JMXServiceURL;
+
+import com.sun.tools.attach.VirtualMachine;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.rhq.plugins.jmx.MBeanResourceComponent;
+
+/**
+ * @author Ian Springer
+ */
+public class JvmUtility {
+
+ private static final Log LOG = LogFactory.getLog(MBeanResourceComponent.class);
+
+ private static final String AGENT_PROP_JMXREMOTE_LOCAL_CONNECTOR_ADDRESS =
+ "com.sun.management.jmxremote.localConnectorAddress";
+
+ private static boolean attachApiAvailable;
+
+ static {
+ try {
+ Class.forName("com.sun.tools.attach.VirtualMachine");
+ attachApiAvailable = true;
+ } catch (ClassNotFoundException e) {
+ LOG.warn("JDK tools.jar not found on system classpath - cannot discover JVMs using Sun JVM Attach API; "
+ + "to fix this, run the RHQ Agent on a JDK, rather than a JRE.");
+ }
+ }
+
+ /**
+ * TODO
+ *
+ * @param pid the process ID of a JVM (java*) process
+ *
+ * @return
+ *
+ * @throws Exception
+ */
+ public static JMXServiceURL extractJMXServiceURL(long pid) {
+ if (!attachApiAvailable) {
+ LOG.debug("Returning null since the Attach API is not available...");
+ return null;
+ }
+ LOG.debug("Attaching to JVM for java process with PID [" + pid + "]...");
+ JMXServiceURL url;
+ try {
+ VirtualMachine vm = VirtualMachine.attach(String.valueOf(pid));
+ LOG.debug("Attached to JVM [" + vm + "].");
+
+ String jmxConnectorAddress = vm.getAgentProperties().getProperty(AGENT_PROP_JMXREMOTE_LOCAL_CONNECTOR_ADDRESS);
+ LOG.debug("Connector address for JVM [" + vm + "] is [" + jmxConnectorAddress + "].");
+ if (jmxConnectorAddress == null) {
+ // java.home always points to the jre dir (e.g. /usr/java/default/jre).
+ String jreDir = vm.getSystemProperties().getProperty("java.home");
+ // management-agent.jar is included with the v6 JRE, so we can rely on it always being there.
+ File jmxAgentJarFile = new File(jreDir, "lib/management-agent.jar");
+ String jmxAgentJar = jmxAgentJarFile.getCanonicalPath();
+ try {
+ vm.loadAgent(jmxAgentJar);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load JVM agent from [" + jmxAgentJar + "].", e);
+ }
+
+ // JMX agent is started - get the connector address.
+ LOG.debug("JMX agent started - getting the connector address...");
+ jmxConnectorAddress = vm.getAgentProperties().getProperty(AGENT_PROP_JMXREMOTE_LOCAL_CONNECTOR_ADDRESS);
+ if (jmxConnectorAddress == null) {
+ throw new RuntimeException("Failed to determine JMX connector address.");
+ }
+ }
+
+ try {
+ vm.detach();
+ } catch (Exception e) {
+ // We already succeeded in obtaining the connector address, so just log this, rather than throwing an exception.
+ LOG.error("Failed to detach from JVM [" + vm + "].", e);
+ }
+
+ url = new JMXServiceURL(jmxConnectorAddress);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to extract JMX service URL for process with PID [" + pid + "].", e);
+ }
+
+ LOG.debug("JMX service URL for java process with PID [" + pid + "]: " + url);
+ return url;
+ }
+
+ private JvmUtility() {
+ }
+
+}
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/Socket.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/Socket.java
new file mode 100644
index 0000000..142cf1c
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/Socket.java
@@ -0,0 +1,120 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2011-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.rhq.plugins.jmx.util;
+
+/**
+ * @author Ian Springer
+ */
+public class Socket implements Comparable<Socket> {
+
+ private static final String STRING_DELIMITER = "/";
+
+ private Protocol protocol;
+ private String host; // either an IP address or a host name
+ private long port;
+
+ public static Socket valueOf(String string) {
+ String[] values = string.split(STRING_DELIMITER);
+ Protocol protocol = Protocol.valueOf(values[0]);
+ String host = values[1];
+ long port = Long.valueOf(values[2]);
+
+ return new Socket(protocol, host, port);
+ }
+
+ public Socket(Protocol protocol, String host, long port) {
+ if (protocol == null) {
+ throw new IllegalArgumentException("protocol must be non-null.");
+ }
+ if (host == null) {
+ throw new IllegalArgumentException("host must be non-null.");
+ }
+ if (port < 0 || port > 65535) {
+ throw new IllegalArgumentException("invalid port: " + port);
+ }
+
+ this.protocol = protocol;
+ this.host = host;
+ this.port = port;
+ }
+
+ public Protocol getProtocol() {
+ return protocol;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public long getPort() {
+ return port;
+ }
+
+ public enum Protocol { TCP, UDP }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Socket that = (Socket) o;
+
+ if (port != that.port) return false;
+ if (!host.equals(that.host)) return false;
+ if (protocol != that.protocol) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = protocol.hashCode();
+ result = 31 * result + host.hashCode();
+ result = 31 * result + (int) (port ^ (port >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return this.protocol + STRING_DELIMITER + this.host + STRING_DELIMITER + this.port;
+ }
+
+ @Override
+ public int compareTo(Socket that) {
+ if (this == that) {
+ return 0;
+ }
+
+ int result = this.protocol.compareTo(that.protocol);
+ if (result == 0) {
+ result = this.host.compareTo(that.host);
+ if (result == 0) {
+ result = Long.valueOf(this.port).compareTo(that.port);
+
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/JMXPluginTest.java b/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/JMXPluginTest.java
index 791a578..ee172ba 100644
--- a/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/JMXPluginTest.java
+++ b/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/JMXPluginTest.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -28,13 +28,22 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.util.ArrayList;
+import java.util.Arrays;
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.domain.resource.ResourceCategory;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.plugins.jmx.JMXDiscoveryComponent;
+import org.rhq.plugins.jmx.util.JvmResourceKey;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
@@ -61,38 +70,38 @@ import org.rhq.core.pluginapi.operation.OperationFacet;
* Integration test for the JMX plugin.
*
* @author Greg Hinkle
+ * @author Ian Springer
*/
public class JMXPluginTest {
- static final String PROGRAM_CLASS = "org.rhq.plugins.jmx.test.JMXPluginTest$TestProgram";
- static final String MONITORABLE = "-Dcom.sun.management.jmxremote.port=9921 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false";
- static final String MBEAN_SERVER_ADDRESS = "service:jmx:rmi:///jndi/rmi://localhost:9921/jmxrmi";
- static final String PROJECT_ARTIFACT_ID_SYSPROP = "project.artifactId";
- static final String PROJECT_VERSION_SYSPROP = "project.version";
+ private static final int JMX_REMOTING_PORT1 = 9921;
+ private static final int JMX_REMOTING_PORT2 = 9922;
- private Process testProgram;
- private InventoryManager inventoryManager;
private static final String PLUGIN_NAME = "JMX";
+ private static final String SERVER_TYPE_NAME = "JMX Server";
+ private static final String EXPLICIT_RESOURCE_KEY1 = "foo1";
+ private static final String EXPLICIT_RESOURCE_KEY2 = "foo2";
+ private List<Process> testServerJvms = new ArrayList<Process>();
+
+ private InventoryManager inventoryManager;
+
@BeforeSuite
public void start() {
try {
- String javaHome = System.getProperty("java.home");
- String javaCmd = javaHome + "/bin/java";
+ // Start the test server JVMs.
+ this.testServerJvms.add(startTestServerJvm("-Dcom.sun.management.jmxremote.port=" + JMX_REMOTING_PORT1,
+ "-Dcom.sun.management.jmxremote.ssl=false", "-Dcom.sun.management.jmxremote.authenticate=false"));
- ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-cp", "target/test-classes",
- "-Dcom.sun.management.jmxremote.port=9921", "-Dcom.sun.management.jmxremote.ssl=false",
- "-Dcom.sun.management.jmxremote.authenticate=false", PROGRAM_CLASS);
- processBuilder.redirectErrorStream(true);
- testProgram = processBuilder.start();
+ this.testServerJvms.add(startTestServerJvm("-D" + JMXDiscoveryComponent.SYSPROP_RHQ_RESOURCE_KEY + "="
+ + EXPLICIT_RESOURCE_KEY1));
- OutputReader or = new OutputReader(testProgram.getInputStream());
- Thread ort = new Thread(or);
- ort.setDaemon(true);
- ort.start();
+ this.testServerJvms.add(startTestServerJvm("-Dcom.sun.management.jmxremote.port=" + JMX_REMOTING_PORT2,
+ "-Dcom.sun.management.jmxremote.ssl=false", "-Dcom.sun.management.jmxremote.authenticate=false",
+ "-D" + JMXDiscoveryComponent.SYSPROP_RHQ_RESOURCE_KEY + "=" + EXPLICIT_RESOURCE_KEY2));
- // Give it time to start
- Thread.sleep(2000);
+ // Give them time to fully start.
+ Thread.sleep(3000);
File pluginDir = new File("target/itest/plugins");
PluginContainerConfiguration pcConfig = new PluginContainerConfiguration();
@@ -102,10 +111,9 @@ public class JMXPluginTest {
PluginContainer.getInstance().setConfiguration(pcConfig);
PluginContainer.getInstance().initialize();
- System.out.println("PC Started");
- for (String plugin : PluginContainer.getInstance().getPluginManager().getMetadataManager().getPluginNames()) {
- System.out.println("PLUGIN: " + plugin);
- }
+
+ Set<String> pluginNames = PluginContainer.getInstance().getPluginManager().getMetadataManager().getPluginNames();
+ System.out.println("PC started with plugins " + pluginNames + ".");
this.inventoryManager = PluginContainer.getInstance().getInventoryManager();
} catch (Throwable t) {
@@ -116,17 +124,43 @@ public class JMXPluginTest {
}
}
+ private Process startTestServerJvm(String... jvmArgs) throws IOException {
+ String javaHome = System.getProperty("java.home");
+ String javaCmd = javaHome + "/bin/java";
+
+ List<String> args = new ArrayList<String>();
+ args.add(javaCmd);
+ args.add("-cp");
+ args.add("target/test-classes");
+ args.addAll(Arrays.asList(jvmArgs));
+ args.add(TestProgram.class.getName());
+
+ ProcessBuilder processBuilder = new ProcessBuilder(args);
+ processBuilder.redirectErrorStream(true);
+ Process process = processBuilder.start();
+
+ OutputReader outputReader = new OutputReader(process.getInputStream());
+ Thread outputReaderThread = new Thread(outputReader);
+ outputReaderThread.setDaemon(true);
+ outputReaderThread.start();
+
+ return process;
+ }
+
@AfterSuite
- public void stop() {
+ public void stop() {
PluginContainer.getInstance().shutdown();
- testProgram.destroy();
+
+ for (Process process : this.testServerJvms) {
+ process.destroy();
+ }
}
@Test
public void testPluginLoad() {
PluginManager pluginManager = PluginContainer.getInstance().getPluginManager();
PluginEnvironment pluginEnvironment = pluginManager.getPlugin(PLUGIN_NAME);
- assert pluginEnvironment != null : "Null environment, plugin not loaded";
+ assert (pluginEnvironment != null) : "Null environment, plugin not loaded";
assert (pluginEnvironment.getPluginName().equals(PLUGIN_NAME));
}
@@ -135,9 +169,43 @@ public class JMXPluginTest {
InventoryReport report = PluginContainer.getInstance().getInventoryManager().executeServerScanImmediately();
assert report != null;
System.out.println("Discovery took: " + (report.getEndTime() - report.getStartTime()) + "ms");
+
Resource platform = PluginContainer.getInstance().getInventoryManager().getPlatform();
- Set<Resource> servers = platform.getChildResources();
- System.out.println("Found " + servers.size() + " servers");
+
+ Set<Resource> jmxServers = getChildResourcesOfType(platform, new ResourceType(SERVER_TYPE_NAME, PLUGIN_NAME,
+ ResourceCategory.SERVER, null));
+ System.out.println("Found " + jmxServers.size() + " JMX Servers:");
+
+ boolean foundJmxRemotingServer = false;
+ boolean foundExplicitKey1Server = false;
+ boolean foundExplicitKey2Server = false;
+ for (Resource jmxServer : jmxServers) {
+ System.out.println(" * " + jmxServer);
+ JvmResourceKey key = JvmResourceKey.valueOf(jmxServer.getResourceKey());
+ switch (key.getType()) {
+ case Explicit:
+ if (key.getExplicitValue().equals(EXPLICIT_RESOURCE_KEY1)) {
+ assert key.getMainClassName().equals(TestProgram.class.getName());
+ foundExplicitKey1Server = true;
+ } else if (key.getExplicitValue().equals(EXPLICIT_RESOURCE_KEY2)) {
+ assert key.getMainClassName().equals(TestProgram.class.getName());
+ foundExplicitKey2Server = true;
+ }
+ break;
+ case JmxRemotingPort:
+ if (key.getMainClassName().equals(TestProgram.class.getName()) &&
+ key.getJmxRemotingPort().equals(JMX_REMOTING_PORT1)) {
+ assert key.getMainClassName().equals(TestProgram.class.getName());
+ foundJmxRemotingServer = true;
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unsupported key type: " + key.getType());
+ }
+ }
+ assert foundJmxRemotingServer : "JMX Remoting server not found.";
+ assert foundExplicitKey1Server : "Explicit key server not found.";
+ assert foundExplicitKey2Server : "JMX Remoting + explicit key server not found.";
}
@Test(dependsOnMethods = "testServerDiscovery")
@@ -147,27 +215,20 @@ public class JMXPluginTest {
Resource platform = PluginContainer.getInstance().getInventoryManager().getPlatform();
assert platform != null;
- Set<Resource> childResources = platform.getChildResources();
- assert childResources != null;
-
- /*System.out.println("RUNTIME SERVERS: " + childResources.size());
- * for (Resource server : platform.getChildResources()) { System.out.println("Server: " + server.toString());
- * System.out.println("Found with " + server.getChildResources().size() + " child services");}*/
- InventoryPrinter.outputInventory(new PrintWriter(System.out), false);
- }
- @Test(dependsOnMethods = "testServerDiscovery")
- public void testNumberOfServers() throws Exception {
- InventoryReport report = PluginContainer.getInstance().getInventoryManager().executeServiceScanImmediately();
- assert report != null;
- Resource platform = PluginContainer.getInstance().getInventoryManager().getPlatform();
+ Set<Resource> jmxServers = getChildResourcesOfType(platform, new ResourceType(SERVER_TYPE_NAME, PLUGIN_NAME,
+ ResourceCategory.SERVER, null));
- assert platform != null;
- Set<Resource> childResources = platform.getChildResources();
- assert childResources != null;
+ for (Resource jmxServer : jmxServers) {
+ Set<Resource> childResources = jmxServer.getChildResources();
+ // Each JMX Server should have exactly six singleton child Resources with the following types:
+ // Operating System, Threading, VM Class Loading System, VM Compilation System, VM Memory System, and
+ // java.util.logging.
+ assert childResources.size() == 6 : jmxServer + " does not have 6 child Resources - child Resources: "
+ + childResources;
+ }
- // TODO GH: ccrouch... why would this be two now?
- //assert childResources.size() == 2 : "Not all Server instances were found.";
+ InventoryPrinter.outputInventory(new PrintWriter(System.out), false);
}
@Test(dependsOnMethods = "testServiceDiscovery")
@@ -198,8 +259,6 @@ public class JMXPluginTest {
@Test(dependsOnMethods = "testServiceDiscovery")
public void testOperation() throws Exception {
- // TODO GH: Test only runs when tested on JDK 6 as the JVM services aren't detected
- // currently for the test platform
Resource platform = PluginContainer.getInstance().getInventoryManager().getPlatform();
for (Resource server : platform.getChildResources()) {
List<Resource> services = new ArrayList<Resource>(server.getChildResources());
@@ -253,6 +312,19 @@ public class JMXPluginTest {
* } }
*/
+ private static Set<Resource> getChildResourcesOfType(Resource platform, ResourceType resourceType) {
+ Set<Resource> childResources = platform.getChildResources();
+ Set<Resource> results = new HashSet<Resource>();
+ for (Resource resource : childResources) {
+ ResourceType childResourceType = resource.getResourceType();
+ if (childResourceType.getPlugin().equals(resourceType.getPlugin()) &&
+ childResourceType.getName().equals(resourceType.getName())) {
+ results.add(resource);
+ }
+ }
+ return results;
+ }
+
public static class OutputReader implements Runnable {
InputStream inputStream;
@@ -262,10 +334,10 @@ public class JMXPluginTest {
public void run() {
try {
- BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
- while ((line = r.readLine()) != null) {
+ while ((line = reader.readLine()) != null) {
System.out.println("__" + line);
}
} catch (IOException e) {
@@ -277,8 +349,35 @@ public class JMXPluginTest {
public static class TestProgram implements Runnable {
long started = System.currentTimeMillis();
- public static void main(String[] args) {
- System.out.println("Test program running...");
+ public static void main(String[] args) {
+ final ServerSocket serverSocket;
+ try {
+ serverSocket = new ServerSocket(0);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+ String jvmName = runtimeMXBean.getName();
+ int atIndex = jvmName.indexOf('@');
+ String pid = (atIndex != -1) ? jvmName.substring(0, atIndex) : "?";
+
+ System.out.println("Test server JVM with pid [" + pid + "] listening on port ["
+ + serverSocket.getLocalPort() + "]...");
+ Runnable runnable = new Runnable() {
+ public void run() {
+ Socket socket;
+ try {
+ while ((socket = serverSocket.accept()) != null) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ runnable.run();
+
TestProgram tp = new TestProgram();
tp.run();
}
@@ -289,8 +388,10 @@ public class JMXPluginTest {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
+ // ignore
}
}
}
}
-}
\ No newline at end of file
+
+}
commit f83f9b96e135f7f6e4dbc505c24218103847835c
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 14:12:11 2012 -0500
move ObjectNameQueryUtility and ParentDefinedJMXServerNamingUtility classes to util subpackage (missed files from earlier commit); minor code cleanup in InternalJMXServerDiscoveryComponent
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/InternalJMXServerDiscoveryComponent.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/InternalJMXServerDiscoveryComponent.java
index fcd16fc..ca5e5e5 100644
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/InternalJMXServerDiscoveryComponent.java
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/InternalJMXServerDiscoveryComponent.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -25,8 +25,6 @@ package org.rhq.plugins.jmx;
import java.util.HashSet;
import java.util.Set;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.support.metadata.InternalVMTypeDescriptor;
import org.rhq.core.domain.configuration.Configuration;
@@ -34,24 +32,32 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.plugins.jmx.util.ParentDefinedJMXServerNamingUtility;
+/**
+ * Discovers a singleton Resource representing the local JVM (i.e. the JVM in which the RHQ Plugin Container is running).
+ */
public class InternalJMXServerDiscoveryComponent implements ResourceDiscoveryComponent {
- private static final Log log = LogFactory.getLog(InternalJMXServerDiscoveryComponent.class);
+
+ private static final String RESOURCE_KEY = "InternalVM";
+ private static final String DEFAULT_RESOURCE_DESCRIPTION = "JVM of RHQ Plugin Container";
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) {
- Set<DiscoveredResourceDetails> found = new HashSet<DiscoveredResourceDetails>();
+ Set<DiscoveredResourceDetails> discoveredResources = new HashSet<DiscoveredResourceDetails>(1);
- DiscoveredResourceDetails localVM = new DiscoveredResourceDetails(context.getResourceType(), "InternalVM",
- ParentDefinedJMXServerNamingUtility.getJVMName(context), System.getProperty("java.version"),
- "VM of plugin container", null, null);
+ String name = ParentDefinedJMXServerNamingUtility.getJVMName(context);
+ String version = System.getProperty("java.version");
+ DiscoveredResourceDetails localVM = new DiscoveredResourceDetails(context.getResourceType(), RESOURCE_KEY,
+ name, version, DEFAULT_RESOURCE_DESCRIPTION, context.getDefaultPluginConfiguration(),
+ context.getSystemInformation().getThisProcess());
Configuration configuration = localVM.getPluginConfiguration();
configuration.put(new PropertySimple(JMXDiscoveryComponent.CONNECTOR_ADDRESS_CONFIG_PROPERTY,
"Local Connection"));
configuration.put(new PropertySimple(JMXDiscoveryComponent.CONNECTION_TYPE, InternalVMTypeDescriptor.class
.getName()));
+ discoveredResources.add(localVM);
- found.add(localVM);
-
- return found;
+ return discoveredResources;
}
-}
\ No newline at end of file
+
+}
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/MBeanResourceDiscoveryComponent.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/MBeanResourceDiscoveryComponent.java
index 471dcbe..8cf89de 100644
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/MBeanResourceDiscoveryComponent.java
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/MBeanResourceDiscoveryComponent.java
@@ -38,6 +38,7 @@ import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* This is meant to be a generic discovery component for MBeans. In order to use it you configure your resource
@@ -87,8 +88,9 @@ public class MBeanResourceDiscoveryComponent<T extends JMXComponent<?>> implemen
// Public --------------------------------------------
/**
- * Same as {@link discoverResources(ResourceDiscoveryContext<T>)} with additional param.
- * @param skipUnknownProps Should we skip over MBeans that have unknown properties in their ObjectName
+ * Same as {@link #discoverResources(ResourceDiscoveryContext<T>)} with additional param.
+ *
+ * @param skipUnknownProps if true, skip over MBeans that have unknown properties in their ObjectName
*/
public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<T> context,
boolean skipUnknownProps) {
commit 01eb02937bb322f4efb53224bbd7889498f9df2d
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 12:12:21 2012 -0500
add 'commandLine' prop to plugin config def for JMX Server type (this prop was already being used in the plugin's code)
diff --git a/modules/plugins/jmx/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/jmx/src/main/resources/META-INF/rhq-plugin.xml
index 5572bf0..97a4025 100644
--- a/modules/plugins/jmx/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/jmx/src/main/resources/META-INF/rhq-plugin.xml
@@ -6,7 +6,6 @@
description="Supports management of JMX MBean Servers via various remoting systems."
pluginLifecycleListener="JMXPluginLifecycleListener"
ampsVersion="2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:xmlns:rhq-plugin"
xmlns:c="urn:xmlns:rhq-configuration">
@@ -40,11 +39,12 @@
</c:property-options>
</c:simple-property>
- <c:simple-property name="connectorAddress" required="true" type="string" description="The connection url in the form of a JMXServiceURL"/>
- <c:simple-property name="installURI" required="false" type="string" description="The installation path for the selected server type which will be used to find client libraries (if appropriate)."/>
+ <c:simple-property name="connectorAddress" required="false" type="string" description="The connection url in the form of a JMXServiceURL - this should only be set if the JVM has JMX Remoting enabled"/>
+ <c:simple-property name="installURI" required="false" type="string" description="The installation path for the selected server type which will be used to find client libraries (if appropriate)"/>
<c:simple-property name="principal" required="false" description="The login principal/username"/>
<c:simple-property name="credentials" required="false" type="password" description="The login credentials/password"/>
<c:simple-property name="additionalClassPathEntries" required="false" type="string" description="Comma-separated list of directories and filenames that contain resources and classes needed to communicate with the JMX Server and its MBeans. If you specify 'some/directory/*.jar', all jars found in the given directory will be added."/>
+ <c:simple-property name="commandLine" required="false" type="string" description="the command line of the JVM at the time it was discovered - only used by JVMs with type Local; if the command line of the JVM changes, this property's value will need to be updated accordingly in order for RHQ to connect to the JVM"/>
<c:template name="JDK 5" description="Connect to JDK 5">
<c:simple-property name="type" default="org.mc4j.ems.connection.support.metadata.J2SE5ConnectionTypeDescriptor"/>
@@ -79,7 +79,7 @@
In order to do this, you must pass in some system properties when starting your application's Java virtual
machine.</p>
- <p> To run a JVM with JMX remoting enabled without authentication, you must pass in the following system
+ <p>To run a JVM with JMX remoting enabled without authentication, you must pass in the following system
properties:</p>
<ul>
commit c56e22e9227dd87f5411ef7dbd17c03833dbea8c
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Mon Jan 23 12:10:57 2012 -0500
move ObjectNameQueryUtility and ParentDefinedJMXServerNamingUtility classes to util subpackage (missed file from earlier commit)
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/EmbeddedJMXServerDiscoveryComponent.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/EmbeddedJMXServerDiscoveryComponent.java
index 4b48067..58f7698 100644
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/EmbeddedJMXServerDiscoveryComponent.java
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/EmbeddedJMXServerDiscoveryComponent.java
@@ -37,6 +37,7 @@ import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.core.system.ProcessInfo;
+import org.rhq.plugins.jmx.util.ParentDefinedJMXServerNamingUtility;
/**
* This discovery component can be used to include JVM information under a parent Process oriented server that supports
commit ebe55c758809eb79b4fd6bbbf01413ae76aef646
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Jan 20 17:48:30 2012 -0500
cosmetic: minor tweak to comment
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
index 219d828..04600b7 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/ResourceType.java
@@ -844,7 +844,7 @@ public class ResourceType implements Serializable, Comparable<ResourceType> {
// NOTE: It's vital that compareTo() is consistent with equals(), otherwise TreeSets containing ResourceTypes, or
// TreeMaps with ResourceTypes as keys, will not work reliably. See the Javadoc for Comparable for a precise
- // definition of consistent with equals().
+ // definition of "consistent with equals()".
@Override
public int compareTo(ResourceType that) {
if (this.name == null) {
commit e80d575b40ee51b6bf81e4525d853b728f0ced71
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Jan 20 17:47:49 2012 -0500
make Resource's compareTo impl consistent with its equals() impl, so Resources can be reliably added to TreeSets and TreeMaps; update "inventory" Agent prompt command to sort sibling Resources by type and then by name, rather than just by name - this makes the output much more readable
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
index c90ed4e..a403cd4 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
@@ -1789,8 +1789,29 @@ public class Resource implements Comparable<Resource>, Serializable {
driftDefinition.setResource(this);
}
+ // NOTE: It's vital that compareTo() is consistent with equals(), otherwise TreeSets containing Resources, or
+ // TreeMaps with Resources as keys, will not work reliably. See the Javadoc for Comparable for a precise
+ // definition of "consistent with equals()".
+ @Override
public int compareTo(Resource that) {
- return this.name.compareTo(that.getName());
+ if (this == that) {
+ return 0;
+ }
+ int result;
+ if (this.name != null) {
+ result = (that.name != null) ? this.name.compareTo(that.name) : -1;
+ } else {
+ result = (that.name == null) ? 0 : 1;
+ }
+ if (result == 0) {
+ // The names are equal - compare the UUIDs to break the tie.
+ if (this.uuid != null) {
+ result = (that.uuid != null) ? this.uuid.compareTo(that.uuid) : -1;
+ } else {
+ result = (that.uuid == null) ? 0 : 1;
+ }
+ }
+ return result;
}
@Override
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/InventoryPrinter.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/InventoryPrinter.java
index e02cd34..4b1fe14 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/InventoryPrinter.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/util/InventoryPrinter.java
@@ -1,6 +1,6 @@
/*
* RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -24,11 +24,12 @@ package org.rhq.core.pc.util;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.Date;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.AvailabilityType;
@@ -282,7 +283,17 @@ public class InventoryPrinter {
}
if (recurseChildren) {
- Set<Resource> children = new HashSet(resource.getChildResources()); // wrap in new HashSet to avoid CCMEs
+ Set<Resource> children = new TreeSet<Resource>(new Comparator<Resource>() {
+ public int compare(Resource o1, Resource o2) {
+ int result = o1.getResourceType().compareTo(o2.getResourceType());
+ if (result == 0) {
+ // The types are the same - let the Resource.compareTo() break the tie.
+ result = o1.compareTo(o2);
+ }
+ return result;
+ }
+ }); // wrap in new TreeSet to avoid CCMEs and to sort by type
+ children.addAll(resource.getChildResources());
for (Resource child : children) {
ResourceContainer childContainer;
commit 4e2594029b4d3368b671b6eef722ede8f7e62efa
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Jan 20 17:44:53 2012 -0500
move ObjectNameQueryUtility and ParentDefinedJMXServerNamingUtility classes to util subpackage (missed this file in my last commit)
diff --git a/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/ObjectNameQueryUtilityTest.java b/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/ObjectNameQueryUtilityTest.java
index e9849b7..a7e9f77 100644
--- a/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/ObjectNameQueryUtilityTest.java
+++ b/modules/plugins/jmx/src/test/java/org/rhq/plugins/jmx/test/ObjectNameQueryUtilityTest.java
@@ -27,11 +27,11 @@ import java.util.Collections;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
import org.testng.annotations.Test;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
public class ObjectNameQueryUtilityTest {
@Test
commit d06bde3ab789c06f603836525d7281e7a96bad85
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Jan 20 17:43:25 2012 -0500
move ObjectNameQueryUtility and ParentDefinedJMXServerNamingUtility classes to util subpackage
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/AbstractMessagingDiscoveryComponent.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/AbstractMessagingDiscoveryComponent.java
index 4d1d19d..3de8057 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/AbstractMessagingDiscoveryComponent.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/AbstractMessagingDiscoveryComponent.java
@@ -38,7 +38,7 @@ import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jmx.JMXComponent;
import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* Abstract base class to discover JBossMessaging and JBossMQ related stuff
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
index 9cc19bc..3169376 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASServerComponent.java
@@ -114,7 +114,7 @@ import org.rhq.plugins.jbossas.util.JarContentDelegate;
import org.rhq.plugins.jbossas.util.XMLConfigurationEditor;
import org.rhq.plugins.jmx.JMXComponent;
import org.rhq.plugins.jmx.JMXDiscoveryComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* Resource component for managing JBoss AS 3.2.3 through 4.2.x, and JBoss EAP and SOA-P 4.x.
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASTomcatConnectorDiscoveryComponent.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASTomcatConnectorDiscoveryComponent.java
index 30068e8..0adc4db 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASTomcatConnectorDiscoveryComponent.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/JBossASTomcatConnectorDiscoveryComponent.java
@@ -40,7 +40,7 @@ import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jmx.JMXComponent;
import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* Plugin discovery component for JBoss Web (embedded Tomcat) connectors. The bulk of the discovery is performed by the
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/WarComponent.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/WarComponent.java
index b3d218c..1993e7b 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/WarComponent.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/WarComponent.java
@@ -24,13 +24,9 @@ package org.rhq.plugins.jbossas;
import java.io.File;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -57,9 +53,9 @@ import org.rhq.core.pluginapi.util.ResponseTimeLogParser;
import org.rhq.plugins.jbossas.util.DeploymentUtility;
import org.rhq.plugins.jbossas.util.WarDeploymentInformation;
import org.rhq.plugins.jbossas.util.WarDiscoveryHelper;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
-/**
+ /**
* A resource component for managing a web application (WAR) deployed to a JBossAS server.
*
* @author Ian Springer
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/DeploymentUtility.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/DeploymentUtility.java
index d915ff0..0a8e8c8 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/DeploymentUtility.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/DeploymentUtility.java
@@ -48,9 +48,9 @@ import org.mc4j.ems.connection.bean.EmsBean;
import org.mc4j.ems.connection.bean.attribute.EmsAttribute;
import org.mc4j.ems.connection.bean.operation.EmsOperation;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
-/**
+ /**
* Accesses the MainDeployer mbean to find the deployment files behind services.
*
* @author Greg Hinkle
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/WarDiscoveryHelper.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/WarDiscoveryHelper.java
index 964223f..48d4c46 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/WarDiscoveryHelper.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/util/WarDiscoveryHelper.java
@@ -42,6 +42,8 @@ import org.apache.commons.logging.LogFactory;
import org.mc4j.ems.connection.EmsConnection;
import org.mc4j.ems.connection.bean.EmsBean;
import org.mc4j.ems.connection.bean.attribute.EmsAttribute;
+
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
import org.xml.sax.InputSource;
import org.rhq.core.domain.configuration.Configuration;
@@ -53,7 +55,6 @@ import org.rhq.plugins.jbossas.JBossASServerComponent;
import org.rhq.plugins.jbossas.WarComponent;
import org.rhq.plugins.jbossas.WarDiscoveryComponent;
import org.rhq.plugins.jmx.MBeanResourceComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
/**
* Provides helper methods that are used by both {@link WarDiscoveryComponent} and {@link EmbeddedWarDiscoveryComponent}
diff --git a/modules/plugins/jboss-cache-v3/src/main/java/org/rhq/plugins/jbosscache3/JBossCacheDiscoveryComponent.java b/modules/plugins/jboss-cache-v3/src/main/java/org/rhq/plugins/jbosscache3/JBossCacheDiscoveryComponent.java
index 86bd02f..bfc3fc4 100644
--- a/modules/plugins/jboss-cache-v3/src/main/java/org/rhq/plugins/jbosscache3/JBossCacheDiscoveryComponent.java
+++ b/modules/plugins/jboss-cache-v3/src/main/java/org/rhq/plugins/jbosscache3/JBossCacheDiscoveryComponent.java
@@ -40,7 +40,7 @@ import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jbossas5.ProfileServiceComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
*
diff --git a/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheComponent.java b/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheComponent.java
index 3ec0276..68050e0 100644
--- a/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheComponent.java
+++ b/modules/plugins/jboss-cache/src/main/java/org/rhq/plugins/jbosscache/JBossCacheComponent.java
@@ -63,7 +63,7 @@ import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.plugins.jbossas.util.DeploymentUtility;
import org.rhq.plugins.jmx.JMXComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* Get statistic for JBossCache instances
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ObjectNameQueryUtility.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ObjectNameQueryUtility.java
deleted file mode 100644
index a3f46ed..0000000
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ObjectNameQueryUtility.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.rhq.plugins.jmx;
-
-import org.rhq.core.domain.configuration.Configuration;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A utility class to help in querying object names and utilizing parts of the object name for setting configuration
- * values and changing string messages. A template that you'd build this utility with could look like
- * "foo:name=%myName%,type=myType". This will be "translated" into a valid JMX objectName Query of the form
- * "foo:type=myType,*". It will also detect that we've got a variable defined as "myName" that we'd like to later match
- * to.
- *
- * <p/>We can then find beans with the query and apply their objectName properties to the object and use those found
- * values to rewrite strings or setup configuration properities. For example, we've got a detected object name for the
- * above template "foo:name=bar,type=myType". We set its detected keys against this utility and we now have a variable
- * defined as the key "myName" and the value of "bar". Then I can call formatMessage with "A foo called {myName}" which
- * will be translated into "A foo called bar". This can be useful for naming resources and descriptions using parts of a
- * mapped ObjectName.
- *
- * @author Greg Hinkle
- */
-public class ObjectNameQueryUtility {
- private String queryTemplate;
-
- private Map<String, String> variableProperties = new HashMap<String, String>();
-
- private Map<String, String> variableValues = new HashMap<String, String>();
-
- private Set<String> nonVariableProperties = new HashSet<String>();
-
- private String translatedQuery;
-
- /**
- * Builds a mapped query utility object and finds the variables in the supplied object name query template.
- *
- * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%"
- */
- public ObjectNameQueryUtility(String objectNameQueryTemplate) {
- this.queryTemplate = objectNameQueryTemplate;
- buildMatchMap(queryTemplate);
- }
-
- /**
- * Builds a mapped query utility object and finds the variables in the supplied object name query template.
- * This version first translates the objectName template for defined values in provided configuration. This
- * is explicitly built for hierarchical objectName models to find the children of parents.
- *
- * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%,h={myParentsH}"
- * @param parentConfiguration the config holding the matched values for the object name key property variables
- */
- public ObjectNameQueryUtility(String objectNameQueryTemplate, Configuration parentConfiguration) {
-
- Pattern p = Pattern.compile("\\{([^\\{\\}]*)\\}");
- Matcher m = p.matcher(objectNameQueryTemplate);
- while (m.find()) {
- String objectNameKeyPropVariableName = m.group(1);
- String value = parentConfiguration.getSimple(objectNameKeyPropVariableName).getStringValue();
- objectNameQueryTemplate = objectNameQueryTemplate.replaceAll("\\{" + objectNameKeyPropVariableName + "\\}", value);
- }
-
- this.queryTemplate = objectNameQueryTemplate;
- buildMatchMap(this.queryTemplate);
- }
-
- /**
- * Set values for properties from an objectName. These are first translated into the "real" keys. e.g. foo:bar=%baz%
- * In this case, the property of the bar objectName property will be set into the properties keyed against "baz"
- * which is the real key.
- *
- * @param keyProperties properties from the found objectName to apply
- *
- * @return true if the objectName properties contained all variable properties or false if some where missing (e.g.
- * foo:A=%a%,B=%b% is the queryTemplate but objectName found is foo:A=alpha)
- */
- public boolean setMatchedKeyValues(Map<String, String> keyProperties) {
- for (String key : keyProperties.keySet()) {
- if (this.variableProperties.containsKey(key)) {
- String realKey = this.variableProperties.get(key);
- String value = keyProperties.get(key);
-
- this.variableValues.put(realKey, value);
- }
- }
-
- // Return true if there are key properties for every variable in the template and false otherwise
- return (keyProperties.keySet().containsAll(this.variableProperties.keySet()));
- }
-
- /**
- * Format a message with {<key>} formatted replacement keys.
- *
- * @param message the message to format
- *
- * @return the formatted text with variables replaced
- */
- public String formatMessage(String message) {
- for (String key : variableValues.keySet()) {
- message = message.replaceAll("\\{" + key + "\\}", this.variableValues.get(key));
- }
-
- return message;
- }
-
- /**
- * Clears out variables so that a new found bean can be used against the same utility object again.
- */
- public void resetVariables() {
- this.variableValues.clear();
- }
-
- public String getQueryTemplate() {
- return queryTemplate;
- }
-
- public Map<String, String> getVariableProperties() {
- return variableProperties;
- }
-
- public Map<String, String> getVariableValues() {
- return variableValues;
- }
-
- public String getTranslatedQuery() {
- return translatedQuery;
- }
-
- /**
- * Detects the mapped variable object name properties and the resulting object name query that can find matching
- * beans.
- *
- * @param objectNameQueryTemplate a template of the form foo:bar=%baz%
- */
- private void buildMatchMap(String objectNameQueryTemplate) {
- StringBuilder queryBuilder = new StringBuilder();
-
- Pattern p = Pattern.compile("^([^:]*\\:)(.*)$");
- Matcher m = p.matcher(objectNameQueryTemplate);
- if (!m.find()) {
- assert false : "ObjectName did not match expected regular expression: " + objectNameQueryTemplate;
- }
-
- queryBuilder.append(m.group(1));
- String keyProps = m.group(2);
- String[] keys = keyProps.split(",");
-
- boolean firstVar = true;
- boolean onlyVar = true;
- for (String key : keys) {
- Pattern p2 = Pattern.compile("^([^=]*)=\\%(.*)\\%$");
- Matcher m2 = p2.matcher(key);
- if (m2.find()) {
- variableProperties.put(m2.group(1), m2.group(2));
- } else {
- Pattern p3 = Pattern.compile("^([^=]*)=(.*)$");
- Matcher m3 = p3.matcher(key);
- if (m3.find()) {
- nonVariableProperties.add(m3.group(1));
- }
-
- onlyVar = false;
- if (firstVar) {
- firstVar = false;
- } else {
- queryBuilder.append(",");
- }
-
- queryBuilder.append(key);
- }
- }
-
- if (variableProperties.size() > 0) {
- if (!onlyVar) {
- queryBuilder.append(",");
- }
-
- queryBuilder.append("*");
- }
-
- this.translatedQuery = queryBuilder.toString();
- }
-
- public boolean isContainsExtraKeyProperties(Set<String> strings) {
- for (String key : strings) {
- if (!nonVariableProperties.contains(key) && !variableProperties.containsKey(key)) {
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ParentDefinedJMXServerNamingUtility.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ParentDefinedJMXServerNamingUtility.java
deleted file mode 100644
index 8817fa7..0000000
--- a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/ParentDefinedJMXServerNamingUtility.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2010 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.rhq.plugins.jmx;
-
-import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.configuration.PropertySimple;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
-
-/**
- * A simple utility class to extract the name of a JMX server from the parent resource's plugin configuration.
- *
- * @author Lukas Krejci
- */
-public class ParentDefinedJMXServerNamingUtility {
- public static final String PROPERTY_CHILD_JMX_SERVER_NAME = "childJmxServerName";
-
- /**
- * Checks if the parent resource's plugin configuration contains a property called {@link #PROPERTY_CHILD_JMX_SERVER_NAME}.
- * If such property exists and its value is non-empty, its value is returned. Otherwise the name of the provided
- * resource type is returned.
- *
- * @param context the discovery context to get the parent plugin configuration and current resource type from.
- * @return the name that can be used for the JVM
- */
- public static String getJVMName(ResourceDiscoveryContext<?> context) {
- Configuration parentPluginConfiguration = context.getParentResourceContext().getPluginConfiguration();
- PropertySimple nameProperty = parentPluginConfiguration.getSimple(PROPERTY_CHILD_JMX_SERVER_NAME);
- if (nameProperty == null || nameProperty.getStringValue() == null
- || nameProperty.getStringValue().trim().length() == 0) {
-
- return context.getResourceType().getName();
- } else {
- return nameProperty.getStringValue();
- }
- }
-}
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ObjectNameQueryUtility.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ObjectNameQueryUtility.java
new file mode 100644
index 0000000..b8454d7
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ObjectNameQueryUtility.java
@@ -0,0 +1,218 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.plugins.jmx.util;
+
+import org.rhq.core.domain.configuration.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A utility class to help in querying object names and utilizing parts of the object name for setting configuration
+ * values and changing string messages. A template that you'd build this utility with could look like
+ * "foo:name=%myName%,type=myType". This will be "translated" into a valid JMX objectName Query of the form
+ * "foo:type=myType,*". It will also detect that we've got a variable defined as "myName" that we'd like to later match
+ * to.
+ *
+ * <p/>We can then find beans with the query and apply their objectName properties to the object and use those found
+ * values to rewrite strings or setup configuration properties. For example, we've got a detected object name for the
+ * above template "foo:name=bar,type=myType". We set its detected keys against this utility and we now have a variable
+ * defined as the key "myName" and the value of "bar". Then I can call formatMessage with "A foo called {myName}" which
+ * will be translated into "A foo called bar". This can be useful for naming resources and descriptions using parts of a
+ * mapped ObjectName.
+ *
+ * @author Greg Hinkle
+ */
+public class ObjectNameQueryUtility {
+ private String queryTemplate;
+
+ private Map<String, String> variableProperties = new HashMap<String, String>();
+
+ private Map<String, String> variableValues = new HashMap<String, String>();
+
+ private Set<String> nonVariableProperties = new HashSet<String>();
+
+ private String translatedQuery;
+
+ /**
+ * Builds a mapped query utility object and finds the variables in the supplied object name query template.
+ *
+ * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%"
+ */
+ public ObjectNameQueryUtility(String objectNameQueryTemplate) {
+ this.queryTemplate = objectNameQueryTemplate;
+ buildMatchMap(queryTemplate);
+ }
+
+ /**
+ * Builds a mapped query utility object and finds the variables in the supplied object name query template.
+ * This version first translates the objectName template for defined values in provided configuration. This
+ * is explicitly built for hierarchical objectName models to find the children of parents.
+ *
+ * @param objectNameQueryTemplate string of form "a:b=%c%,d=e,f=%g%,h={myParentsH}"
+ * @param parentConfiguration the config holding the matched values for the object name key property variables
+ */
+ public ObjectNameQueryUtility(String objectNameQueryTemplate, Configuration parentConfiguration) {
+
+ Pattern p = Pattern.compile("\\{([^\\{\\}]*)\\}");
+ Matcher m = p.matcher(objectNameQueryTemplate);
+ while (m.find()) {
+ String objectNameKeyPropVariableName = m.group(1);
+ String value = parentConfiguration.getSimple(objectNameKeyPropVariableName).getStringValue();
+ objectNameQueryTemplate = objectNameQueryTemplate.replaceAll("\\{" + objectNameKeyPropVariableName + "\\}", value);
+ }
+
+ this.queryTemplate = objectNameQueryTemplate;
+ buildMatchMap(this.queryTemplate);
+ }
+
+ /**
+ * Set values for properties from an objectName. These are first translated into the "real" keys. e.g. foo:bar=%baz%
+ * In this case, the property of the bar objectName property will be set into the properties keyed against "baz"
+ * which is the real key.
+ *
+ * @param keyProperties properties from the found objectName to apply
+ *
+ * @return true if the objectName properties contained all variable properties or false if some where missing (e.g.
+ * foo:A=%a%,B=%b% is the queryTemplate but objectName found is foo:A=alpha)
+ */
+ public boolean setMatchedKeyValues(Map<String, String> keyProperties) {
+ for (String key : keyProperties.keySet()) {
+ if (this.variableProperties.containsKey(key)) {
+ String realKey = this.variableProperties.get(key);
+ String value = keyProperties.get(key);
+
+ this.variableValues.put(realKey, value);
+ }
+ }
+
+ // Return true if there are key properties for every variable in the template and false otherwise
+ return (keyProperties.keySet().containsAll(this.variableProperties.keySet()));
+ }
+
+ /**
+ * Format a message with {<key>} formatted replacement keys.
+ *
+ * @param message the message to format
+ *
+ * @return the formatted text with variables replaced
+ */
+ public String formatMessage(String message) {
+ for (String key : variableValues.keySet()) {
+ message = message.replaceAll("\\{" + key + "\\}", this.variableValues.get(key));
+ }
+
+ return message;
+ }
+
+ /**
+ * Clears out variables so that a new found bean can be used against the same utility object again.
+ */
+ public void resetVariables() {
+ this.variableValues.clear();
+ }
+
+ public String getQueryTemplate() {
+ return queryTemplate;
+ }
+
+ public Map<String, String> getVariableProperties() {
+ return variableProperties;
+ }
+
+ public Map<String, String> getVariableValues() {
+ return variableValues;
+ }
+
+ public String getTranslatedQuery() {
+ return translatedQuery;
+ }
+
+ /**
+ * Detects the mapped variable object name properties and the resulting object name query that can find matching
+ * beans.
+ *
+ * @param objectNameQueryTemplate a template of the form foo:bar=%baz%
+ */
+ private void buildMatchMap(String objectNameQueryTemplate) {
+ StringBuilder queryBuilder = new StringBuilder();
+
+ Pattern p = Pattern.compile("^([^:]*\\:)(.*)$");
+ Matcher m = p.matcher(objectNameQueryTemplate);
+ if (!m.find()) {
+ assert false : "ObjectName did not match expected regular expression: " + objectNameQueryTemplate;
+ }
+
+ queryBuilder.append(m.group(1));
+ String keyProps = m.group(2);
+ String[] keys = keyProps.split(",");
+
+ boolean firstVar = true;
+ boolean onlyVar = true;
+ for (String key : keys) {
+ Pattern p2 = Pattern.compile("^([^=]*)=\\%(.*)\\%$");
+ Matcher m2 = p2.matcher(key);
+ if (m2.find()) {
+ variableProperties.put(m2.group(1), m2.group(2));
+ } else {
+ Pattern p3 = Pattern.compile("^([^=]*)=(.*)$");
+ Matcher m3 = p3.matcher(key);
+ if (m3.find()) {
+ nonVariableProperties.add(m3.group(1));
+ }
+
+ onlyVar = false;
+ if (firstVar) {
+ firstVar = false;
+ } else {
+ queryBuilder.append(",");
+ }
+
+ queryBuilder.append(key);
+ }
+ }
+
+ if (variableProperties.size() > 0) {
+ if (!onlyVar) {
+ queryBuilder.append(",");
+ }
+
+ queryBuilder.append("*");
+ }
+
+ this.translatedQuery = queryBuilder.toString();
+ }
+
+ public boolean isContainsExtraKeyProperties(Set<String> strings) {
+ for (String key : strings) {
+ if (!nonVariableProperties.contains(key) && !variableProperties.containsKey(key)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ParentDefinedJMXServerNamingUtility.java b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ParentDefinedJMXServerNamingUtility.java
new file mode 100644
index 0000000..118debc
--- /dev/null
+++ b/modules/plugins/jmx/src/main/java/org/rhq/plugins/jmx/util/ParentDefinedJMXServerNamingUtility.java
@@ -0,0 +1,57 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2010 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.rhq.plugins.jmx.util;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+
+/**
+ * A simple utility class to extract the name of a JMX server from the parent resource's plugin configuration.
+ *
+ * @author Lukas Krejci
+ */
+public class ParentDefinedJMXServerNamingUtility {
+ public static final String PROPERTY_CHILD_JMX_SERVER_NAME = "childJmxServerName";
+
+ /**
+ * Checks if the parent resource's plugin configuration contains a property called {@link #PROPERTY_CHILD_JMX_SERVER_NAME}.
+ * If such property exists and its value is non-empty, its value is returned. Otherwise the name of the provided
+ * resource type is returned.
+ *
+ * @param context the discovery context to get the parent plugin configuration and current resource type from.
+ * @return the name that can be used for the JVM
+ */
+ public static String getJVMName(ResourceDiscoveryContext<?> context) {
+ Configuration parentPluginConfiguration = context.getParentResourceContext().getPluginConfiguration();
+ PropertySimple nameProperty = parentPluginConfiguration.getSimple(PROPERTY_CHILD_JMX_SERVER_NAME);
+ if (nameProperty == null || nameProperty.getStringValue() == null
+ || nameProperty.getStringValue().trim().length() == 0) {
+
+ return context.getResourceType().getName();
+ } else {
+ return nameProperty.getStringValue();
+ }
+ }
+}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
index 4f334a4..ab3e829 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorComponent.java
@@ -45,7 +45,7 @@ import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.plugins.jmx.MBeanResourceComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* Plugin component for representing Tomcat connectors. Much of the functionality is left to the super class,
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
index 0940910..e6e95ee 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatConnectorDiscoveryComponent.java
@@ -39,7 +39,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* JON plugin discovery component for Tomcat connectors. The bulk of the discovery is performed by the super class. This
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
index d1c0f59..75f8e92 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
@@ -74,7 +74,7 @@ import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.core.util.file.JarContentFileInfo;
import org.rhq.plugins.jmx.MBeanResourceComponent;
-import org.rhq.plugins.jmx.ObjectNameQueryUtility;
+import org.rhq.plugins.jmx.util.ObjectNameQueryUtility;
/**
* A resource component for managing a web application (WAR) deployed to a Tomcat server.
commit 55d2403c5e1c0dceab624242e849cdda9b65f9dc
Author: Ian Springer <ian.springer(a)redhat.com>
Date: Fri Jan 20 17:39:10 2012 -0500
improve javadoc
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceDiscoveryComponent.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceDiscoveryComponent.java
index b695290..3f6da9a 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceDiscoveryComponent.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/inventory/ResourceDiscoveryComponent.java
@@ -76,8 +76,9 @@ public interface ResourceDiscoveryComponent<T extends ResourceComponent<?>> {
*
* @return a set of discovered resource details that were discovered and can be imported/merged into inventory
*
- * @throws InvalidPluginConfigurationException if a plugin configuration found in the context was somehow invalid
- * and thus caused a failure to connect to a resource
+ * @throws InvalidPluginConfigurationException (used only be the deprecated manual add API) if the plugin
+ * configuration found in the context was somehow invalid and thus
+ * caused a failure to connect to a managed resource
* @throws Exception if a generic error occurred that caused the discovery to abort
*/
Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<T> context)
commit 1189549551b1c290e8ff6989ba3a23719eb0a1b8
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Mon Jan 23 12:09:18 2012 -0500
[BZ 784006] rename agent option to --fullcleanconfig and change the error you get so the user knows the command line argument to pass to set the token.
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 c7e0cfc..805d280 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
@@ -2917,7 +2917,7 @@ public class AgentMain {
new LongOpt("console", LongOpt.REQUIRED_ARGUMENT, null, 'e'),
new LongOpt("daemon", LongOpt.NO_ARGUMENT, null, 'd'),
new LongOpt("cleanconfig", LongOpt.NO_ARGUMENT, null, 'l'),
- new LongOpt("cleanallconfig", LongOpt.NO_ARGUMENT, null, 'L'),
+ new LongOpt("fullcleanconfig", LongOpt.NO_ARGUMENT, null, 'L'),
new LongOpt("advanced", LongOpt.NO_ARGUMENT, null, 'a'),
new LongOpt("setup", LongOpt.NO_ARGUMENT, null, 's'),
new LongOpt("nostart", LongOpt.NO_ARGUMENT, null, 'n'),
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 0b41bb7..8ba3100 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
@@ -614,7 +614,7 @@ public interface AgentI18NResourceKeys {
+ "\\ -h, --help Shows this help message (default)\\n\\\n"
+ "\\ -i, --input=<filename> Specifies a script file to be used for input\\n\\\n"
+ "\\ -l, --cleanconfig Clears out existing configuration and data files, except for the security token.\\n\\\n"
- + "\\ -L, --cleanallconfig Clears out all existing configuration and data files so the agent starts with a totally clean slate\\n\\\n"
+ + "\\ -L, --fullcleanconfig Clears out all existing configuration and data files so the agent starts with a totally clean slate\\n\\\n"
+ "\\ -n, --nostart If specified, the agent will not be automatically started\\n\\\n"
+ "\\ -o, --output=<filename> Specifies a file to write all output (excluding log messages)\\n\\\n"
+ "\\ -p, --pref=<preferences name> Specifies the agent preferences name used to identify what configuration to use\\n\\\n"
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
index 75c4d65..9afc3b9 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
@@ -135,9 +135,11 @@ public class CoreServerServiceImpl implements CoreServerService {
if (agentByName != null) {
// the agent request provided a name that already is in use by an agent. However, the request
// provided a security token that was not assigned to any agent! How can this be? Something is fishy.
- String msg = "The agent asking for registration under the name [" + request.getName()
+ String msg = "The agent asking for registration under the name ["
+ + request.getName()
+ "] provided an invalid security token. This request will fail. "
- + "Please consult an administrator to reconfigure this agent with its proper security token.";
+ + "Please consult an administrator to obtain the agent's proper security token "
+ + "and restart the agent with the option \"-Drhq.agent.security-token=<the valid security token>\"";
throw new AgentRegistrationException(msg);
}
Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(),
@@ -172,9 +174,11 @@ public class CoreServerServiceImpl implements CoreServerService {
+ " and same security token.";
throw new AgentRegistrationException(msg);
} else {
- String msg = "The agent [" + request.getName()
+ String msg = "The agent ["
+ + request.getName()
+ "] is attempting to re-register without a security token. "
- + "Please consult an administrator to reconfigure this agent with its proper security token.";
+ + "Please consult an administrator to obtain the agent's proper security token "
+ + "and restart the agent with the option \"-Drhq.agent.security-token=<the valid security token>\"";
throw new AgentRegistrationException(msg);
}
commit 37407916deff1159eae8b68c226af2a801a681cd
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Sat Jan 21 20:56:15 2012 -0500
back to testng 6.1.1, still issues with upgrading...
diff --git a/pom.xml b/pom.xml
index 4117cf0..3b77493 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,7 +91,9 @@
<jna.version>3.2.5</jna.version>
<twitter4j.version>2.2.4</twitter4j.version>
<commons-codec.version>1.4</commons-codec.version>
- <testng.version>6.3.1</testng.version>
+ <!-- NOTE (ips, 10/04/11): Upgrading testng to 6.2.x causes 10 server-jar tests to fail for an unknown reason. -->
+ <!-- NOTE (jshaughn, 01/20/12): With the latest work, the sserver-jar tests passed using testng to 6.3.1, so perhaps an upgrade is possible -->
+ <testng.version>6.1.1</testng.version>
<cobertura.version>1.9.4.1</cobertura.version>
<augeas.version>0.9.0</augeas.version>
<augeas.classifier>el5</augeas.classifier>
commit 171ca7ef13047426ab71a69d9fa110c2f01a7c60
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Sat Jan 21 19:35:09 2012 -0500
Try upping testng version from 6.1.1 to 6.3.1. This used to cause
problems, with the latest unit test work, let's see if we can run. If
not this commit will be reverted...
diff --git a/pom.xml b/pom.xml
index 3b77493..4117cf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,9 +91,7 @@
<jna.version>3.2.5</jna.version>
<twitter4j.version>2.2.4</twitter4j.version>
<commons-codec.version>1.4</commons-codec.version>
- <!-- NOTE (ips, 10/04/11): Upgrading testng to 6.2.x causes 10 server-jar tests to fail for an unknown reason. -->
- <!-- NOTE (jshaughn, 01/20/12): With the latest work, the sserver-jar tests passed using testng to 6.3.1, so perhaps an upgrade is possible -->
- <testng.version>6.1.1</testng.version>
+ <testng.version>6.3.1</testng.version>
<cobertura.version>1.9.4.1</cobertura.version>
<augeas.version>0.9.0</augeas.version>
<augeas.classifier>el5</augeas.classifier>
commit 9cc28466baff7e226f948b4227cf70f4ef14b078
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Sat Jan 21 17:27:50 2012 -0500
Put back the test group dependency which, I think, effectively disables
these tests. It is a dependency on a group defined in the itests module.
But without it we get server test jar build issues.
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
index 89ff87b..9294ec8 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
@@ -77,6 +77,10 @@ import org.rhq.enterprise.server.util.LookupUtil;
* !!! configured drift server plugin. To enhance this to do that then you may need to model this
* !!! mode like BundleManagerBeanTest
*/
+// TODO: Figure out how to get this test class to run without causing issues in the test-jar generation. I don't
+// understand exactly what the deal is but removing this dependency on an itests group causes the server test jar to
+// not correctly generate the drift package contents.
+@Test(dependsOnGroups = "drift")
public class DriftManagerBeanTest extends AbstractEJB3Test {
private static final boolean ENABLE_TESTS = true;
commit 68a688bc7bf11d2d6cfe22b08a1ffb1d282eb804
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Fri Jan 20 21:59:31 2012 -0500
More work to prevent server jar tests from stepping on each other, or
themselves.
- tests now pass with testng 6.1.1 (current version) and also 6.3.1,
latest version. Each version brought out different issues due to
different execution ordering and constraint checking.
- Avoid the use of DatabaseOperation.CLEAN_INSERT. This deletes all rows
in tables used by the data set. This does not play well with other modules.
Instead use DatabaseOperation.REFRESH and also clean up using
DatabaseOperation.DELETE. These options affect only the rows in the
data set. (see DeleteAlertsTest)
- Unless absolutely necessary, use Before|AfterMethod for database setup
and teardown. The perf hit is typically minimal but the risk of
test class conflict is high. (see DatabaseAndFilePluginDeloymentTest)
- Be more diligent to keep the database clean. For example, in addition to
DatabaseOperation.DELETE, there may be additional data created by the
tests. (see DiscoveryBossBeanTest)
- When possible, assertions should be narrowed to deal with only the data
relevant to the test or test class. Don't assume the database is
necessarily clean. This helps ensure that other test data does not cause
failures, or is not manipulated accidentally. Queries should try to be
qualified with the ids known to be relevant. (see InventoryManagerBeanTest)
- Prefer to use slsb calls to do cleanup, these calls are often better at
ensuring related data is also cleaned up. Hibernate cascading is often
not enough. And straight SQl requires even more diligence. Cleaning up
plugins is very important (see MetadataBeanTest).
- If a test does specific dbsetup make sure it also cleans it up, or move
it to Before|AfterMethod. (see PluginManagerBeanTest)
- Make sure your tests can executein any order, or add specific dependencies
to force ordering. (see ResourceMetadataManagerBean)
Other tips:
- Use unusua/varying ids for canned data. Always starting ids at id 1 is more likely to cause conflicts.
- Always run your test class twice in a row. It should work more than once. If
it doesn't it probably changed state of the db or other shared resource.
- Start your tests with a clean db (dbsetup) and manually inspect the
db to see if any data was left behind (or better, write atool to do it).
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/alert/test/DeleteAlertsTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/alert/test/DeleteAlertsTest.java
index f0ae1b5..487a0ea 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/alert/test/DeleteAlertsTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/alert/test/DeleteAlertsTest.java
@@ -27,7 +27,7 @@ import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.xml.sax.InputSource;
@@ -60,7 +60,7 @@ public class DeleteAlertsTest extends AbstractEJB3Test {
try {
connection = getConnection();
IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
- DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, getDataSet());
+ DatabaseOperation.REFRESH.execute(dbUnitConnection, getDataSet());
} finally {
if (connection != null) {
connection.close();
@@ -70,15 +70,15 @@ public class DeleteAlertsTest extends AbstractEJB3Test {
newResource = getEntityManager().find(Resource.class, 1);
}
- @AfterClass
- public void cleanupDB() throws Exception {
+ @AfterMethod(alwaysRun = true)
+ public void afterMethod() throws Exception {
if ("true".equals(System.getProperty("clean.db"))) {
Connection connection = null;
try {
connection = getConnection();
IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
- DatabaseOperation.DELETE_ALL.execute(dbUnitConnection, getDataSet());
+ DatabaseOperation.DELETE.execute(dbUnitConnection, getDataSet());
} finally {
if (connection != null) {
connection.close();
@@ -103,17 +103,17 @@ public class DeleteAlertsTest extends AbstractEJB3Test {
int resourceTypeId = 1;
int deletedCount = alertManager.deleteAlertsByContext(superuser, EntityContext.forTemplate(resourceTypeId));
- List<AlertConditionLog> alertConditionLogs = getEntityManager().createQuery(
- "from AlertConditionLog log where log.id = :id").setParameter("id", 2).getResultList();
+ List<AlertConditionLog> alertConditionLogs = getEntityManager()
+ .createQuery("from AlertConditionLog log where log.id = :id").setParameter("id", 2).getResultList();
- List<AlertNotificationLog> notificationLogs = getEntityManager().createQuery(
- "from AlertNotificationLog log where log.id = :id").setParameter("id", 2).getResultList();
+ List<AlertNotificationLog> notificationLogs = getEntityManager()
+ .createQuery("from AlertNotificationLog log where log.id = :id").setParameter("id", 2).getResultList();
assertEquals("Failed to delete alerts by template", 1, deletedCount);
- assertEquals("Failed to delete alert condition logs when deleting alerts by template", 0, alertConditionLogs
- .size());
- assertEquals("Failed to delete alert notification logs when deleting alerts by template", 0, notificationLogs
- .size());
+ assertEquals("Failed to delete alert condition logs when deleting alerts by template", 0,
+ alertConditionLogs.size());
+ assertEquals("Failed to delete alert notification logs when deleting alerts by template", 0,
+ notificationLogs.size());
}
public void testAlertDeleteInRange() {
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/plugin/DatabaseAndFilePluginDeploymentTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/plugin/DatabaseAndFilePluginDeploymentTest.java
index c539a44..c6180fc 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/plugin/DatabaseAndFilePluginDeploymentTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/plugin/DatabaseAndFilePluginDeploymentTest.java
@@ -110,6 +110,128 @@ public class DatabaseAndFilePluginDeploymentTest extends AbstractEJB3Test {
// | 1.0-feb-2 | | | | one of the files gets deleted
// --------------------------------------------------------------------------
+ @BeforeClass
+ public void beforeClass() throws Exception {
+ Calendar cal = Calendar.getInstance();
+ cal.set(2009, Calendar.FEBRUARY, 1, 1, 0, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ Date febDate = cal.getTime();
+ cal.set(2009, Calendar.JUNE, 1, 1, 0, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ Date juneDate = cal.getTime();
+ testTimestamps.put(TESTPLUGIN_1_0_FEB, febDate);
+ testTimestamps.put(TESTPLUGIN_1_0_JUN, juneDate);
+ testTimestamps.put(TESTPLUGIN_1_1_FEB, febDate);
+ testTimestamps.put(TESTPLUGIN_1_1_JUN, juneDate);
+ testTimestamps.put(TESTPLUGIN_1_0_FEB2, febDate);
+
+ pluginMgr = LookupUtil.getPluginManager();
+ subjectManager = LookupUtil.getSubjectManager();
+
+ File deployDir = new File(DEPLOY_LOCATION);
+ deployDir.mkdirs();
+ assert deployDir.isDirectory();
+
+ File jarsDir = new File(JARS_LOCATION);
+ jarsDir.mkdirs();
+ assert jarsDir.isDirectory();
+
+ testPluginFiles.put(TESTPLUGIN_1_0_FEB, new File(jarsDir, TESTPLUGIN_1_0_FEB + ".jar"));
+ testPluginFiles.put(TESTPLUGIN_1_0_JUN, new File(jarsDir, TESTPLUGIN_1_0_JUN + ".jar"));
+ testPluginFiles.put(TESTPLUGIN_1_1_FEB, new File(jarsDir, TESTPLUGIN_1_1_FEB + ".jar"));
+ testPluginFiles.put(TESTPLUGIN_1_1_JUN, new File(jarsDir, TESTPLUGIN_1_1_JUN + ".jar"));
+ testPluginFiles.put(TESTPLUGIN_1_0_FEB2, new File(jarsDir, TESTPLUGIN_1_0_FEB2 + ".jar"));
+
+ for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) {
+ File descriptorFile = new File(DESCRIPTORS_LOCATION, entry.getKey() + ".xml");
+ File file = entry.getValue();
+ buildPluginJar(descriptorFile, file);
+ assert file.exists();
+
+ PluginDescriptor descriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI().toURL());
+ testPluginDescriptors.put(entry.getKey(), descriptor);
+
+ Plugin pluginPojo = new Plugin(PLUGIN_NAME, file.getName());
+ pluginPojo.setVersion(descriptor.getVersion());
+ pluginPojo.setMd5(MessageDigestGenerator.getDigestString(file));
+ pluginPojo.setMtime(testTimestamps.get(entry.getKey()).getTime());
+ testPlugins.put(entry.getKey(), pluginPojo);
+ }
+
+ return;
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void afterClass() throws Exception {
+ for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) {
+ File doomed = entry.getValue();
+ doomed.delete();
+ }
+ File jarsDir = new File(JARS_LOCATION);
+ jarsDir.delete();
+
+ File deployDir = new File(DEPLOY_LOCATION);
+ emptyDirectory(deployDir);
+ deployDir.delete();
+
+ return;
+ }
+
+ @BeforeMethod
+ public void beforeMethod() throws Exception {
+ afterMethod(); // we clean up before and after, just to be sure we're clean
+
+ File deployDir = new File(DEPLOY_LOCATION);
+ deployDir.mkdirs();
+ assert deployDir.isDirectory();
+
+ File jarsDir = new File(JARS_LOCATION);
+ jarsDir.mkdirs();
+ assert jarsDir.isDirectory();
+
+ for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) {
+ File descriptorFile = new File(DESCRIPTORS_LOCATION, entry.getKey() + ".xml");
+ File file = entry.getValue();
+ buildPluginJar(descriptorFile, file);
+ assert file.exists();
+
+ PluginDescriptor descriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI().toURL());
+ testPluginDescriptors.put(entry.getKey(), descriptor);
+
+ Plugin pluginPojo = new Plugin(PLUGIN_NAME, file.getName());
+ pluginPojo.setVersion(descriptor.getVersion());
+ pluginPojo.setMd5(MessageDigestGenerator.getDigestString(file));
+ pluginPojo.setMtime(testTimestamps.get(entry.getKey()).getTime());
+ testPlugins.put(entry.getKey(), pluginPojo);
+ }
+
+ }
+
+ @AfterMethod(alwaysRun = true)
+ @SuppressWarnings("unchecked")
+ public void afterMethod() throws Exception {
+
+ emptyDirectory(new File(DEPLOY_LOCATION));
+
+ TransactionManager tm = getTransactionManager();
+ tm.begin();
+ EntityManager em = getEntityManager();
+ try {
+ Query q = em.createNamedQuery(Plugin.QUERY_FIND_BY_NAME);
+ q.setParameter("name", PLUGIN_NAME);
+ List<Plugin> doomedPlugins = q.getResultList();
+ for (Plugin doomedPlugin : doomedPlugins) {
+ em.remove(em.find(Plugin.class, doomedPlugin.getId()));
+ }
+ } catch (NoResultException ignore) {
+ } finally {
+ tm.commit();
+ em.close();
+ }
+
+ return;
+ }
+
public void test0() throws Exception {
Plugin plugin10feb = deployPluginJarToFilesystem(TESTPLUGIN_1_0_FEB);
deployPluginJarToDatabase(TESTPLUGIN_1_0_FEB);
@@ -327,102 +449,6 @@ public class DatabaseAndFilePluginDeploymentTest extends AbstractEJB3Test {
return;
}
- @BeforeClass
- public void beforeClass() throws Exception {
- Calendar cal = Calendar.getInstance();
- cal.set(2009, Calendar.FEBRUARY, 1, 1, 0, 0);
- cal.set(Calendar.MILLISECOND, 0);
- Date febDate = cal.getTime();
- cal.set(2009, Calendar.JUNE, 1, 1, 0, 0);
- cal.set(Calendar.MILLISECOND, 0);
- Date juneDate = cal.getTime();
- testTimestamps.put(TESTPLUGIN_1_0_FEB, febDate);
- testTimestamps.put(TESTPLUGIN_1_0_JUN, juneDate);
- testTimestamps.put(TESTPLUGIN_1_1_FEB, febDate);
- testTimestamps.put(TESTPLUGIN_1_1_JUN, juneDate);
- testTimestamps.put(TESTPLUGIN_1_0_FEB2, febDate);
-
- pluginMgr = LookupUtil.getPluginManager();
- subjectManager = LookupUtil.getSubjectManager();
-
- File deployDir = new File(DEPLOY_LOCATION);
- deployDir.mkdirs();
- assert deployDir.isDirectory();
-
- File jarsDir = new File(JARS_LOCATION);
- jarsDir.mkdirs();
- assert jarsDir.isDirectory();
-
- testPluginFiles.put(TESTPLUGIN_1_0_FEB, new File(jarsDir, TESTPLUGIN_1_0_FEB + ".jar"));
- testPluginFiles.put(TESTPLUGIN_1_0_JUN, new File(jarsDir, TESTPLUGIN_1_0_JUN + ".jar"));
- testPluginFiles.put(TESTPLUGIN_1_1_FEB, new File(jarsDir, TESTPLUGIN_1_1_FEB + ".jar"));
- testPluginFiles.put(TESTPLUGIN_1_1_JUN, new File(jarsDir, TESTPLUGIN_1_1_JUN + ".jar"));
- testPluginFiles.put(TESTPLUGIN_1_0_FEB2, new File(jarsDir, TESTPLUGIN_1_0_FEB2 + ".jar"));
-
- for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) {
- File descriptorFile = new File(DESCRIPTORS_LOCATION, entry.getKey() + ".xml");
- File file = entry.getValue();
- buildPluginJar(descriptorFile, file);
- assert file.exists();
-
- PluginDescriptor descriptor = AgentPluginDescriptorUtil.loadPluginDescriptorFromUrl(file.toURI().toURL());
- testPluginDescriptors.put(entry.getKey(), descriptor);
-
- Plugin pluginPojo = new Plugin(PLUGIN_NAME, file.getName());
- pluginPojo.setVersion(descriptor.getVersion());
- pluginPojo.setMd5(MessageDigestGenerator.getDigestString(file));
- pluginPojo.setMtime(testTimestamps.get(entry.getKey()).getTime());
- testPlugins.put(entry.getKey(), pluginPojo);
- }
-
- return;
- }
-
- @AfterClass
- public void afterClass() throws Exception {
- for (Map.Entry<String, File> entry : testPluginFiles.entrySet()) {
- File doomed = entry.getValue();
- doomed.delete();
- }
- File jarsDir = new File(JARS_LOCATION);
- jarsDir.delete();
-
- File deployDir = new File(DEPLOY_LOCATION);
- emptyDirectory(deployDir);
- deployDir.delete();
-
- return;
- }
-
- @BeforeMethod
- public void beforeMethod() throws Exception {
- afterMethod(); // we clean up before and after, just to be sure we're clean
- }
-
- @AfterMethod
- @SuppressWarnings("unchecked")
- public void afterMethod() throws Exception {
- emptyDirectory(new File(DEPLOY_LOCATION));
-
- TransactionManager tm = getTransactionManager();
- tm.begin();
- EntityManager em = getEntityManager();
- try {
- Query q = em.createNamedQuery(Plugin.QUERY_FIND_BY_NAME);
- q.setParameter("name", PLUGIN_NAME);
- List<Plugin> doomedPlugins = q.getResultList();
- for (Plugin doomedPlugin : doomedPlugins) {
- em.remove(em.find(Plugin.class, doomedPlugin.getId()));
- }
- } catch (NoResultException ignore) {
- } finally {
- tm.commit();
- em.close();
- }
-
- return;
- }
-
private void assertSamePlugin(Plugin p1, Plugin p2) throws Exception {
assert p1.getName().equals(p2.getName()) : "NAME: " + p1 + "!=" + p2;
assert p1.getMd5().equals(p2.getMd5()) : "MD5: " + p1 + "!=" + p2;
@@ -568,6 +594,9 @@ public class DatabaseAndFilePluginDeploymentTest extends AbstractEJB3Test {
}
private void emptyDirectory(File dirToEmpty) {
+ if (!dirToEmpty.isDirectory()) {
+ return;
+ }
File[] doomedFiles = dirToEmpty.listFiles();
for (File doomedFile : doomedFiles) {
doomedFile.delete();
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
index 630b778..6bda968 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
@@ -23,10 +23,13 @@ import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
+import java.util.List;
import java.util.Random;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
@@ -54,11 +57,13 @@ import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.enterprise.server.core.comm.ServerCommunicationsService;
import org.rhq.enterprise.server.core.comm.ServerCommunicationsServiceMBean;
+import org.rhq.enterprise.server.resource.ResourceManagerLocal;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.util.LookupUtil;
public class DiscoveryBossBeanTest extends AbstractEJB3Test {
private DiscoveryBossLocal discoveryBoss;
+ private ResourceManagerLocal resourceManager;
private MBeanServer dummyJBossMBeanServer;
private ResourceType platformType;
@@ -84,6 +89,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
ServerCommunicationsServiceMBean.OBJECT_NAME);
initDB();
+
platformType = getEntityManager().find(ResourceType.class, 1);
serverType = getEntityManager().find(ResourceType.class, 2);
serviceType1 = getEntityManager().find(ResourceType.class, 3);
@@ -94,6 +100,8 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
@AfterMethod(alwaysRun = true)
public void afterMethod() throws Exception {
MBeanServerFactory.releaseMBeanServer(dummyJBossMBeanServer);
+
+ cleanDB();
}
@Test(groups = "integration.ejb3")
@@ -180,7 +188,51 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
connection = getConnection();
IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
setDbType(dbUnitConnection);
- DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, getDataSet());
+ DatabaseOperation.REFRESH.execute(dbUnitConnection, getDataSet());
+ } finally {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ public void cleanDB() throws Exception {
+ Connection connection = null;
+ EntityManager em = null;
+
+ try {
+ getTransactionManager().begin();
+ em = getEntityManager();
+
+ Query q;
+ List<?> doomed;
+ q = em.createQuery("SELECT r FROM Resource r WHERE r.resourceType.id <= 4 ORDER BY r.id DESC");
+ doomed = q.getResultList();
+ for (Object removeMe : doomed) {
+ em.remove(em.getReference(Resource.class, ((Resource) removeMe).getId()));
+ }
+ em.flush();
+ getTransactionManager().commit();
+ em.close();
+ em = null;
+ } catch (Exception e) {
+ try {
+ System.out.println("CANNOT CLEAN UP TEST: Cause: " + e);
+ getTransactionManager().rollback();
+ } catch (Exception ignore) {
+ }
+ } finally {
+ if (null != em) {
+ em.close();
+ }
+ }
+
+ try {
+ connection = getConnection();
+
+ IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
+ setDbType(dbUnitConnection);
+ DatabaseOperation.DELETE.execute(dbUnitConnection, getDataSet());
} finally {
if (connection != null) {
connection.close();
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/inventory/InventoryManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/inventory/InventoryManagerBeanTest.java
index 6aa8c4d..dcf83fe 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/inventory/InventoryManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/inventory/InventoryManagerBeanTest.java
@@ -17,7 +17,8 @@ import org.dbunit.ext.oracle.Oracle10DataTypeFactory;
import org.dbunit.ext.oracle.OracleDataTypeFactory;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
-import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.xml.sax.InputSource;
@@ -29,48 +30,49 @@ import org.rhq.enterprise.server.util.LookupUtil;
public class InventoryManagerBeanTest extends AbstractEJB3Test {
- @BeforeClass
- public void deleteResourceTypes() throws Exception {
+ private static List<Integer> deletedTypeIds = asList(1, 2, 3, 4, 5);
+
+ @BeforeMethod
+ public void beforeMethod() throws Exception {
initDB();
getTransactionManager().begin();
- List<Integer> resourceTypeIds = asList(1, 2, 3, 4, 5);
-
+
InventoryManagerLocal inventoryMgr = LookupUtil.getInventoryManager();
- inventoryMgr.markTypesDeleted(resourceTypeIds);
+ inventoryMgr.markTypesDeleted(deletedTypeIds);
getTransactionManager().commit();
}
+ @AfterMethod(alwaysRun = true)
+ public void afterMethod() throws Exception {
+ cleanDB();
+ }
+
@SuppressWarnings("unchecked")
@Test
public void markTypesAndTheirChildTypesForDeletion() {
- List<ResourceType> resourceTypes = getEntityManager().createQuery(
- "from ResourceType t where t.id in (:resourceTypeIds)")
- .setParameter("resourceTypeIds", asList(1, 2, 3, 4, 5))
- .getResultList();
+ List<ResourceType> resourceTypes = getEntityManager()
+ .createQuery("from ResourceType t where t.id in (:resourceTypeIds)")
+ .setParameter("resourceTypeIds", deletedTypeIds).getResultList();
assertEquals("Failed to retrieve all resource types", 5, resourceTypes.size());
List<Integer> typesNotDeleted = new ArrayList<Integer>();
for (ResourceType type : resourceTypes) {
- if (!type.isDeleted()) {
- typesNotDeleted.add(type.getId());
- }
+ if (!type.isDeleted()) {
+ typesNotDeleted.add(type.getId());
+ }
}
- assertEquals(
- "Failed to mark for deletion resource types with the following ids: " + typesNotDeleted + ".",
- 0,
- typesNotDeleted.size()
- );
+ assertEquals("Failed to mark for deletion resource types with the following ids: " + typesNotDeleted + ".", 0,
+ typesNotDeleted.size());
}
@SuppressWarnings("unchecked")
@Test
public void uninventoryResourcesOfTypesMarkedForDeletion() {
List<Resource> resources = getEntityManager().createQuery("from Resource r where r.id in (:resourceIds)")
- .setParameter("resourceIds", asList(1, 2))
- .getResultList();
+ .setParameter("resourceIds", asList(1, 2)).getResultList();
assertEquals("Failed to retrieve all resources", 2, resources.size());
@@ -82,11 +84,8 @@ public class InventoryManagerBeanTest extends AbstractEJB3Test {
}
assertEquals(
- "Resources of types marked for deletion should be uninventoried. Resources with the following ids " +
- "should have been uninventoried: " + resourcesNotDeleted + ".",
- 0,
- resourcesNotDeleted.size()
- );
+ "Resources of types marked for deletion should be uninventoried. Resources with the following ids "
+ + "should have been uninventoried: " + resourcesNotDeleted + ".", 0, resourcesNotDeleted.size());
}
@Test
@@ -94,7 +93,16 @@ public class InventoryManagerBeanTest extends AbstractEJB3Test {
InventoryManagerLocal inventoryMgr = LookupUtil.getInventoryManager();
List<ResourceType> deletedTypes = inventoryMgr.getDeletedTypes();
- assertEquals("Expected to get back five deleted resource types", 5, deletedTypes.size());
+ // protect against other db detritus, just look for the ones we expect
+ int resultSize = deletedTypes.size();
+ assertTrue("Expected at least five deleted types", resultSize >= 5);
+ List<Integer> resultIds = new ArrayList(resultSize);
+ for (ResourceType rt : deletedTypes) {
+ resultIds.add(rt.getId());
+ }
+ for (Integer id : deletedTypeIds) {
+ assert (resultIds.contains(id));
+ }
}
@Test
@@ -111,7 +119,7 @@ public class InventoryManagerBeanTest extends AbstractEJB3Test {
ResourceType resourceType = getEntityManager().find(ResourceType.class, 6);
assertFalse(resourceType + " is not ready for removal because it is not deleted.",
- inventoryMgr.isReadyForPermanentRemoval(resourceType));
+ inventoryMgr.isReadyForPermanentRemoval(resourceType));
}
public void initDB() throws Exception {
@@ -121,7 +129,22 @@ public class InventoryManagerBeanTest extends AbstractEJB3Test {
connection = getConnection();
IDatabaseConnection conn = new DatabaseConnection(connection);
setDbType(conn);
- DatabaseOperation.CLEAN_INSERT.execute(conn, getDataSet());
+ DatabaseOperation.REFRESH.execute(conn, getDataSet());
+ } finally {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ public void cleanDB() throws Exception {
+ Connection connection = null;
+
+ try {
+ connection = getConnection();
+ IDatabaseConnection conn = new DatabaseConnection(connection);
+ setDbType(conn);
+ DatabaseOperation.DELETE.execute(conn, getDataSet());
} finally {
if (connection != null) {
connection.close();
@@ -146,13 +169,13 @@ public class InventoryManagerBeanTest extends AbstractEJB3Test {
}
if (type != null) {
- dbConfig.setProperty("http://www.dbunit.org/properties/datatypeFactory",type);
+ dbConfig.setProperty("http://www.dbunit.org/properties/datatypeFactory", type);
}
}
IDataSet getDataSet() throws Exception {
FlatXmlProducer xmlProducer = new FlatXmlProducer(new InputSource(getClass().getResourceAsStream(
- getDataSetFile())));
+ getDataSetFile())));
xmlProducer.setColumnSensing(true);
return new FlatXmlDataSet(xmlProducer);
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
index fac9251..d4249eb 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
@@ -24,13 +24,14 @@ import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
-import org.testng.annotations.AfterGroups;
+import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.BeforeMethod;
import org.xml.sax.InputSource;
import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
+import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.criteria.ResourceTypeCriteria;
import org.rhq.core.domain.plugin.Plugin;
import org.rhq.core.domain.resource.ResourceType;
@@ -38,12 +39,14 @@ import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.bundle.TestBundleServerPluginService;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
+import org.rhq.enterprise.server.scheduler.jobs.PurgePluginsJob;
+import org.rhq.enterprise.server.scheduler.jobs.PurgeResourceTypesJob;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.util.LookupUtil;
public class MetadataBeanTest extends AbstractEJB3Test {
- private static List<String> plugins = new ArrayList<String>();
+ private List<Integer> pluginIds = new ArrayList<Integer>();
@Override
protected boolean isDBResetNeeded() {
@@ -60,12 +63,14 @@ public class MetadataBeanTest extends AbstractEJB3Test {
* at what plugins are in the database, and then look for corresponding plugin files on the file system. MetadataTest
* however removes the generated plugin files during each test run.
*/
- @AfterGroups(alwaysRun = true, groups = { "plugin.metadata" })
- void afterGroups() throws Exception {
- getTransactionManager().begin();
- getEntityManager().createQuery("delete from Plugin p where p.name in (:plugins)")
- .setParameter("plugins", plugins).executeUpdate();
- getTransactionManager().commit();
+ @AfterClass(alwaysRun = true, groups = { "plugin.metadata" })
+ void afterClass() throws Exception {
+ PluginManagerLocal pluginMgr = LookupUtil.getPluginManager();
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+ pluginMgr.deletePlugins(overlord, pluginIds);
+ pluginMgr.markPluginsForPurge(overlord, pluginIds);
+ new PurgePluginsJob().executeJobCode(null);
+ new PurgeResourceTypesJob().executeJobCode(null);
}
@BeforeMethod(groups = { "plugin.metadata" }, dependsOnGroups = { "integration.ejb3" })
@@ -94,7 +99,9 @@ public class MetadataBeanTest extends AbstractEJB3Test {
connection = getConnection();
DatabaseConnection dbunitConnection = new DatabaseConnection(connection);
setDbType(dbunitConnection);
- DatabaseOperation.CLEAN_INSERT.execute(dbunitConnection, getDataSet());
+ // note - this info should already be in the db as part of dbsetup, but just in case
+ // perform the refresh. Do not DELETE this data set as it may be assumed in other tests.
+ DatabaseOperation.REFRESH.execute(dbunitConnection, getDataSet());
} finally {
if (connection != null) {
connection.close();
@@ -151,7 +158,7 @@ public class MetadataBeanTest extends AbstractEJB3Test {
pluginMgr.registerPlugin(subjectMgr.getOverlord(), plugin, pluginDescriptor, null, true);
- plugins.add(plugin.getName());
+ pluginIds.add(plugin.getId());
}
private URL getDescriptorURL(String descriptor) {
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/PluginManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/PluginManagerBeanTest.java
index a12d7a8..4ccad7f 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/PluginManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/PluginManagerBeanTest.java
@@ -1,5 +1,7 @@
package org.rhq.enterprise.server.resource.metadata;
+import static java.util.Arrays.asList;
+
import java.util.List;
import javax.ejb.EJBException;
@@ -11,27 +13,23 @@ import org.rhq.core.domain.plugin.PluginStatusType;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
-import static java.util.Arrays.asList;
-
public class PluginManagerBeanTest extends MetadataBeanTest {
SubjectManagerLocal subjectMgr;
PluginManagerLocal pluginMgr;
- @Test(groups = {"plugin.metadata", "PluginManagerBean"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" })
public void registerPlugins() throws Exception {
subjectMgr = LookupUtil.getSubjectManager();
pluginMgr = LookupUtil.getPluginManager();
- setupDB();
-
createPlugin("test-plugin1", "1.0", "plugin_1.xml");
createPlugin("test-plugin2", "1.0", "plugin_2.xml");
createPlugin("test-plugin3", "1.0", "plugin_3.xml");
}
- @Test(groups = {"plugin.metadata", "PluginManagerBean"}, dependsOnMethods = {"registerPlugins"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "registerPlugins" })
public void disablePlugin() throws Exception {
Plugin plugin = getPlugin("PluginManagerBeanTestPlugin3");
@@ -41,7 +39,7 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertFalse("Failed to disable plugin", plugin.isEnabled());
}
- @Test(groups = {"plugin.metadata", "PluginManagerBean"}, dependsOnMethods = {"registerPlugins"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "registerPlugins" })
public void doNotDisablePluginIfDependentPluginsAreNotAlsoDisabled() throws Exception {
Plugin plugin = getPlugin("PluginManagerBeanTestPlugin1");
EJBException exception = null;
@@ -54,14 +52,11 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertNotNull("Expected exception to be thrown when trying to disable a plugin that has dependent plugins",
exception);
- assertTrue(
- "Expected an IllegalArgumentException when trying to disable a plugin with dependent plugins",
- exception.getCausedByException() instanceof IllegalArgumentException
- );
+ assertTrue("Expected an IllegalArgumentException when trying to disable a plugin with dependent plugins",
+ exception.getCausedByException() instanceof IllegalArgumentException);
}
- @Test(groups = {"plugin.metadata", "PluginManagerBean"},
- dependsOnMethods = {"doNotDisablePluginIfDependentPluginsAreNotAlsoDisabled"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "doNotDisablePluginIfDependentPluginsAreNotAlsoDisabled" })
public void disablePluginAndDependentPlugins() throws Exception {
Plugin plugin1 = getPlugin("PluginManagerBeanTestPlugin1");
Plugin plugin2 = getPlugin("PluginManagerBeanTestPlugin2");
@@ -75,7 +70,7 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertFalse("Failed to disable plugin", plugin2.isEnabled());
}
- @Test(groups = {"plugin.metadata", "PluginManagerBean"}, dependsOnMethods = {"disablePluginAndDependentPlugins"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "disablePluginAndDependentPlugins" })
public void enablePlugins() throws Exception {
Plugin plugin1 = getPlugin("PluginManagerBeanTestPlugin1");
Plugin plugin2 = getPlugin("PluginManagerBeanTestPlugin2");
@@ -89,7 +84,7 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertTrue("Failed to enable plugin", plugin2.isEnabled());
}
- @Test(groups = {"plugin.metadata", "PluginManagerBean"}, dependsOnMethods = {"enablePlugins"})
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "enablePlugins" })
public void doNotDeletePluginIfDependentPluginIsNotAlsoDeleted() throws Exception {
Plugin plugin = getPlugin("PluginManagerBeanTestPlugin1");
EJBException exception = null;
@@ -102,14 +97,11 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertNotNull("Expected exception to be thrown when trying to delete a plugin that has dependent plugins",
exception);
- assertTrue(
- "Expected an IllegalArgumentException when trying to delete a plugin with dependent plugins",
- exception.getCausedByException() instanceof IllegalArgumentException
- );
- }
-
- @Test(groups = {"plugin.metadata", "PluginManagerBean"},
- dependsOnMethods = {"doNotDeletePluginIfDependentPluginIsNotAlsoDeleted"})
+ assertTrue("Expected an IllegalArgumentException when trying to delete a plugin with dependent plugins",
+ exception.getCausedByException() instanceof IllegalArgumentException);
+ }
+
+ @Test(groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "doNotDeletePluginIfDependentPluginIsNotAlsoDeleted" })
public void deletePlugins() throws Exception {
Plugin plugin1 = getPlugin("PluginManagerBeanTestPlugin1");
Plugin plugin2 = getPlugin("PluginManagerBeanTestPlugin2");
@@ -123,7 +115,7 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
assertTrue("Expected plugin status to be set to DELETED", plugin2.getStatus() == PluginStatusType.DELETED);
}
- @Test(enabled = false, groups = {"plugin.metadata", "PluginManagerBean"}, dependsOnMethods = {"deletePlugins"})
+ @Test(enabled = false, groups = { "plugin.metadata", "PluginManagerBean" }, dependsOnMethods = { "deletePlugins" })
public void purgePlugins() throws Exception {
Plugin plugin1 = getPlugin("PluginManagerBeanTestPlugin1",
"Deleting a plugin should not remove it from the database");
@@ -144,8 +136,7 @@ public class PluginManagerBeanTest extends MetadataBeanTest {
Plugin getPlugin(String name, String msg) {
List<Plugin> plugins = getEntityManager().createQuery("from Plugin where name = :name")
- .setParameter("name", name)
- .getResultList();
+ .setParameter("name", name).getResultList();
assertTrue("Failed to find plugin <$name>: $msg", plugins.size() == 1);
return plugins.get(0);
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBeanTest.java
index 415eb99..7155c3d 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ResourceMetadataManagerBeanTest.java
@@ -1,5 +1,7 @@
package org.rhq.enterprise.server.resource.metadata;
+import static java.util.Arrays.asList;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -22,7 +24,6 @@ import org.rhq.core.domain.bundle.ResourceTypeBundleConfiguration;
import org.rhq.core.domain.bundle.ResourceTypeBundleConfiguration.BundleDestinationBaseDirectory;
import org.rhq.core.domain.bundle.ResourceTypeBundleConfiguration.BundleDestinationBaseDirectory.Context;
import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.configuration.definition.ConfigurationTemplate;
import org.rhq.core.domain.content.Package;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.criteria.OperationDefinitionCriteria;
@@ -49,8 +50,6 @@ import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
-import static java.util.Arrays.asList;
-
public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(groups = { "plugin.metadata", "NewPlugin" })
@@ -118,7 +117,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
}
}
- @Test(groups = { "plugin.metadata", "NewPlugin" })
+ @Test(dependsOnMethods = { "registerPluginWithDuplicateDriftDefinitions" }, groups = { "plugin.metadata",
+ "NewPlugin" })
public void registerPlugin() throws Exception {
createPlugin("test-plugin.jar", "1.0", "plugin_v1.xml");
}
@@ -146,8 +146,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "persistNewTypes" }, groups = { "plugin.metadata", "NewPlugin" })
public void persistEventDefinitions() throws Exception {
- assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "eventDefinitions", asList("logAEntry",
- "logBEntry"));
+ assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "eventDefinitions",
+ asList("logAEntry", "logBEntry"));
}
@Test(dependsOnMethods = { "persistNewTypes" }, groups = { "plugin.metadata", "NewPlugin" })
@@ -246,8 +246,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "persistNewTypes" }, groups = { "plugin.metadata", "NewPlugin" })
public void persistPackageTypes() throws Exception {
- assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "packageTypes", asList("ServerA.Content.1",
- "ServerA.Content.2"));
+ assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "packageTypes",
+ asList("ServerA.Content.1", "ServerA.Content.2"));
}
@Test(groups = { "plugin.metadata", "UpgradePlugin" }, dependsOnGroups = { "NewPlugin" })
@@ -257,8 +257,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "upgradePlugin" }, groups = { "plugin.metadata", "UpgradePlugin" })
public void upgradeOperationDefinitions() throws Exception {
- assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "operationDefinitions", asList("start",
- "shutdown", "restart"));
+ assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "operationDefinitions",
+ asList("start", "shutdown", "restart"));
}
@Test(dependsOnMethods = { "upgradePlugin" }, groups = { "plugin.metadata", "UpgradePlugin" })
@@ -273,8 +273,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "upgradePlugin" }, groups = { "plugin.metadata", "UpgradePlugin" })
public void upgradeEventDefinitions() throws Exception {
- assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "eventDefinitions", asList("logAEntry",
- "logCEntry"));
+ assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "eventDefinitions",
+ asList("logAEntry", "logCEntry"));
}
@Test(dependsOnMethods = { "upgradePlugin" }, groups = { "plugin.metadata", "UpgradePlugin" })
@@ -349,8 +349,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "upgradePlugin" }, groups = { "plugin.metadata", "UpgradePlugin" })
public void upgradePackageTypes() throws Exception {
- assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "packageTypes", asList("ServerA.Content.1",
- "ServerA.Content.3"));
+ assertResourceTypeAssociationEquals("ServerA", "TestPlugin", "packageTypes",
+ asList("ServerA.Content.1", "ServerA.Content.3"));
}
@Test(groups = { "RemoveTypes" }, dependsOnGroups = { "UpgradePlugin" })
@@ -375,17 +375,17 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
criteria.addFilterResourceTypeName("ServerC");
criteria.addFilterName("run");
- List<OperationDefinition> operationDefs = operationMgr.findOperationDefinitionsByCriteria(subjectMgr
- .getOverlord(), criteria);
+ List<OperationDefinition> operationDefs = operationMgr.findOperationDefinitionsByCriteria(
+ subjectMgr.getOverlord(), criteria);
assertEquals("The operation definition should have been deleted", 0, operationDefs.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteEventDefsForRemovedType() throws Exception {
- List<?> results = getEntityManager().createQuery(
- "from EventDefinition e where e.name = :ename and e.resourceType.name = :rname").setParameter("ename",
- "serverCEvent").setParameter("rname", "ServerC").getResultList();
+ List<?> results = getEntityManager()
+ .createQuery("from EventDefinition e where e.name = :ename and e.resourceType.name = :rname")
+ .setParameter("ename", "serverCEvent").setParameter("rname", "ServerC").getResultList();
assertEquals("The event definition(s) should have been deleted", 0, results.size());
}
@@ -425,29 +425,30 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteTypeAndAllItsDescedantTypes() throws Exception {
- List<?> typesNotRemoved = getEntityManager().createQuery(
- "from ResourceType t where t.plugin = :plugin and t.name in (:resourceTypes)").setParameter("plugin",
- "RemoveTypesPlugin").setParameter("resourceTypes",
- asList("ServerE", "ServerE1", "ServerE2", "ServerE3", "ServerE4")).getResultList();
+ List<?> typesNotRemoved = getEntityManager()
+ .createQuery("from ResourceType t where t.plugin = :plugin and t.name in (:resourceTypes)")
+ .setParameter("plugin", "RemoveTypesPlugin")
+ .setParameter("resourceTypes", asList("ServerE", "ServerE1", "ServerE2", "ServerE3", "ServerE4"))
+ .getResultList();
assertEquals("Failed to delete resource type or one or more of its descendant types", 0, typesNotRemoved.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteProcessScans() {
- List<?> processScans = getEntityManager().createQuery(
- "from ProcessScan p where p.name = :name1 or p.name = :name2").setParameter("name1", "scan1").setParameter(
- "name2", "scan2").getResultList();
+ List<?> processScans = getEntityManager()
+ .createQuery("from ProcessScan p where p.name = :name1 or p.name = :name2").setParameter("name1", "scan1")
+ .setParameter("name2", "scan2").getResultList();
assertEquals("The process scans should have been deleted", 0, processScans.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteSubcategories() {
- List<?> subcategories = getEntityManager().createQuery(
- "from ResourceSubCategory r where r.name = :name1 or r.name = :name2 or r.name = :name3").setParameter(
- "name1", "ServerC.Category1").setParameter("name2", "ServerC.Category2").setParameter("name3",
- "ServerC.NestedCategory1").getResultList();
+ List<?> subcategories = getEntityManager()
+ .createQuery("from ResourceSubCategory r where r.name = :name1 or r.name = :name2 or r.name = :name3")
+ .setParameter("name1", "ServerC.Category1").setParameter("name2", "ServerC.Category2")
+ .setParameter("name3", "ServerC.NestedCategory1").getResultList();
assertEquals("The subcategories should have been deleted", 0, subcategories.size());
}
@@ -462,8 +463,8 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
List<Resource> resources = resourceMgr.findResourcesByCriteria(subjectMgr.getOverlord(), criteria);
- assertTrue("Did not expect to find any more that three resources. Database might need to be reset", resources
- .size() < 4);
+ assertTrue("Did not expect to find any more that three resources. Database might need to be reset",
+ resources.size() < 4);
// We won't do anything more rigorous that making sure the resources were marked uninventoried.
// Resource deletion is an expensive, time-consuming process; consequently, it is carried out
@@ -471,57 +472,57 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
// quickly as it is basically just updates the the inventory status to UNINVENTORIED for the
// resources to be deleted.
for (Resource resource : resources) {
- assertEquals("The resource should have been marked for deletion", InventoryStatus.UNINVENTORIED == resource
- .getInventoryStatus());
+ assertEquals("The resource should have been marked for deletion",
+ InventoryStatus.UNINVENTORIED == resource.getInventoryStatus());
}
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteBundles() {
- List<?> bundles = getEntityManager().createQuery("from Bundle b where b.bundleType.name = :name").setParameter(
- "name", "Test Bundle").getResultList();
+ List<?> bundles = getEntityManager().createQuery("from Bundle b where b.bundleType.name = :name")
+ .setParameter("name", "Test Bundle").getResultList();
assertEquals("Failed to delete the bundles", 0, bundles.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteBundleTypes() {
- List<?> bundleTypes = getEntityManager().createQuery("from BundleType b where b.name = :name").setParameter(
- "name", "Test Bundle").getResultList();
+ List<?> bundleTypes = getEntityManager().createQuery("from BundleType b where b.name = :name")
+ .setParameter("name", "Test Bundle").getResultList();
assertEquals("The bundle type should have been deleted", 0, bundleTypes.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deletePackages() {
- List<?> packages = getEntityManager().createQuery("from Package p where p.name = :name").setParameter("name",
- "ServerC::test-package").getResultList();
+ List<?> packages = getEntityManager().createQuery("from Package p where p.name = :name")
+ .setParameter("name", "ServerC::test-package").getResultList();
assertEquals("All packages should have been deleted", 0, packages.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deletePackageTypes() {
- List<?> packageTypes = getEntityManager().createQuery("from PackageType p where p.name = :name").setParameter(
- "name", "ServerC.Content").getResultList();
+ List<?> packageTypes = getEntityManager().createQuery("from PackageType p where p.name = :name")
+ .setParameter("name", "ServerC.Content").getResultList();
assertEquals("All package types should have been deleted", 0, packageTypes.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteResourceGroups() {
- List<?> groups = getEntityManager().createQuery(
- "from ResourceGroup g where g.name = :name and g.resourceType.name = :typeName").setParameter("name",
- "ServerC Group").setParameter("typeName", "ServerC").getResultList();
+ List<?> groups = getEntityManager()
+ .createQuery("from ResourceGroup g where g.name = :name and g.resourceType.name = :typeName")
+ .setParameter("name", "ServerC Group").setParameter("typeName", "ServerC").getResultList();
assertEquals("All resource groups should have been deleted", 0, groups.size());
}
@Test(dependsOnMethods = { "upgradePluginWithTypesRemoved" }, groups = { "plugin.metadata", "RemoveTypes" })
public void deleteAlertTemplates() {
- List<?> templates = getEntityManager().createQuery(
- "from AlertDefinition a where a.name = :name and a.resourceType.name = :typeName").setParameter("name",
- "ServerC Alert Template").setParameter("typeName", "ServerC").getResultList();
+ List<?> templates = getEntityManager()
+ .createQuery("from AlertDefinition a where a.name = :name and a.resourceType.name = :typeName")
+ .setParameter("name", "ServerC Alert Template").setParameter("typeName", "ServerC").getResultList();
assertEquals("Alert templates should have been deleted.", 0, templates.size());
}
@@ -576,9 +577,9 @@ public class ResourceMetadataManagerBeanTest extends MetadataBeanTest {
List<Resource> resources = new ArrayList<Resource>();
for (int i = 0; i < count; ++i) {
- resources.add(new ResourceBuilder().createServer().withResourceType(resourceType).withName(
- resourceType.getName() + "--" + i).withUuid(resourceType.getName()).withRandomResourceKey(
- resourceType.getName() + "--" + i).build());
+ resources.add(new ResourceBuilder().createServer().withResourceType(resourceType)
+ .withName(resourceType.getName() + "--" + i).withUuid(resourceType.getName())
+ .withRandomResourceKey(resourceType.getName() + "--" + i).build());
}
getTransactionManager().begin();
diff --git a/pom.xml b/pom.xml
index 7e390f8..3b77493 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,7 @@
<twitter4j.version>2.2.4</twitter4j.version>
<commons-codec.version>1.4</commons-codec.version>
<!-- NOTE (ips, 10/04/11): Upgrading testng to 6.2.x causes 10 server-jar tests to fail for an unknown reason. -->
+ <!-- NOTE (jshaughn, 01/20/12): With the latest work, the sserver-jar tests passed using testng to 6.3.1, so perhaps an upgrade is possible -->
<testng.version>6.1.1</testng.version>
<cobertura.version>1.9.4.1</cobertura.version>
<augeas.version>0.9.0</augeas.version>
commit b295126d93d63138c31a4e9df4429d56bc6aa902
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Jan 19 14:58:43 2012 -0500
Re-enable and update this test class. Seems to work now.
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
index 1ff724a..89ff87b 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
@@ -54,6 +54,7 @@ import org.rhq.core.domain.drift.DriftChangeSet;
import org.rhq.core.domain.drift.DriftConfigurationDefinition.BaseDirValueContext;
import org.rhq.core.domain.drift.DriftDefinition;
import org.rhq.core.domain.drift.DriftDefinition.BaseDirectory;
+import org.rhq.core.domain.drift.DriftDefinitionTemplate;
import org.rhq.core.domain.drift.DriftFile;
import org.rhq.core.domain.drift.DriftFileStatus;
import org.rhq.core.domain.resource.Agent;
@@ -76,14 +77,6 @@ import org.rhq.enterprise.server.util.LookupUtil;
* !!! configured drift server plugin. To enhance this to do that then you may need to model this
* !!! mode like BundleManagerBeanTest
*/
-// Tests in this class **must** be run after the drift-template group. More specifically,
-// tests in this class need to be run after DriftTemplateManagerBeanTest. If test methods
-// in this class run first, for reasons I have yet to understand, DriftTemplateManagerBeanTest.initDB
-// will fail with a ClassNotFoundException for an anonymous inner class that is created in
-// the initDB method.
-//
-// - jsanda
-@Test(dependsOnGroups = "drift")
public class DriftManagerBeanTest extends AbstractEJB3Test {
private static final boolean ENABLE_TESTS = true;
@@ -345,7 +338,13 @@ public class DriftManagerBeanTest extends AbstractEJB3Test {
try {
ResourceType resourceType = new ResourceType("plat" + System.currentTimeMillis(), "test",
ResourceCategory.PLATFORM, null);
-
+ DriftDefinitionTemplate template = new DriftDefinitionTemplate();
+ template.setName("test-template");
+ DriftDefinition templateDef = new DriftDefinition(new Configuration());
+ templateDef.setName("test-template-def");
+ template.setTemplateDefinition(templateDef);
+ template.setUserDefined(true);
+ resourceType.addDriftDefinitionTemplate(template);
em.persist(resourceType);
Agent agent = new Agent("testagent", "testaddress", 1, "", "testtoken");
commit 24d89dc93ac47178812ce63c213d176fa265e915
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Jan 19 13:06:11 2012 -0500
It seems we didn't really understand how testng was executing tests
when we submitted many test classes in a run. For example, when we
submit the server jar tests we assumed that the test classes would
be run sequentially, in perhaps some random order, and that each would
have its Before/AfterClass methods executed atthe start and end of each
test class execution.
That is not true.
Although testng seems to run most tests from a test class together, it does
not seem to make that guarantee. From latest traces it seems that the
test classes are, toa degree, pooled and:
1) you can not assume that all test methods for a test class will execute
before execution of test methods from another test class.
2) you can not assume that multiple BeforeClass methods will not execute
prior to an AfterClass. For example, this can happen:
Class1:BeforeClass
Class2:BeforeClass
Class1:AfterClass
Class2:AfterClass
Put another way: You can only assume that BeforeClass and AfterClass
execute in order, for a single test class. You can not predict the
execution order of all Before|AfterClass methods for all test classes.
3) The same rules as described in 2 apply to Before|AfterGroups
What this means is that you must be very careful with what is done in
Before|AfterClass and BeforeAfter|Groups. The work must not conflict
with work done in other test classes that will execute in the same test
suite.
This is very important when multiple test classes are sharing some sort
of test resource.
In general, it is much safer, although perhaps a bit slower, to use
@BeforeMethod() and @AfterMethod(alwaysRun=true).
This misunderstanding was particularly bad for us in the server jar tests,
where many test classes extend AbstractEJB3Test and utilize the jboss
mbean server under the covers, in the prepareXXX methods. This caused
clashes described above.
So, for server jar testing this reworks things to better share the mbean
server, even among tests in the same class. And migrates all
AbstractEJB3Test.prepare/unprepare calls from Before|AfterClass|Groups to
Before|After|Method.
also - remove/suppress IDE warnings from touched test classes
diff --git a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/server/drift/DriftServerTest.java b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/server/drift/DriftServerTest.java
index adab2c8..5fa92b9 100644
--- a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/server/drift/DriftServerTest.java
+++ b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/server/drift/DriftServerTest.java
@@ -109,7 +109,8 @@ public class DriftServerTest extends AbstractEJB3Test {
private void shutDownDriftServer() throws Exception {
unprepareServerPluginService();
- driftServerPluginService.stopMasterPluginContainer();
+ //already done by the above call
+ //driftServerPluginService.stopMasterPluginContainer();
}
private void shutDownAgentServices() {
@@ -178,9 +179,9 @@ public class DriftServerTest extends AbstractEJB3Test {
protected void deleteEntity(Class<?> clazz, String name, EntityManager em) {
try {
- Object entity = em.createQuery(
- "select entity from " + clazz.getSimpleName() + " entity where entity.name = :name").setParameter(
- "name", name).getSingleResult();
+ Object entity = em
+ .createQuery("select entity from " + clazz.getSimpleName() + " entity where entity.name = :name")
+ .setParameter("name", name).getSingleResult();
em.remove(entity);
} catch (NoResultException e) {
// we can ignore no results because this code will run when the db
@@ -203,8 +204,8 @@ public class DriftServerTest extends AbstractEJB3Test {
}
protected void initResource() {
- resource = new ResourceBuilder().createResource().withId(0).withName(RESOURCE_NAME).withResourceKey(
- RESOURCE_NAME).withRandomUuid().withResourceType(resourceType).build();
+ resource = new ResourceBuilder().createResource().withId(0).withName(RESOURCE_NAME)
+ .withResourceKey(RESOURCE_NAME).withRandomUuid().withResourceType(resourceType).build();
}
protected Subject getOverlord() {
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
index 40a0168..587bdfb 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/BundleManagerBeanTest.java
@@ -37,9 +37,7 @@ import javax.persistence.Query;
import javax.transaction.TransactionManager;
import org.hibernate.LazyInitializationException;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -94,7 +92,7 @@ import org.rhq.enterprise.server.util.LookupUtil;
* @author John Mazzitelli
* @author Jay Shaughnessy
*/
-@SuppressWarnings( { "unused" })
+@SuppressWarnings({ "unused" })
@Test
public class BundleManagerBeanTest extends AbstractEJB3Test {
@@ -115,19 +113,11 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
private Subject overlord;
TestServerCommunicationsService agentServiceContainer;
- @BeforeClass
- public void beforeClass() {
+ @BeforeMethod
+ public void beforeMethod() throws Exception {
agentServiceContainer = prepareForTestAgents();
agentServiceContainer.bundleService = new TestAgentClient(null, agentServiceContainer);
- }
- @AfterClass
- public void afterClass() throws Exception {
- unprepareForTestAgents();
- }
-
- @BeforeMethod
- public void beforeMethod() throws Exception {
this.ps = new TestBundleServerPluginService();
prepareCustomServerPluginService(this.ps);
bundleManager = LookupUtil.getBundleManager();
@@ -141,9 +131,14 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
@AfterMethod(alwaysRun = true)
public void afterMethod() throws Exception {
- cleanupDatabase();
- unprepareServerPluginService();
- this.ps = null;
+ unprepareForTestAgents();
+
+ try {
+ this.ps = null;
+ cleanupDatabase();
+ } finally {
+ unprepareServerPluginService();
+ }
}
private void cleanupDatabase() {
@@ -189,8 +184,7 @@ public class BundleManagerBeanTest extends AbstractEJB3Test {
+ TEST_PREFIX + "%'");
doomed = q.getResultList();
for (Object removeMe : doomed) {
- em.remove(em
- .getReference(BundleResourceDeployment.class, ((BundleResourceDeployment) removeMe).getId()));
+ em.remove(em.getReference(BundleResourceDeployment.class, ((BundleResourceDeployment) removeMe).getId()));
}
// remove any orphaned bds
q = em.createQuery("SELECT bd FROM BundleDeployment bd WHERE bd.description LIKE '" + TEST_PREFIX + "%'");
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/cloud/FailoverListManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/cloud/FailoverListManagerBeanTest.java
index 6b95388..29e9e58 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/cloud/FailoverListManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/cloud/FailoverListManagerBeanTest.java
@@ -27,7 +27,6 @@ import java.util.Set;
import javax.persistence.EntityManager;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
@@ -86,13 +85,6 @@ public class FailoverListManagerBeanTest extends AbstractEJB3Test {
servers = new ArrayList<Server>();
agents = new ArrayList<Agent>();
newAgents = new ArrayList<Agent>();
-
- prepareForTestAgents();
- }
-
- @AfterClass
- public void afterClass() throws Exception {
- this.unprepareForTestAgents();
}
@BeforeMethod
@@ -100,9 +92,11 @@ public class FailoverListManagerBeanTest extends AbstractEJB3Test {
servers.clear();
agents.clear();
newAgents.clear();
+
+ prepareForTestAgents();
}
- @AfterMethod
+ @AfterMethod(alwaysRun = true)
public void afterMethod() throws Exception {
try {
getTransactionManager().begin();
@@ -151,6 +145,8 @@ public class FailoverListManagerBeanTest extends AbstractEJB3Test {
}
throw e;
+ } finally {
+ this.unprepareForTestAgents();
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
index 1dfd79a..3645d77 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBeanTest.java
@@ -26,8 +26,6 @@ import java.util.Map;
import javax.persistence.EntityManager;
-import org.rhq.core.domain.criteria.ResourceConfigurationUpdateCriteria;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
@@ -48,6 +46,7 @@ import org.rhq.core.domain.configuration.PluginConfigurationUpdate;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.ResourceConfigurationUpdate;
import org.rhq.core.domain.configuration.group.GroupPluginConfigurationUpdate;
+import org.rhq.core.domain.criteria.ResourceConfigurationUpdateCriteria;
import org.rhq.core.domain.discovery.AvailabilityReport;
import org.rhq.core.domain.discovery.MergeResourceResponse;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
@@ -70,6 +69,7 @@ import org.rhq.enterprise.server.util.SessionTestHelper;
* Tests the configuration manager.
*/
@Test
+@SuppressWarnings("all")
public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
private static final boolean ENABLE_TESTS = true;
@@ -97,32 +97,27 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
configurationManager = LookupUtil.getConfigurationManager();
resourceManager = LookupUtil.getResourceManager();
overlord = LookupUtil.getSubjectManager().getOverlord();
-
- TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
- TestServices testServices = new TestServices();
- agentServiceContainer.configurationService = testServices;
- agentServiceContainer.discoveryService = testServices;
- }
-
- @AfterClass
- public void afterClass() throws Exception {
- unprepareForTestAgents();
}
@BeforeMethod
public void beforeMethod() throws Exception {
prepareScheduler();
+ TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
+ TestServices testServices = new TestServices();
+ agentServiceContainer.configurationService = testServices;
+ agentServiceContainer.discoveryService = testServices;
+
getTransactionManager().begin();
EntityManager em = getEntityManager();
try {
compatibleGroup = SessionTestHelper.createNewCompatibleGroupForRole(em, null, // no role necessary here
"compat");
- newResource1 = SessionTestHelper.createNewResourceForGroup(em, compatibleGroup, "res"
- + System.currentTimeMillis());
- newResource2 = SessionTestHelper.createNewResourceForGroup(em, compatibleGroup, "res"
- + System.currentTimeMillis());
+ newResource1 = SessionTestHelper.createNewResourceForGroup(em, compatibleGroup,
+ "res" + System.currentTimeMillis());
+ newResource2 = SessionTestHelper.createNewResourceForGroup(em, compatibleGroup,
+ "res" + System.currentTimeMillis());
// set one resource as the child of another, so that they don't both look like platforms under the agent
newResource1.addChildResource(newResource2);
@@ -145,7 +140,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
}
}
- @AfterMethod
+ @AfterMethod(alwaysRun = true)
public void afterMethod() throws Exception {
try {
// perform in-band and out-of-band work in quick succession
@@ -202,6 +197,7 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
} finally {
unprepareScheduler();
+ unprepareForTestAgents();
}
}
@@ -425,18 +421,18 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
configuration2.put(new PropertySimple("fail", "false"));
/* begin simple checks */
- PluginConfigurationUpdate update1 = configurationManager.updatePluginConfiguration(overlord, resource1
- .getId(), configuration1);
+ PluginConfigurationUpdate update1 = configurationManager.updatePluginConfiguration(overlord,
+ resource1.getId(), configuration1);
assert update1.getErrorMessage() == null : "We weren't expecting a failure here";
- PluginConfigurationUpdate update2 = configurationManager.updatePluginConfiguration(overlord, resource2
- .getId(), configuration2);
+ PluginConfigurationUpdate update2 = configurationManager.updatePluginConfiguration(overlord,
+ resource2.getId(), configuration2);
assert update2.getErrorMessage() == null : "We weren't expecting a failure here";
- Configuration updatedConfiguration1 = configurationManager.getPluginConfiguration(overlord, resource1
- .getId());
- Configuration updatedConfiguration2 = configurationManager.getPluginConfiguration(overlord, resource2
- .getId());
+ Configuration updatedConfiguration1 = configurationManager.getPluginConfiguration(overlord,
+ resource1.getId());
+ Configuration updatedConfiguration2 = configurationManager.getPluginConfiguration(overlord,
+ resource2.getId());
assert updatedConfiguration1.equals(configuration1) : "configuration1 was: " + updatedConfiguration1 + ", "
+ "expected was: " + configuration1;
@@ -487,8 +483,8 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
Map<Integer, Configuration> memberConfigs = new HashMap<Integer, Configuration>();
memberConfigs.put(resource1.getId(), configuration1);
memberConfigs.put(resource2.getId(), configuration2);
- int groupUpdateId = configurationManager.scheduleGroupPluginConfigurationUpdate(overlord, compatibleGroup
- .getId(), memberConfigs);
+ int groupUpdateId = configurationManager.scheduleGroupPluginConfigurationUpdate(overlord,
+ compatibleGroup.getId(), memberConfigs);
// instead of sleeping, let's directly execute what would normally be scheduled
//configurationManager.completeGroupPluginConfigurationUpdate(groupUpdateId);
@@ -713,8 +709,8 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
criteria.addFilterResourceIds(resource.getId());
criteria.fetchConfiguration(true);
criteria.addSortCreatedTime(PageOrdering.ASC);
- List<ResourceConfigurationUpdate> history =
- configurationManager.findResourceConfigurationUpdatesByCriteria(overlord, criteria);
+ List<ResourceConfigurationUpdate> history = configurationManager.findResourceConfigurationUpdatesByCriteria(
+ overlord, criteria);
assert history != null;
assert history.size() == 3;
@@ -1011,8 +1007,8 @@ public class ConfigurationManagerBeanTest extends AbstractEJB3Test {
} else {
mybool.setErrorMessage(ThrowableUtil.getStackAsString(new IllegalArgumentException(
"Not a valid boolean")));
- response = new ConfigurationUpdateResponse(request.getConfigurationUpdateId(), request
- .getConfiguration(), new NullPointerException("This simulates a failed update"));
+ response = new ConfigurationUpdateResponse(request.getConfigurationUpdateId(),
+ request.getConfiguration(), new NullPointerException("This simulates a failed update"));
}
LookupUtil.getConfigurationManager().completeResourceConfigurationUpdate(response);
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/content/test/ContentManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/content/test/ContentManagerBeanTest.java
index 6f75197..ea48c65 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/content/test/ContentManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/content/test/ContentManagerBeanTest.java
@@ -28,7 +28,6 @@ import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.Query;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
@@ -146,23 +145,15 @@ public class ContentManagerBeanTest extends AbstractEJB3Test {
contentManager = LookupUtil.getContentManager();
subjectManager = LookupUtil.getSubjectManager();
- TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
- agentServiceContainer.contentService = contentAgentService;
-
populateResponseSteps();
}
- @AfterClass
- public void teardownAfterClass() throws Exception {
- unprepareForTestAgents();
- }
-
@BeforeMethod
public void setupBeforeMethod() throws Exception {
setupTestEnvironment();
}
- @AfterMethod
+ @AfterMethod(alwaysRun = true)
public void tearDownAfterMethod() throws Exception {
tearDownTestEnvironment();
}
@@ -316,8 +307,8 @@ public class ContentManagerBeanTest extends AbstractEJB3Test {
report.addDeployedPackage(package3);
// Package where entire package does not exist
- PackageDetailsKey key4 = new PackageDetailsKey("PackageX", "1.0.0", packageType4.getName(), architecture1
- .getName());
+ PackageDetailsKey key4 = new PackageDetailsKey("PackageX", "1.0.0", packageType4.getName(),
+ architecture1.getName());
ResourcePackageDetails package4 = new ResourcePackageDetails(key4);
// Fully populate this version to make sure the translation from details -> domain model works
@@ -1385,6 +1376,9 @@ public class ContentManagerBeanTest extends AbstractEJB3Test {
// Private --------------------------------------------
private void setupTestEnvironment() throws Exception {
+ TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
+ agentServiceContainer.contentService = contentAgentService;
+
getTransactionManager().begin();
EntityManager em = getEntityManager();
@@ -1567,6 +1561,7 @@ public class ContentManagerBeanTest extends AbstractEJB3Test {
}
} finally {
em.close();
+ unprepareForTestAgents();
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
index 5a702ff..8c356f1 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
@@ -29,8 +29,9 @@ import java.util.Properties;
import javax.management.MBeanServer;
import javax.persistence.Query;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.core.clientapi.server.core.AgentRegistrationException;
@@ -92,7 +93,7 @@ import org.rhq.enterprise.server.util.LookupUtil;
// J. testAttemptToChangeAgentName
// 1) register agent "newName" but with Z's host/port/token. In effect, this is trying to change the agent's name. (REJECT - you are not allowed to rename agents)
-@Test
+@Test(groups = { "core.agent-registration" })
public class CoreServerServiceImplTest extends AbstractEJB3Test {
private static final String TEST_AGENT_NAME_PREFIX = "CoreServerServiceImplTest.Agent";
private static final String RHQ_SERVER_NAME_PROPERTY = "rhq.server.high-availability.name";
@@ -109,6 +110,80 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
private static final int B_PORT = 22222;
private static final String B_HOST = "hostB";
+ @AfterGroups(groups = { "core.agent-registration" })
+ public void afterGroup() throws Exception {
+ // clean up any agents we might have created
+ Query q = getEntityManager().createQuery(
+ "select a from Agent a where name like '" + TEST_AGENT_NAME_PREFIX + "%'");
+ List<Agent> doomed = (List<Agent>) q.getResultList();
+ for (Agent deleteMe : doomed) {
+ LookupUtil.getAgentManager().deleteAgent(deleteMe);
+ }
+ }
+
+ @BeforeMethod
+ public void prepare() throws Exception {
+ // mock the name of our server via the sysprop (in production, this is normally set in rhq-server.properties)
+ oldServerNamePropertyValue = System.getProperty(RHQ_SERVER_NAME_PROPERTY);
+ String newServerNamePropertyValue = "CoreServerServiceImplTest.Server";
+ System.setProperty(RHQ_SERVER_NAME_PROPERTY, newServerNamePropertyValue);
+
+ // mock up our core server MBean that provides information about where the jboss home dir is
+ MBeanServer mbs = getJBossMBeanServer();
+ DummyCoreServer mbean = new DummyCoreServer();
+ mbs.registerMBean(mbean, CoreServerMBean.OBJECT_NAME);
+
+ // in order to register, we need to mock out the agent version file used by the server
+ // to determine the agent version it supports.
+ agentVersion = new AgentVersion("1.2.3", "12345");
+ File agentVersionFile = new File(mbean.getJBossServerHomeDir(),
+ "deploy/rhq.ear/rhq-downloads/rhq-agent/rhq-server-agent-versions.properties");
+ agentVersionFile.getParentFile().mkdirs();
+ agentVersionFile.delete();
+ Properties agentVersionProps = new Properties();
+ agentVersionProps.put("rhq-agent.latest.version", agentVersion.getVersion());
+ agentVersionProps.put("rhq-agent.latest.build-number", agentVersion.getBuild());
+ FileOutputStream fos = new FileOutputStream(agentVersionFile);
+ try {
+ agentVersionProps.store(fos, "This file was created by " + CoreServerServiceImplTest.class.getName());
+ } finally {
+ fos.close();
+ }
+
+ // this mocks out the endpoint ping - the server will think the agent that is registering is up and pingable
+ prepareForTestAgents();
+
+ // mock our server
+ server = new Server();
+ server.setName(newServerNamePropertyValue);
+ server.setAddress("CoreServerServiceImplTest.localhost");
+ server.setPort(12345);
+ server.setSecurePort(12346);
+ server.setOperationMode(OperationMode.NORMAL);
+ int serverId = LookupUtil.getServerManager().create(server);
+ server.setId(serverId);
+ }
+
+ @AfterMethod
+ public void unprepare() throws Exception {
+
+ // cleanup our test server
+ LookupUtil.getCloudManager().updateServerMode(new Integer[] { server.getId() }, OperationMode.DOWN);
+ LookupUtil.getCloudManager().deleteServer(server.getId());
+
+ // shutdown our mock mbean server
+ MBeanServer mbs = getJBossMBeanServer();
+ mbs.unregisterMBean(CoreServerMBean.OBJECT_NAME);
+
+ unprepareForTestAgents();
+
+ // in case this was set before our tests, put it back the way it was
+ if (oldServerNamePropertyValue != null) {
+ System.setProperty(RHQ_SERVER_NAME_PROPERTY, oldServerNamePropertyValue);
+ }
+ }
+
+ @Test
public void testNewAgentRegistrationWithOldToken() throws Exception {
// this tests the case where someone purged an agent from the DB, but then
// changed their mind and want to re-run that agent and re-register it again.
@@ -125,6 +200,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
LookupUtil.getAgentManager().deleteAgent(agent);
}
+ @Test
public void testChangeAddressPort() throws Exception {
CoreServerServiceImpl service = new CoreServerServiceImpl();
AgentRegistrationRequest request;
@@ -379,75 +455,6 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
}
}
- @BeforeClass
- public void prepare() throws Exception {
- // mock the name of our server via the sysprop (in production, this is normally set in rhq-server.properties)
- oldServerNamePropertyValue = System.getProperty(RHQ_SERVER_NAME_PROPERTY);
- String newServerNamePropertyValue = "CoreServerServiceImplTest.Server";
- System.setProperty(RHQ_SERVER_NAME_PROPERTY, newServerNamePropertyValue);
-
- // mock up our core server MBean that provides information about where the jboss home dir is
- MBeanServer mbs = getJBossMBeanServer();
- DummyCoreServer mbean = new DummyCoreServer();
- mbs.registerMBean(mbean, CoreServerMBean.OBJECT_NAME);
-
- // in order to register, we need to mock out the agent version file used by the server
- // to determine the agent version it supports.
- agentVersion = new AgentVersion("1.2.3", "12345");
- File agentVersionFile = new File(mbean.getJBossServerHomeDir(),
- "deploy/rhq.ear/rhq-downloads/rhq-agent/rhq-server-agent-versions.properties");
- agentVersionFile.getParentFile().mkdirs();
- agentVersionFile.delete();
- Properties agentVersionProps = new Properties();
- agentVersionProps.put("rhq-agent.latest.version", agentVersion.getVersion());
- agentVersionProps.put("rhq-agent.latest.build-number", agentVersion.getBuild());
- FileOutputStream fos = new FileOutputStream(agentVersionFile);
- try {
- agentVersionProps.store(fos, "This file was created by " + CoreServerServiceImplTest.class.getName());
- } finally {
- fos.close();
- }
-
- // this mocks out the endpoint ping - the server will think the agent that is registering is up and pingable
- prepareForTestAgents();
-
- // mock our server
- server = new Server();
- server.setName(newServerNamePropertyValue);
- server.setAddress("CoreServerServiceImplTest.localhost");
- server.setPort(12345);
- server.setSecurePort(12346);
- server.setOperationMode(OperationMode.NORMAL);
- int serverId = LookupUtil.getServerManager().create(server);
- server.setId(serverId);
- }
-
- @AfterClass
- public void unprepare() throws Exception {
- // clean up any agents we might have created
- Query q = getEntityManager().createQuery(
- "select a from Agent a where name like '" + TEST_AGENT_NAME_PREFIX + "%'");
- List<Agent> doomed = (List<Agent>) q.getResultList();
- for (Agent deleteMe : doomed) {
- LookupUtil.getAgentManager().deleteAgent(deleteMe);
- }
-
- // cleanup our test server
- LookupUtil.getCloudManager().updateServerMode(new Integer[] { server.getId() }, OperationMode.DOWN);
- LookupUtil.getCloudManager().deleteServer(server.getId());
-
- // shutdown our mock mbean server
- MBeanServer mbs = getJBossMBeanServer();
- mbs.unregisterMBean(CoreServerMBean.OBJECT_NAME);
-
- unprepareForTestAgents();
-
- // in case this was set before our tests, put it back the way it was
- if (oldServerNamePropertyValue != null) {
- System.setProperty(RHQ_SERVER_NAME_PROPERTY, oldServerNamePropertyValue);
- }
- }
-
interface DummyCoreServerMBean extends CoreServerMBean {
};
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
index 082bd6b..630b778 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/discovery/DiscoveryBossBeanTest.java
@@ -39,7 +39,7 @@ import org.dbunit.ext.oracle.Oracle10DataTypeFactory;
import org.dbunit.ext.oracle.OracleDataTypeFactory;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -74,20 +74,15 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
@BeforeClass
public void beforeClass() throws Exception {
discoveryBoss = LookupUtil.getDiscoveryBoss();
+ }
+ @BeforeMethod
+ public void setupTestData() throws Exception {
dummyJBossMBeanServer = MBeanServerFactory.createMBeanServer("jboss");
MBeanServerLocator.setJBoss(dummyJBossMBeanServer);
dummyJBossMBeanServer.registerMBean(new ServerCommunicationsService(),
- ServerCommunicationsServiceMBean.OBJECT_NAME);
- }
-
- @AfterClass
- public void afterClass() {
- MBeanServerFactory.releaseMBeanServer(dummyJBossMBeanServer);
- }
+ ServerCommunicationsServiceMBean.OBJECT_NAME);
- @BeforeMethod
- public void setupTestData() throws Exception {
initDB();
platformType = getEntityManager().find(ResourceType.class, 1);
serverType = getEntityManager().find(ResourceType.class, 2);
@@ -96,6 +91,11 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
agent = getEntityManager().find(Agent.class, 1);
}
+ @AfterMethod(alwaysRun = true)
+ public void afterMethod() throws Exception {
+ MBeanServerFactory.releaseMBeanServer(dummyJBossMBeanServer);
+ }
+
@Test(groups = "integration.ejb3")
public void testBasicInventoryReport() throws Exception {
InventoryReport inventoryReport = new InventoryReport(agent);
@@ -211,7 +211,7 @@ public class DiscoveryBossBeanTest extends AbstractEJB3Test {
IDataSet getDataSet() throws Exception {
FlatXmlProducer xmlProducer = new FlatXmlProducer(new InputSource(getClass().getResourceAsStream(
- getDataSetFile())));
+ getDataSetFile())));
xmlProducer.setColumnSensing(true);
return new FlatXmlDataSet(xmlProducer);
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
index f7152a9..1ff724a 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/drift/DriftManagerBeanTest.java
@@ -46,7 +46,6 @@ import org.rhq.core.clientapi.server.drift.DriftServerService;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.criteria.GenericDriftChangeSetCriteria;
import org.rhq.core.domain.criteria.JPADriftChangeSetCriteria;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.drift.Drift;
@@ -109,19 +108,18 @@ public class DriftManagerBeanTest extends AbstractEJB3Test {
overlord = LookupUtil.getSubjectManager().getOverlord();
driftServerService = new DriftServerServiceImpl();
-
- TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
- agentServiceContainer.driftService = new TestDefService();
}
- @AfterClass
+ @AfterClass(alwaysRun = true)
public void afterClass() {
driftServerService = null;
- unprepareForTestAgents();
}
@BeforeMethod
public void beforeMethod() throws Exception {
+ TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
+ agentServiceContainer.driftService = new TestDefService();
+
prepareScheduler();
deleteDriftFiles();
@@ -134,6 +132,7 @@ public class DriftManagerBeanTest extends AbstractEJB3Test {
try {
deleteNewResource(newResource);
} finally {
+ unprepareForTestAgents();
unprepareScheduler();
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/operation/OperationManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/operation/OperationManagerBeanTest.java
index f068ead..bce9bad 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/operation/OperationManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/operation/OperationManagerBeanTest.java
@@ -35,8 +35,8 @@ import org.testng.annotations.Test;
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.operation.CancelResults;
-import org.rhq.core.clientapi.agent.operation.OperationAgentService;
import org.rhq.core.clientapi.agent.operation.CancelResults.InterruptedState;
+import org.rhq.core.clientapi.agent.operation.OperationAgentService;
import org.rhq.core.clientapi.server.operation.OperationServerService;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.Configuration;
@@ -108,19 +108,18 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
overlord = LookupUtil.getSubjectManager().getOverlord();
operationServerService = new OperationServerServiceImpl();
-
- TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
- agentServiceContainer.operationService = new TestConfigService();
}
- @AfterClass
+ @AfterClass(alwaysRun = true)
public void afterClass() {
operationServerService = null;
- unprepareForTestAgents();
}
@BeforeMethod
public void beforeMethod() throws Exception {
+ TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
+ agentServiceContainer.operationService = new TestConfigService();
+
prepareScheduler();
simulatedOperation_Sleep = 500L;
@@ -137,6 +136,7 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
try {
deleteNewResource(newResource);
} finally {
+ unprepareForTestAgents();
unprepareScheduler();
}
}
@@ -226,8 +226,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
.getGroup().getId());
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 0;
// should be no resource histories that belong to it
@@ -290,8 +290,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert list.size() == 0;
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 0;
// should be no resource histories that belong to it
@@ -336,14 +336,14 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(9000L); // wait for it to be triggered and finish
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 1 : "Expected 1 result, but got " + results.size();
operationManager.deleteOperationHistory(overlord, results.get(0).getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 0;
// purging group history purges all resource histories that belong to it
@@ -375,8 +375,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// wait for it to be triggered so we get a history item
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
- results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
if ((results != null) && (results.size() > 0)) {
break; // operation was triggered - got the history item
}
@@ -406,8 +406,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// cancel the group history - which cancels all the resource histories
operationManager.cancelOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1;
assert results.get(0).getStatus() == OperationRequestStatus.CANCELED : results.get(0);
@@ -426,8 +426,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// purge the group history
operationManager.deleteOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -460,8 +460,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// wait for it to be triggered so we get a history item
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
- results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
if ((results != null) && (results.size() > 0)) {
break; // operation was triggered - got the history item
}
@@ -474,8 +474,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// get the one resource history from the group
PageList<ResourceOperationHistory> results2;
- results2 = operationManager.findPendingResourceOperationHistories(overlord, newResource.getId(), PageControl
- .getUnlimitedInstance());
+ results2 = operationManager.findPendingResourceOperationHistories(overlord, newResource.getId(),
+ PageControl.getUnlimitedInstance());
assert results2.size() == 1 : "Should have had 1 resource history result: " + results2;
ResourceOperationHistory rHistory = results2.get(0);
@@ -485,28 +485,28 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// this doesn't actually cancel the FINISHED resource operation. This simulates the fact that
// the agent couldn't cancel the resource op since it already finished.
operationManager.cancelOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 1;
assert results.get(0).getStatus() == OperationRequestStatus.CANCELED : results.get(0);
- results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results.size() == 0;
// still pending - our operation wasn't really canceled - waiting for the agent to tell us its finished
results2 = operationManager.findCompletedResourceOperationHistories(overlord, newResource.getId(), null, null,
PageControl.getUnlimitedInstance());
assert results2.size() == 0;
- results2 = operationManager.findPendingResourceOperationHistories(overlord, newResource.getId(), PageControl
- .getUnlimitedInstance());
+ results2 = operationManager.findPendingResourceOperationHistories(overlord, newResource.getId(),
+ PageControl.getUnlimitedInstance());
assert results2.size() == 1;
assert results2.get(0).getStatus() == OperationRequestStatus.INPROGRESS : results2.get(0);
// purge the group history (note we tell it to even purge those in progress)
operationManager.deleteOperationHistory(overlord, history.getId(), true);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -536,8 +536,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(4000L); // wait for it to finish, should be fast
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1;
GroupOperationHistory history = results.get(0);
@@ -573,8 +573,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert rHistory.getSubjectName().equals(overlord.getName()) : rHistory;
operationManager.deleteOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -607,8 +607,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(8000L); // wait for it to finish, should be fast
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
// the group job executed twice
assert results != null;
@@ -663,8 +663,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
operationManager.deleteOperationHistory(overlord, history0.getId(), false);
operationManager.deleteOperationHistory(overlord, history1.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0 : results; // none left, we purged the two group histories
@@ -710,8 +710,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(4000L); // wait for it to finish, should be fast
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1;
GroupOperationHistory history = results.get(0);
@@ -742,8 +742,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert rHistory.getSubjectName().equals(overlord.getName()) : rHistory;
// parameters and results are lazily loaded in the paginated queries, but are eagerly individually
- rHistory = (ResourceOperationHistory) operationManager.getOperationHistoryByHistoryId(overlord, rHistory
- .getId());
+ rHistory = (ResourceOperationHistory) operationManager.getOperationHistoryByHistoryId(overlord,
+ rHistory.getId());
assert rHistory.getResults() != null;
assert rHistory.getResults().getSimple("param1echo") != null;
assert rHistory.getResults().getSimple("param1echo").getStringValue().equals("group-test");
@@ -751,8 +751,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert rHistory.getParameters().getId() != history.getParameters().getId() : "params should be copies - not shared";
operationManager.deleteOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -781,8 +781,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(4000L); // wait for it to finish, should be fast
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1 : "Did not get 1 result back, but " + results.size();
GroupOperationHistory history = results.get(0);
@@ -810,8 +810,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert rHistory.getSubjectName().equals(overlord.getName()) : rHistory;
operationManager.deleteOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -840,8 +840,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
Thread.sleep(4000L); // wait for it to finish, should be fast
PageList<GroupOperationHistory> results;
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1;
GroupOperationHistory history = results.get(0);
@@ -869,8 +869,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert rHistory.getSubjectName().equals(overlord.getName()) : rHistory;
operationManager.deleteOperationHistory(overlord, history.getId(), false);
- results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findCompletedGroupOperationHistories(overlord, newGroup.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 0; // none left, we purged the only group history there was
@@ -1174,8 +1174,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// wait for it to be triggered so we get a history item
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
- results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(),
+ PageControl.getUnlimitedInstance());
if ((results != null) && (results.size() > 0)) {
break; // operation was triggered - got the history item
}
@@ -1233,8 +1233,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
// wait for it to be triggered so we get a history item
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
- results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(),
+ PageControl.getUnlimitedInstance());
if ((results != null) && (results.size() > 0)) {
break; // operation was triggered - got the history item
}
@@ -1254,8 +1254,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert results.size() == 0;
// still pending - our operation wasn't really canceled - waiting for the agent to tell us its finished
- results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(), PageControl
- .getUnlimitedInstance());
+ results = operationManager.findPendingResourceOperationHistories(overlord, resource.getId(),
+ PageControl.getUnlimitedInstance());
assert results != null;
assert results.size() == 1;
history = results.get(0);
@@ -1308,8 +1308,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert history.getSubjectName().equals(overlord.getName()) : history;
PageList<ResourceOperationLastCompletedComposite> list;
- list = operationManager.findRecentlyCompletedResourceOperations(overlord, null, PageControl
- .getUnlimitedInstance());
+ list = operationManager.findRecentlyCompletedResourceOperations(overlord, null,
+ PageControl.getUnlimitedInstance());
assert list.size() == 1;
assert list.get(0).getOperationHistoryId() == history.getId();
assert list.get(0).getResourceId() == resource.getId();
@@ -1322,8 +1322,8 @@ public class OperationManagerBeanTest extends AbstractEJB3Test {
assert results != null;
assert results.size() == 0;
- list = operationManager.findRecentlyCompletedResourceOperations(overlord, null, PageControl
- .getUnlimitedInstance());
+ list = operationManager.findRecentlyCompletedResourceOperations(overlord, null,
+ PageControl.getUnlimitedInstance());
assert list.size() == 0;
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncContentProviderTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncContentProviderTest.java
index d0beddc..dd72437 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncContentProviderTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncContentProviderTest.java
@@ -27,7 +27,6 @@ import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
-import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.testng.annotations.AfterMethod;
@@ -121,58 +120,60 @@ public class ContentProviderManagerSyncContentProviderTest extends AbstractEJB3T
@AfterMethod
public void tearDownAfterMethod() throws Exception {
- // Transactional stuff
- TransactionManager tx = getTransactionManager();
- tx.begin();
- EntityManager entityManager = getEntityManager();
-
- RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
- Subject overlord = subjectManager.getOverlord();
-
- // Delete the repo relationships
- entityManager.createNamedQuery(RepoRepoRelationship.DELETE_BY_REPO_ID).setParameter("repoId", repoId)
- .executeUpdate();
-
- entityManager.createNamedQuery(RepoRelationship.DELETE_BY_RELATED_REPO_ID).setParameter("relatedRepoId",
- relatedRepoId).executeUpdate();
+ try {
+ // Transactional stuff
+ TransactionManager tx = getTransactionManager();
+ tx.begin();
+ EntityManager entityManager = getEntityManager();
- // Delete any repos that were created in this test
- for (Integer repoId : reposToDelete) {
- repoManager.deleteRepo(overlord, repoId);
- }
- reposToDelete.clear();
+ RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
+ SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ Subject overlord = subjectManager.getOverlord();
- // Delete any repo groups that were created in this test
- for (Integer repoGroupId : repoGroupsToDelete) {
- repoManager.deleteRepoGroup(overlord, repoGroupId);
+ // Delete the repo relationships
+ entityManager.createNamedQuery(RepoRepoRelationship.DELETE_BY_REPO_ID).setParameter("repoId", repoId)
+ .executeUpdate();
+
+ entityManager.createNamedQuery(RepoRelationship.DELETE_BY_RELATED_REPO_ID)
+ .setParameter("relatedRepoId", relatedRepoId).executeUpdate();
+
+ // Delete any repos that were created in this test
+ for (Integer repoId : reposToDelete) {
+ repoManager.deleteRepo(overlord, repoId);
+ }
+ reposToDelete.clear();
+
+ // Delete any repo groups that were created in this test
+ for (Integer repoGroupId : repoGroupsToDelete) {
+ repoManager.deleteRepoGroup(overlord, repoGroupId);
+ }
+ repoGroupsToDelete.clear();
+
+ // First disassociate packages from the content source
+ entityManager.createNamedQuery(PackageVersionContentSource.DELETE_BY_CONTENT_SOURCE_ID)
+ .setParameter("contentSourceId", syncSource.getId()).executeUpdate();
+
+ // Delete the existing repos
+ nonCandidateOnOtherSource = entityManager.find(Repo.class, nonCandidateOnOtherSource.getId());
+ entityManager.remove(nonCandidateOnOtherSource);
+
+ // Delete the source that was created
+ syncSource = entityManager.find(ContentSource.class, syncSource.getId());
+ entityManager.remove(syncSource);
+
+ nonSyncSource = entityManager.find(ContentSource.class, nonSyncSource.getId());
+ entityManager.remove(nonSyncSource);
+
+ // Delete the fake source type
+ testSourceType = entityManager.find(ContentSourceType.class, testSourceType.getId());
+ entityManager.remove(testSourceType);
+
+ tx.commit();
+ } finally {
+ // Plugin service teardown
+ unprepareServerPluginService();
+ unprepareScheduler();
}
- repoGroupsToDelete.clear();
-
- // First disassociate packages from the content source
- entityManager.createNamedQuery(PackageVersionContentSource.DELETE_BY_CONTENT_SOURCE_ID).setParameter(
- "contentSourceId", syncSource.getId()).executeUpdate();
-
- // Delete the existing repos
- nonCandidateOnOtherSource = entityManager.find(Repo.class, nonCandidateOnOtherSource.getId());
- entityManager.remove(nonCandidateOnOtherSource);
-
- // Delete the source that was created
- syncSource = entityManager.find(ContentSource.class, syncSource.getId());
- entityManager.remove(syncSource);
-
- nonSyncSource = entityManager.find(ContentSource.class, nonSyncSource.getId());
- entityManager.remove(nonSyncSource);
-
- // Delete the fake source type
- testSourceType = entityManager.find(ContentSourceType.class, testSourceType.getId());
- entityManager.remove(testSourceType);
-
- tx.commit();
-
- // Plugin service teardown
- unprepareServerPluginService();
- unprepareScheduler();
}
@Test
@@ -210,12 +211,13 @@ public class ContentProviderManagerSyncContentProviderTest extends AbstractEJB3T
previousRepo.addContentSource(syncSource);
repoManager.createRepo(overlord, previousRepo);
- // Test
- // --------------------------------------------
- // TestContentProviderManager providerManager = new TestContentProviderManager();
+ // Test
+ // --------------------------------------------
+ // TestContentProviderManager providerManager = new TestContentProviderManager();
pluginService.getContentProviderManager().testConnection(syncSource.getId());
- boolean completed = pluginService.getContentProviderManager().synchronizeContentProvider(syncSource.getId());
+ boolean completed = pluginService.getContentProviderManager()
+ .synchronizeContentProvider(syncSource.getId());
assert completed;
// Verify RepoGroups
@@ -303,7 +305,7 @@ public class ContentProviderManagerSyncContentProviderTest extends AbstractEJB3T
assert retrievedRepos.size() == 0;
getTransactionManager().commit();
- } catch(Throwable t) {
+ } catch (Throwable t) {
getTransactionManager().rollback();
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncRepoTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncRepoTest.java
index 22d65e2..65154bb 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncRepoTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerSyncRepoTest.java
@@ -167,76 +167,79 @@ public class ContentProviderManagerSyncRepoTest extends AbstractEJB3Test {
@AfterMethod
public void tearDownAfterMethod() throws Exception {
+ try {
- TransactionManager tx = getTransactionManager();
- tx.begin();
- EntityManager entityManager = getEntityManager();
+ TransactionManager tx = getTransactionManager();
+ tx.begin();
+ EntityManager entityManager = getEntityManager();
- Query query;
+ Query query;
- ContentSourceManagerLocal contentSourceManagerLocal = LookupUtil.getContentSourceManager();
- RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
- DistributionManagerLocal distroManager = LookupUtil.getDistributionManagerLocal();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
- Subject overlord = subjectManager.getOverlord();
+ ContentSourceManagerLocal contentSourceManagerLocal = LookupUtil.getContentSourceManager();
+ RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
+ DistributionManagerLocal distroManager = LookupUtil.getDistributionManagerLocal();
+ SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ Subject overlord = subjectManager.getOverlord();
- // Delete all distributions
- distroManager.deleteDistributionMappingsForRepo(overlord, repoToSync.getId());
+ // Delete all distributions
+ distroManager.deleteDistributionMappingsForRepo(overlord, repoToSync.getId());
- for (String distroLabel : TestContentProvider.DISTRIBUTIONS.keySet()) {
- Distribution distro = distroManager.getDistributionByLabel(distroLabel);
- if (distro != null) {
- // Delete the files
- query = entityManager.createNamedQuery(DistributionFile.DELETE_BY_DIST_ID);
- query.setParameter("distId", distro.getId());
- query.executeUpdate();
+ for (String distroLabel : TestContentProvider.DISTRIBUTIONS.keySet()) {
+ Distribution distro = distroManager.getDistributionByLabel(distroLabel);
+ if (distro != null) {
+ // Delete the files
+ query = entityManager.createNamedQuery(DistributionFile.DELETE_BY_DIST_ID);
+ query.setParameter("distId", distro.getId());
+ query.executeUpdate();
- // Delete the actual distro
- distroManager.deleteDistributionByDistId(overlord, distro.getId());
+ // Delete the actual distro
+ distroManager.deleteDistributionByDistId(overlord, distro.getId());
+ }
}
- }
- // Delete all package version <-> content source mappings
- for (ContentSource source : repoContentSources) {
- contentSourceManagerLocal.deleteContentSource(overlord, source.getId());
- }
- repoContentSources.clear();
+ // Delete all package version <-> content source mappings
+ for (ContentSource source : repoContentSources) {
+ contentSourceManagerLocal.deleteContentSource(overlord, source.getId());
+ }
+ repoContentSources.clear();
- // Delete the repo
- repoManager.deleteRepo(overlord, repoToSync.getId());
+ // Delete the repo
+ repoManager.deleteRepo(overlord, repoToSync.getId());
- // Delete any packages that were created
- for (ContentProviderPackageDetails details : TestContentProvider.PACKAGES.values()) {
- String packageName = details.getContentProviderPackageDetailsKey().getName();
+ // Delete any packages that were created
+ for (ContentProviderPackageDetails details : TestContentProvider.PACKAGES.values()) {
+ String packageName = details.getContentProviderPackageDetailsKey().getName();
- query = entityManager.createNamedQuery(Package.QUERY_FIND_BY_NAME_PKG_TYPE_ID);
- query.setParameter("name", packageName);
- query.setParameter("packageTypeId", packageType.getId());
+ query = entityManager.createNamedQuery(Package.QUERY_FIND_BY_NAME_PKG_TYPE_ID);
+ query.setParameter("name", packageName);
+ query.setParameter("packageTypeId", packageType.getId());
- Package p = (Package) query.getSingleResult();
- entityManager.remove(p);
- }
+ Package p = (Package) query.getSingleResult();
+ entityManager.remove(p);
+ }
- // Delete the package type
- packageType = entityManager.find(PackageType.class, packageType.getId());
- entityManager.remove(packageType);
+ // Delete the package type
+ packageType = entityManager.find(PackageType.class, packageType.getId());
+ entityManager.remove(packageType);
- resourceType = entityManager.find(ResourceType.class, resourceType.getId());
- entityManager.remove(resourceType);
+ resourceType = entityManager.find(ResourceType.class, resourceType.getId());
+ entityManager.remove(resourceType);
- // Delete the content source type
- contentSourceType = entityManager.find(ContentSourceType.class, contentSourceType.getId());
- entityManager.remove(contentSourceType);
+ // Delete the content source type
+ contentSourceType = entityManager.find(ContentSourceType.class, contentSourceType.getId());
+ entityManager.remove(contentSourceType);
- tx.commit();
+ tx.commit();
- // Cleanup providers between tests
- contentProvider1.reset();
- contentProvider2.reset();
+ // Cleanup providers between tests
+ contentProvider1.reset();
+ contentProvider2.reset();
- // Plugin service teardown
- unprepareServerPluginService();
- unprepareScheduler();
+ } finally {
+ // Plugin service teardown
+ unprepareServerPluginService();
+ unprepareScheduler();
+ }
}
@Test(enabled = TESTS_ENABLED)
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/group/test/LdapGroupManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/group/test/LdapGroupManagerBeanTest.java
index c4cfca5..78d23e8 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/group/test/LdapGroupManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/group/test/LdapGroupManagerBeanTest.java
@@ -25,8 +25,9 @@ import java.util.Properties;
import javax.persistence.Query;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.rhq.core.domain.common.SystemConfiguration;
@@ -65,6 +66,7 @@ import org.rhq.test.TransactionCallback;
* @author loleary
*
*/
+@SuppressWarnings("deprecation")
public class LdapGroupManagerBeanTest extends AbstractEJB3Test {
/**
@@ -95,7 +97,7 @@ public class LdapGroupManagerBeanTest extends AbstractEJB3Test {
private LdapGroupManagerLocal ldapGroupManager = null;
private SystemManagerLocal systemManager = null;
private TestServerPluginService testServerPluginService = null;
-
+
// private Subject overlord = null;
@BeforeClass
@@ -104,12 +106,15 @@ public class LdapGroupManagerBeanTest extends AbstractEJB3Test {
// overlord = LookupUtil.getSubjectManager().getOverlord();
systemManager = LookupUtil.getSystemManager();
ldapGroupManager = LookupUtil.getLdapGroupManager();
+ }
+ @BeforeMethod
+ public void beforeMethod() throws Exception {
//we need this because the drift plugins are referenced from the system settings that we use in our tests
testServerPluginService = new TestServerPluginService();
prepareCustomServerPluginService(testServerPluginService);
testServerPluginService.startMasterPluginContainer();
-
+
// get our Maven properties for LDAP testing
java.net.URL url = LdapGroupManagerBeanTest.class.getClassLoader().getResource("test-ldap.properties");
Properties mvnProps = new Properties();
@@ -146,12 +151,11 @@ public class LdapGroupManagerBeanTest extends AbstractEJB3Test {
this.setLdapGroupMemberAttribute("member");
}
- @AfterClass
- public void tearDown() throws Exception {
+ @AfterMethod(alwaysRun = true)
+ public void afterMethod() throws Exception {
unprepareServerPluginService();
- testServerPluginService.stopMasterPluginContainer();
}
-
+
/**
* Test {@link LdapGroupManagerBean#findAvailableGroupsFor(String)} method
* using a user who does not exist in the test LDAP instance.
@@ -485,21 +489,21 @@ public class LdapGroupManagerBeanTest extends AbstractEJB3Test {
private void setLdapCtxFactory(final String name) throws Exception {
//this is a readonly system property that we are trying to override, so we
//need to be a little bit more persuasive...
- executeInTransaction(new TransactionCallback() {
+ executeInTransaction(new TransactionCallback() {
@Override
public void execute() throws Exception {
Query q = getEntityManager().createNamedQuery(SystemConfiguration.FIND_PROPERTY_BY_KEY);
q.setParameter("key", SystemSetting.LDAP_NAMING_FACTORY.getInternalName());
-
+
SystemConfiguration config = (SystemConfiguration) q.getSingleResult();
config.setPropertyValue(name);
-
+
getEntityManager().merge(config);
-
+
getEntityManager().flush();
}
});
-
+
//reload the system settings cache so that the new value is reflected there immediately
systemManager.loadSystemConfigurationCache();
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ContentMetadataManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ContentMetadataManagerBeanTest.java
index 07d320e..712606d 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ContentMetadataManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/ContentMetadataManagerBeanTest.java
@@ -1,7 +1,7 @@
package org.rhq.enterprise.server.resource.metadata;
-import java.util.Arrays;
-import java.util.Collections;
+import static java.util.Arrays.asList;
+import static java.util.Collections.EMPTY_LIST;
import org.testng.annotations.Test;
@@ -10,62 +10,43 @@ import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.resource.ResourceType;
-import static java.util.Arrays.asList;
-import static java.util.Collections.EMPTY_LIST;
-
public class ContentMetadataManagerBeanTest extends MetadataBeanTest {
- @Test(groups = {"plugin.metadata", "Content.NewPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.NewPlugin" })
public void registerContentPlugin() throws Exception {
createPlugin("content-test-plugin", "1.0", "plugin_v1.xml");
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnGroups = {"Content.NewPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnGroups = { "Content.NewPlugin" })
public void upgradeContentPlugin() throws Exception {
createPlugin("content-test-plugin", "2.0", "plugin_v2.xml");
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void addPackageTypes() throws Exception {
- assertResourceTypeAssociationEquals(
- "ContentServer1",
- "ContentMetadataManagerBeanTestPlugin",
- "packageTypes",
- asList("ContentServer1.Content.1", "ContentServer1.Content.2")
- );
- }
-
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ assertResourceTypeAssociationEquals("ContentServer1", "ContentMetadataManagerBeanTestPlugin", "packageTypes",
+ asList("ContentServer1.Content.1", "ContentServer1.Content.2"));
+ }
+
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void deletePackageTypes() throws Exception {
- assertResourceTypeAssociationEquals(
- "ContentServer2",
- "ContentMetadataManagerBeanTestPlugin",
- "packageTypes",
- EMPTY_LIST
- );
+ assertResourceTypeAssociationEquals("ContentServer2", "ContentMetadataManagerBeanTestPlugin", "packageTypes",
+ EMPTY_LIST);
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void deletePackageTypesThatExistsInOldResourceTypeButNotInNewResourceType() throws Exception {
- assertResourceTypeAssociationEquals(
- "ContentServer3",
- "ContentMetadataManagerBeanTestPlugin",
- "packageTypes",
- asList("ContentServer3.Content.2", "ContentServer3.Content.3")
- );
+ assertResourceTypeAssociationEquals("ContentServer3", "ContentMetadataManagerBeanTestPlugin", "packageTypes",
+ asList("ContentServer3.Content.2", "ContentServer3.Content.3"));
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void addPackageThatAreAddedInNewResourceType() throws Exception {
- assertResourceTypeAssociationEquals(
- "ContentServer4",
- "ContentMetadataManagerBeanTestPlugin",
- "packageTypes",
- asList("ContentServer4.Content.1", "ContentServer4.Content.2")
- );
+ assertResourceTypeAssociationEquals("ContentServer4", "ContentMetadataManagerBeanTestPlugin", "packageTypes",
+ asList("ContentServer4.Content.1", "ContentServer4.Content.2"));
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void addNewDeploymentConfigurationDefinition() throws Exception {
PackageType packageType = loadPackageType("ContentServer", "ContentMetadataManagerBeanTestPlugin",
"ContentServer.Content.1");
@@ -74,67 +55,49 @@ public class ContentMetadataManagerBeanTest extends MetadataBeanTest {
assertNotNull(
"Failed to create new deployment configuration definition for package type that previously did not have one",
- deploymentConfigDef
- );
- assertEquals(
- "Expected to find 1 property definition in new deployment configuration definition",
- 1,
- deploymentConfigDef.getPropertyDefinitions().size()
- );
- assertNotNull(
- "Expected to find 1 property definition, <version>, in new deployment configuration definition",
- deploymentConfigDef.get("version")
- );
+ deploymentConfigDef);
+ assertEquals("Expected to find 1 property definition in new deployment configuration definition", 1,
+ deploymentConfigDef.getPropertyDefinitions().size());
+ assertNotNull("Expected to find 1 property definition, <version>, in new deployment configuration definition",
+ deploymentConfigDef.get("version"));
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void updateDeploymentConfigDefThatExistsInOldAndNewResourceType() throws Exception {
PackageType packageType = loadPackageType("ContentServer5", "ContentMetadataManagerBeanTestPlugin",
"ContentServer5.Content.1");
ConfigurationDefinition deploymentConfigDef = packageType.getDeploymentConfigurationDefinition();
assertNotNull("Failed to update deployment configuration definition for package type", deploymentConfigDef);
- assertEquals(
- "Expected to find 2 property definitions in updated deployment configuration definition",
- 2,
- deploymentConfigDef.getPropertyDefinitions().size()
- );
- assertNotNull(
- "Expected existing property definition to be retained across update",
- deploymentConfigDef.get("x")
- );
- assertNotNull(
- "Expected new property definition to be added during update",
- deploymentConfigDef.get("y")
- );
- }
+ assertEquals("Expected to find 2 property definitions in updated deployment configuration definition", 2,
+ deploymentConfigDef.getPropertyDefinitions().size());
+ assertNotNull("Expected existing property definition to be retained across update",
+ deploymentConfigDef.get("x"));
+ assertNotNull("Expected new property definition to be added during update", deploymentConfigDef.get("y"));
+ }
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void deleteDeploymentConfigDefThatIsRemovedInNewResourceType() {
PackageType packageType = loadPackageType("ContentServer5", "ContentMetadataManagerBeanTestPlugin",
"ContentServer5.Content.2");
assertNull(
"Expected deployment configuration definition to be removed since it was removed from new resource type",
- packageType.getDeploymentConfigurationDefinition()
- );
+ packageType.getDeploymentConfigurationDefinition());
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void updateBundleType() {
ResourceType resourceType = loadResourceTypeWithBundleType("ContentServer7",
"ContentMetadataManagerBeanTestPlugin");
BundleType bundleType = resourceType.getBundleType();
assertNotNull("Failed to upgrade bundle type", bundleType);
- assertEquals(
- "Failed to upgrade bundle type correctly. The bundle type name is wrong",
- "ContentServer.Bundle.2",
- bundleType.getName()
- );
+ assertEquals("Failed to upgrade bundle type correctly. The bundle type name is wrong",
+ "ContentServer.Bundle.2", bundleType.getName());
}
- @Test(groups = {"plugin.metadata", "Content.UpgradePlugin"}, dependsOnMethods = {"upgradeContentPlugin"})
+ @Test(groups = { "plugin.metadata", "Content.UpgradePlugin" }, dependsOnMethods = { "upgradeContentPlugin" })
public void addBundleTypeThatOnlyExistsInNewResourceType() {
ResourceType resourceType = loadResourceTypeWithBundleType("ContentServer6",
"ContentMetadataManagerBeanTestPlugin");
@@ -146,23 +109,19 @@ public class ContentMetadataManagerBeanTest extends MetadataBeanTest {
}
PackageType loadPackageType(String resourceType, String plugin, String packageType) {
- return (PackageType) getEntityManager().createQuery(
- "from PackageType p left join fetch p.deploymentConfigurationDefinition " +
- "where p.name = :packageType and " +
- "p.resourceType.name = :resourceType and " +
- "p.resourceType.plugin = :plugin")
- .setParameter("packageType", packageType)
- .setParameter("plugin", plugin)
- .setParameter("resourceType", resourceType)
- .getSingleResult();
+ return (PackageType) getEntityManager()
+ .createQuery(
+ "from PackageType p left join fetch p.deploymentConfigurationDefinition "
+ + "where p.name = :packageType and " + "p.resourceType.name = :resourceType and "
+ + "p.resourceType.plugin = :plugin").setParameter("packageType", packageType)
+ .setParameter("plugin", plugin).setParameter("resourceType", resourceType).getSingleResult();
}
ResourceType loadResourceTypeWithBundleType(String resourceType, String plugin) {
- return (ResourceType) getEntityManager().createQuery(
- "from ResourceType t left join fetch t.bundleType where t.name = :resourceType and t.plugin = :plugin")
- .setParameter("resourceType", resourceType)
- .setParameter("plugin", plugin)
- .getSingleResult();
- }
+ return (ResourceType) getEntityManager()
+ .createQuery(
+ "from ResourceType t left join fetch t.bundleType where t.name = :resourceType and t.plugin = :plugin")
+ .setParameter("resourceType", resourceType).setParameter("plugin", plugin).getSingleResult();
+ }
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/EventMetadataManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/EventMetadataManagerBeanTest.java
index a8bb5e4..99e1e22 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/EventMetadataManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/EventMetadataManagerBeanTest.java
@@ -1,33 +1,26 @@
package org.rhq.enterprise.server.resource.metadata;
-import java.util.Arrays;
-import java.util.Collections;
+import static java.util.Arrays.asList;
+import static java.util.Collections.EMPTY_LIST;
import org.testng.annotations.Test;
import org.rhq.core.domain.event.EventDefinition;
-import static java.util.Arrays.asList;
-import static java.util.Collections.EMPTY_LIST;
-
public class EventMetadataManagerBeanTest extends MetadataBeanTest {
- @Test(groups = {"plugin.metadata", "Events.NewPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.NewPlugin" })
public void registerEventsPlugin() throws Exception {
createPlugin("event-test-plugin", "1.0", "plugin_v1.xml");
}
- @Test(groups = {"plugin.metadata", "Events.NewPlugin"}, dependsOnMethods = {"registerEventsPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.NewPlugin" }, dependsOnMethods = { "registerEventsPlugin" })
public void persistNewEventDefs() throws Exception {
- assertResourceTypeAssociationEquals(
- "EventServer1",
- "EventMetadataManagerBeanTestPlugin",
- "eventDefinitions",
- asList("event1", "event2")
- );
+ assertResourceTypeAssociationEquals("EventServer1", "EventMetadataManagerBeanTestPlugin", "eventDefinitions",
+ asList("event1", "event2"));
}
- @Test(groups = {"plugin.metadata", "Events.NewPlugin"}, dependsOnMethods = {"persistNewEventDefs"})
+ @Test(groups = { "plugin.metadata", "Events.NewPlugin" }, dependsOnMethods = { "persistNewEventDefs" })
public void persistNewEventDefProperties() {
EventDefinition eventDef = loadEventDef("event1", "EventServer1");
@@ -35,60 +28,42 @@ public class EventMetadataManagerBeanTest extends MetadataBeanTest {
assertEquals("Failed to set EventDefinition.description", "Event 1", eventDef.getDescription());
}
- @Test(groups = {"plugin.metadata", "Events.UpgradePlugin"}, dependsOnGroups = {"Events.NewPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.UpgradePlugin" }, dependsOnGroups = { "Events.NewPlugin" })
public void upgradeEventsPlugin() throws Exception {
createPlugin("event-test-plugin", "2.0", "plugin_v2.xml");
}
- @Test(groups = {"plugin.metadata", "Events.UpgradePlugin"}, dependsOnMethods = {"upgradeEventsPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.UpgradePlugin" }, dependsOnMethods = { "upgradeEventsPlugin" })
public void retainEventDefsOfTypeThatIsNotChangedDuringUpgrade() throws Exception {
- assertResourceTypeAssociationEquals(
- "EventServer1",
- "EventMetadataManagerBeanTestPlugin",
- "eventDefinitions",
- asList("event1", "event2")
- );
+ assertResourceTypeAssociationEquals("EventServer1", "EventMetadataManagerBeanTestPlugin", "eventDefinitions",
+ asList("event1", "event2"));
}
- @Test(groups = {"plugin.metadata", "Events.UpgradePlugin"}, dependsOnMethods = {"upgradeEventsPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.UpgradePlugin" }, dependsOnMethods = { "upgradeEventsPlugin" })
public void addNewEventDefs() throws Exception {
- assertResourceTypeAssociationEquals(
- "EventServer2",
- "EventMetadataManagerBeanTestPlugin",
- "eventDefinitions",
- asList("event1", "event2")
- );
+ assertResourceTypeAssociationEquals("EventServer2", "EventMetadataManagerBeanTestPlugin", "eventDefinitions",
+ asList("event1", "event2"));
}
- @Test(groups = {"plugin.metadata", "Events.UpgradePlugin"}, dependsOnMethods = {"upgradeEventsPlugin"})
+ @Test(groups = { "plugin.metadata", "Events.UpgradePlugin" }, dependsOnMethods = { "upgradeEventsPlugin" })
public void deleteEventDefsThatHaveBeenRemovedInUpgradedType() throws Exception {
- assertResourceTypeAssociationEquals(
- "EventServer3",
- "EventMetadataManagerBeanTestPlugin",
- "eventDefinitions",
- EMPTY_LIST
- );
- }
-
- @Test(groups = {"plugin.metadata", "Events.UpgradePlugin"}, dependsOnMethods = {"upgradeEventsPlugin"})
+ assertResourceTypeAssociationEquals("EventServer3", "EventMetadataManagerBeanTestPlugin", "eventDefinitions",
+ EMPTY_LIST);
+ }
+
+ @Test(groups = { "plugin.metadata", "Events.UpgradePlugin" }, dependsOnMethods = { "upgradeEventsPlugin" })
public void updateExistingEventDefs() throws Exception {
- assertResourceTypeAssociationEquals(
- "EventServer4",
- "EventMetadataManagerBeanTestPlugin",
- "eventDefinitions",
- asList("event1", "event3")
- );
+ assertResourceTypeAssociationEquals("EventServer4", "EventMetadataManagerBeanTestPlugin", "eventDefinitions",
+ asList("event1", "event3"));
EventDefinition eventDef = loadEventDef("event1", "EventServer4");
assertEquals("The description property should have been updated", "EVENT ONE", eventDef.getDescription());
}
EventDefinition loadEventDef(String name, String resourceType) {
- return (EventDefinition) getEntityManager().createQuery(
- "from EventDefinition e where e.name = :name and e.resourceType.name = :resourceType")
- .setParameter("name", name)
- .setParameter("resourceType", resourceType)
- .getSingleResult();
+ return (EventDefinition) getEntityManager()
+ .createQuery("from EventDefinition e where e.name = :name and e.resourceType.name = :resourceType")
+ .setParameter("name", name).setParameter("resourceType", resourceType).getSingleResult();
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
index 7ffacbf..fac9251 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/MetadataBeanTest.java
@@ -1,5 +1,7 @@
package org.rhq.enterprise.server.resource.metadata;
+import static org.rhq.core.clientapi.shared.PluginDescriptorUtil.loadPluginDescriptor;
+
import java.io.File;
import java.net.URL;
import java.sql.Connection;
@@ -23,7 +25,9 @@ import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
import org.testng.annotations.AfterGroups;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.BeforeMethod;
import org.xml.sax.InputSource;
import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
@@ -37,8 +41,6 @@ import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.util.LookupUtil;
-import static org.rhq.core.clientapi.shared.PluginDescriptorUtil.loadPluginDescriptor;
-
public class MetadataBeanTest extends AbstractEJB3Test {
private static List<String> plugins = new ArrayList<String>();
@@ -49,9 +51,25 @@ public class MetadataBeanTest extends AbstractEJB3Test {
}
@BeforeGroups(groups = { "plugin.metadata" }, dependsOnGroups = { "integration.ejb3" })
- public void startMBeanServer() throws Exception {
+ public void beforeGroups() throws Exception {
setupDB();
+ }
+ /**
+ * Need to delete rows from RHQ_PLUGINS because subsequent tests in server/jar would otherwise fail. Some tests look
+ * at what plugins are in the database, and then look for corresponding plugin files on the file system. MetadataTest
+ * however removes the generated plugin files during each test run.
+ */
+ @AfterGroups(alwaysRun = true, groups = { "plugin.metadata" })
+ void afterGroups() throws Exception {
+ getTransactionManager().begin();
+ getEntityManager().createQuery("delete from Plugin p where p.name in (:plugins)")
+ .setParameter("plugins", plugins).executeUpdate();
+ getTransactionManager().commit();
+ }
+
+ @BeforeMethod(groups = { "plugin.metadata" }, dependsOnGroups = { "integration.ejb3" })
+ public void beforeMethod() throws Exception {
TestBundleServerPluginService bundleService = new TestBundleServerPluginService();
prepareCustomServerPluginService(bundleService);
bundleService.startMasterPluginContainerWithoutSchedulingJobs();
@@ -63,14 +81,10 @@ public class MetadataBeanTest extends AbstractEJB3Test {
* at what plugins are in the database, and then look for corresponding plugin files on the file system. MetadataTest
* however removes the generated plugin files during each test run.
*/
- @AfterGroups(groups = { "plugin.metadata" })
- void removePluginsFromDB() throws Exception {
+ @AfterMethod(alwaysRun = true, groups = { "plugin.metadata" })
+ void afterMethod() throws Exception {
+ unprepareServerPluginService();
unprepareScheduler();
-
- getTransactionManager().begin();
- getEntityManager().createQuery("delete from Plugin p where p.name in (:plugins)").setParameter("plugins",
- plugins).executeUpdate();
- getTransactionManager().commit();
}
protected void setupDB() throws Exception {
@@ -145,6 +159,7 @@ public class MetadataBeanTest extends AbstractEJB3Test {
return getClass().getResource(dir + "/" + descriptor);
}
+ @SuppressWarnings("unused")
private String getPluginWorkDir() throws Exception {
return getCurrentWorkingDir() + "/work";
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/test/UpdatePluginMetadataTestBase.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/test/UpdatePluginMetadataTestBase.java
index 535fd06..f381318 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/test/UpdatePluginMetadataTestBase.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/metadata/test/UpdatePluginMetadataTestBase.java
@@ -37,7 +37,7 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.rhq.core.clientapi.agent.measurement.MeasurementAgentService;
@@ -77,8 +77,18 @@ public class UpdatePluginMetadataTestBase extends AbstractEJB3Test {
protected static ResourceTypeManagerLocal resourceTypeManager;
protected static ResourceManagerLocal resourceManager;
+ @AfterClass
+ public void afterClass() throws Exception {
+ cleanupTest();
+ }
+
@BeforeMethod
protected void init() {
+ agentServiceContainer = prepareForTestAgents();
+ prepareMockAgentServiceContainer();
+
+ prepareScheduler();
+
try {
pluginMgr = LookupUtil.getPluginManager();
resourceTypeManager = LookupUtil.getResourceTypeManager();
@@ -91,25 +101,16 @@ public class UpdatePluginMetadataTestBase extends AbstractEJB3Test {
}
}
- @BeforeClass
- public void beforeClass() {
- agentServiceContainer = prepareForTestAgents();
- prepareMockAgentServiceContainer();
-
- prepareScheduler();
+ @AfterMethod(alwaysRun = true)
+ public void afterMethod() throws Exception {
+ unprepareForTestAgents();
+ unprepareScheduler();
}
protected void prepareMockAgentServiceContainer() {
agentServiceContainer.measurementService = new MockMeasurementAgentService();
}
- @AfterClass
- public void afterClass() throws Exception {
- unprepareForTestAgents();
- unprepareScheduler();
- cleanupTest();
- }
-
protected ResourceType getResourceType(String typeName) {
return getResourceType(typeName, PLUGIN_NAME);
}
@@ -225,8 +226,8 @@ public class UpdatePluginMetadataTestBase extends AbstractEJB3Test {
protected int getPluginId(EntityManager entityManager) throws NoResultException {
Plugin existingPlugin;
try {
- existingPlugin = (Plugin) entityManager.createNamedQuery(Plugin.QUERY_FIND_BY_NAME).setParameter("name",
- PLUGIN_NAME).getSingleResult();
+ existingPlugin = (Plugin) entityManager.createNamedQuery(Plugin.QUERY_FIND_BY_NAME)
+ .setParameter("name", PLUGIN_NAME).getSingleResult();
int plugin1Id = existingPlugin.getId();
return plugin1Id;
} catch (NoResultException nre) {
@@ -247,8 +248,8 @@ public class UpdatePluginMetadataTestBase extends AbstractEJB3Test {
protected Agent getAgent(EntityManager entityManager) throws NoResultException {
Agent existingAgent;
try {
- existingAgent = (Agent) entityManager.createNamedQuery(Agent.QUERY_FIND_BY_NAME).setParameter("name",
- AGENT_NAME).getSingleResult();
+ existingAgent = (Agent) entityManager.createNamedQuery(Agent.QUERY_FIND_BY_NAME)
+ .setParameter("name", AGENT_NAME).getSingleResult();
return existingAgent;
} catch (NoResultException nre) {
throw nre;
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceFactoryManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceFactoryManagerBeanTest.java
index f38c1a4..fdb6607 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceFactoryManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceFactoryManagerBeanTest.java
@@ -26,9 +26,6 @@ import java.util.Set;
import javax.persistence.EntityManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
@@ -68,8 +65,6 @@ import org.rhq.enterprise.server.util.LookupUtil;
public class ResourceFactoryManagerBeanTest extends AbstractEJB3Test {
// Attributes --------------------------------------------
- private final Log log = LogFactory.getLog(ResourceFactoryManagerBeanTest.class);
-
private ResourceFactoryManagerLocal resourceFactoryManager;
private ResourceManagerLocal resourceManager;
private Subject overlord;
@@ -89,7 +84,10 @@ public class ResourceFactoryManagerBeanTest extends AbstractEJB3Test {
resourceFactoryManager = LookupUtil.getResourceFactoryManager();
resourceManager = LookupUtil.getResourceManager();
overlord = LookupUtil.getSubjectManager().getOverlord();
+ }
+ @BeforeMethod
+ public void setupBeforeMethod() throws Exception {
prepareScheduler();
TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
agentServiceContainer.resourceFactoryService = mockAgentService;
@@ -98,22 +96,16 @@ public class ResourceFactoryManagerBeanTest extends AbstractEJB3Test {
StandardServerPluginService serverPluginService = new StandardServerPluginService();
prepareCustomServerPluginService(serverPluginService);
serverPluginService.startMasterPluginContainer();
+
+ setupResourceEnvironment();
}
- @AfterClass
- public void teardownAfterClass() throws Exception {
+ @AfterMethod(alwaysRun = true)
+ public void teardownAfterMethod() throws Exception {
unprepareForTestAgents();
unprepareScheduler();
unprepareServerPluginService();
- }
- @BeforeMethod
- public void setupBeforeMethod() throws Exception {
- setupResourceEnvironment();
- }
-
- @AfterMethod
- public void teardownAfterMethod() throws Exception {
teardownResourceEnvironment();
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/scheduler/jobs/DataPurgeJobTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/scheduler/jobs/DataPurgeJobTest.java
index e3f52f5..7506aaa 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/scheduler/jobs/DataPurgeJobTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/scheduler/jobs/DataPurgeJobTest.java
@@ -36,9 +36,7 @@ import javax.transaction.SystemException;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
-import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -94,27 +92,19 @@ import org.rhq.enterprise.server.util.LookupUtil;
public class DataPurgeJobTest extends AbstractEJB3Test {
private Resource newResource;
+ @SuppressWarnings("unused")
private int agentId;
private int resourceTypeId;
private TestServerPluginService testServerPluginService;
-
- @BeforeClass
- public void setup() {
- //we need this because the drift plugins are referenced from the system settings that we use in our tests
- testServerPluginService = new TestServerPluginService();
- prepareCustomServerPluginService(testServerPluginService);
- testServerPluginService.startMasterPluginContainer();
- }
- @AfterClass
- public void tearDown() throws Exception {
- unprepareServerPluginService();
- testServerPluginService.stopMasterPluginContainer();
- }
-
@BeforeMethod
public void beforeMethod() throws Throwable {
try {
+ //we need this because the drift plugins are referenced from the system settings that we use in our tests
+ testServerPluginService = new TestServerPluginService();
+ prepareCustomServerPluginService(testServerPluginService);
+ testServerPluginService.startMasterPluginContainer();
+
prepareScheduler();
TestServerCommunicationsService agentContainer = prepareForTestAgents();
newResource = createNewResource();
@@ -125,12 +115,13 @@ public class DataPurgeJobTest extends AbstractEJB3Test {
}
}
- @AfterMethod
+ @AfterMethod(alwaysRun = true)
public void afterMethod() throws Throwable {
try {
deleteNewResource(newResource);
unprepareForTestAgents();
unprepareScheduler();
+ unprepareServerPluginService();
} catch (Throwable t) {
System.err.println("Cannot unprepare test: " + t);
t.printStackTrace();
@@ -369,8 +360,8 @@ public class DataPurgeJobTest extends AbstractEJB3Test {
}
mgr.addTraitData(dataset);
- List<MeasurementDataTrait> persistedTraits = mgr.findTraits(LookupUtil.getSubjectManager().getOverlord(), res
- .getId(), traitSchedule.getDefinition().getId());
+ List<MeasurementDataTrait> persistedTraits = mgr.findTraits(LookupUtil.getSubjectManager().getOverlord(),
+ res.getId(), traitSchedule.getDefinition().getId());
assert persistedTraits.size() == count : "did not persist trait data:" + persistedTraits.size() + ":"
+ persistedTraits;
}
@@ -424,9 +415,9 @@ public class DataPurgeJobTest extends AbstractEJB3Test {
mgr.addEventData(eventMap);
Subject overlord = LookupUtil.getSubjectManager().getOverlord();
- PageList<EventComposite> persistedEvents = mgr.findEventComposites(overlord, EntityContext.forResource(res
- .getId()), timestamp - 1L, timestamp + count + 1L, new EventSeverity[] { EventSeverity.DEBUG }, null, null,
- new PageControl());
+ PageList<EventComposite> persistedEvents = mgr.findEventComposites(overlord,
+ EntityContext.forResource(res.getId()), timestamp - 1L, timestamp + count + 1L,
+ new EventSeverity[] { EventSeverity.DEBUG }, null, null, new PageControl());
assert persistedEvents.getTotalSize() == count : "did not persist all events, only persisted: "
+ persistedEvents.getTotalSize();
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java
index 41f9a56..1f5d0b9 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java
@@ -132,12 +132,12 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public static boolean importerConfigured;
public static boolean importValidatorsObtainedAfterConfiguration;
-
+
public static void reset() {
importerConfigured = false;
importValidatorsObtainedAfterConfiguration = false;
}
-
+
@Override
public void initialize(Subject subject, EntityManager entityManager) {
}
@@ -150,13 +150,13 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public ExportingIterator<String> getExportingIterator() {
return new ExportingIterator<String>() {
boolean ran = false;
-
+
@Override
public boolean hasNext() {
if (ran) {
return false;
}
-
+
ran = true;
return true;
}
@@ -181,7 +181,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public String getNotes() {
return null;
}
-
+
};
}
@@ -189,7 +189,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public String getNotes() {
return null;
}
-
+
};
}
@@ -215,20 +215,20 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
@Override
public Set<EntityValidator<String>> getEntityValidators() {
EntityValidator<String> v = new EntityValidator<String>() {
-
+
@Override
public void validateExportedEntity(String entity) throws ValidationException {
}
-
+
@Override
public void initialize(Subject subject, EntityManager entityManager) {
}
};
-
+
if (importerConfigured) {
importValidatorsObtainedAfterConfiguration = true;
}
-
+
return Collections.singleton(v);
}
@@ -245,7 +245,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public String finishImport() throws Exception {
return null;
}
-
+
};
}
@@ -253,9 +253,9 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
public Set<ConsistencyValidator> getRequiredValidators() {
return Collections.emptySet();
}
-
+
}
-
+
private TestData testData;
//I just don't get why this can't be a @BeforeTest
@@ -270,9 +270,8 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
//add our new metric template that we are going to perform the tests with
testData.fakeType = new ResourceType(RESOURCE_TYPE_NAME, PLUGIN_NAME, ResourceCategory.PLATFORM, null);
- MeasurementDefinition mdef =
- new MeasurementDefinition(METRIC_NAME, MeasurementCategory.PERFORMANCE, MeasurementUnits.NONE,
- DataType.MEASUREMENT, true, 600000, DisplayType.SUMMARY);
+ MeasurementDefinition mdef = new MeasurementDefinition(METRIC_NAME, MeasurementCategory.PERFORMANCE,
+ MeasurementUnits.NONE, DataType.MEASUREMENT, true, 600000, DisplayType.SUMMARY);
testData.fakeType.addMetricDefinition(mdef);
em.persist(testData.fakeType);
@@ -310,43 +309,46 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
systemManager.loadSystemConfigurationCache();
testData.systemSettings = systemManager.getSystemConfiguration(freshUser());
-
+
if (createExport) {
export = synchronizationManager.exportAllSubsystems(freshUser());
}
}
private void tearDown() throws Exception {
- getTransactionManager().begin();
try {
- LookupUtil.getSystemManager().setSystemConfiguration(freshUser(), testData.systemSettings, true);
-
- EntityManager em = getEntityManager();
+ getTransactionManager().begin();
+ try {
+ LookupUtil.getSystemManager().setSystemConfiguration(freshUser(), testData.systemSettings, true);
- MeasurementSchedule sched =
- em.find(MeasurementSchedule.class, testData.fakePlatform.getSchedules().iterator().next().getId());
- em.remove(sched);
+ EntityManager em = getEntityManager();
- Resource attachedPlatform = em.find(Resource.class, testData.fakePlatform.getId());
- em.remove(attachedPlatform);
+ MeasurementSchedule sched = em.find(MeasurementSchedule.class, testData.fakePlatform.getSchedules()
+ .iterator().next().getId());
+ em.remove(sched);
- ResourceType attachedType = em.find(ResourceType.class, testData.fakeType.getId());
- em.remove(attachedType);
+ Resource attachedPlatform = em.find(Resource.class, testData.fakePlatform.getId());
+ em.remove(attachedPlatform);
- em.flush();
+ ResourceType attachedType = em.find(ResourceType.class, testData.fakeType.getId());
+ em.remove(attachedType);
- getTransactionManager().commit();
- } catch (Exception e) {
- getTransactionManager().rollback();
- throw e;
- }
+ em.flush();
- unprepareServerPluginService();
- testData.testServerPluginService.stopMasterPluginContainer();
+ getTransactionManager().commit();
+ } catch (Exception e) {
+ getTransactionManager().rollback();
+ throw e;
+ }
+ } finally {
+ unprepareServerPluginService();
+ //unnecessary, done by above method
+ //testData.testServerPluginService.stopMasterPluginContainer();
- export = null;
- testData = null;
- synchronizationManager = null;
+ export = null;
+ testData = null;
+ synchronizationManager = null;
+ }
}
public void testExport() throws Exception {
@@ -364,16 +366,16 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
try {
SystemManagerLocal systemManager = LookupUtil.getSystemManager();
- MeasurementDefinitionManagerLocal measurementDefinitionManager =
- LookupUtil.getMeasurementDefinitionManager();
+ MeasurementDefinitionManagerLocal measurementDefinitionManager = LookupUtil
+ .getMeasurementDefinitionManager();
Properties beforeSystemSettings = systemManager.getSystemConfiguration(freshUser());
MeasurementDefinitionCriteria criteria = new MeasurementDefinitionCriteria();
criteria.setPageControl(PageControl.getUnlimitedInstance());
criteria.fetchResourceType(true);
- List<MeasurementDefinition> beforeMeasurementDefinitions =
- measurementDefinitionManager.findMeasurementDefinitionsByCriteria(freshUser(), criteria);
+ List<MeasurementDefinition> beforeMeasurementDefinitions = measurementDefinitionManager
+ .findMeasurementDefinitionsByCriteria(freshUser(), criteria);
synchronizationManager.importAllSubsystems(freshUser(), export.getExportFile(), null);
@@ -381,16 +383,16 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
systemManager.loadSystemConfigurationCache();
Properties afterSystemSettings = systemManager.getSystemConfiguration(freshUser());
- List<MeasurementDefinition> afterMeasurementDefinitions =
- measurementDefinitionManager.findMeasurementDefinitionsByCriteria(freshUser(), criteria);
+ List<MeasurementDefinition> afterMeasurementDefinitions = measurementDefinitionManager
+ .findMeasurementDefinitionsByCriteria(freshUser(), criteria);
assertEquals("System settings unexpectedly differ", beforeSystemSettings, afterSystemSettings);
//make sure we don't fail on simple order differences, which are not important here..
- Set<MeasurementDefinition> beforeDefsToCheck =
- new HashSet<MeasurementDefinition>(beforeMeasurementDefinitions);
- Set<MeasurementDefinition> afterDefsToCheck =
- new HashSet<MeasurementDefinition>(afterMeasurementDefinitions);
+ Set<MeasurementDefinition> beforeDefsToCheck = new HashSet<MeasurementDefinition>(
+ beforeMeasurementDefinitions);
+ Set<MeasurementDefinition> afterDefsToCheck = new HashSet<MeasurementDefinition>(
+ afterMeasurementDefinitions);
assertEquals("Measurement definitions unexpectedly differ", beforeDefsToCheck, afterDefsToCheck);
} finally {
tearDown();
@@ -420,13 +422,13 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
assertEquals(settings.getProperty("CAM_BASE_URL"), "http://testing.domain:7080");
- MeasurementDefinitionManagerLocal measurementDefinitionManager =
- LookupUtil.getMeasurementDefinitionManager();
+ MeasurementDefinitionManagerLocal measurementDefinitionManager = LookupUtil
+ .getMeasurementDefinitionManager();
MeasurementDefinitionCriteria crit = new MeasurementDefinitionCriteria();
crit.addFilterResourceTypeName(RESOURCE_TYPE_NAME);
crit.addFilterName(METRIC_NAME);
- MeasurementDefinition mdef =
- measurementDefinitionManager.findMeasurementDefinitionsByCriteria(freshUser(), crit).get(0);
+ MeasurementDefinition mdef = measurementDefinitionManager.findMeasurementDefinitionsByCriteria(freshUser(),
+ crit).get(0);
assertEquals("The " + METRIC_NAME + " metric should have been updated with default interval of 30s",
Long.valueOf(30000), new Long(mdef.getDefaultInterval()));
@@ -445,9 +447,8 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
//now find the schedule for the measurement
MeasurementScheduleManagerLocal measurementScheduleManager = LookupUtil.getMeasurementScheduleManager();
- List<MeasurementSchedule> schedules =
- measurementScheduleManager.findSchedulesByResourceIdAndDefinitionIds(freshUser(), platformResourceId,
- new int[] { mdef.getId() });
+ List<MeasurementSchedule> schedules = measurementScheduleManager.findSchedulesByResourceIdAndDefinitionIds(
+ freshUser(), platformResourceId, new int[] { mdef.getId() });
assertEquals("Unexpected number of '" + METRIC_NAME + "' schedules found.", 1, schedules.size());
@@ -469,13 +470,13 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
String originalBaseUrl = settings.getProperty("CAM_BASE_URL");
- MeasurementDefinitionManagerLocal measurementDefinitionManager =
- LookupUtil.getMeasurementDefinitionManager();
+ MeasurementDefinitionManagerLocal measurementDefinitionManager = LookupUtil
+ .getMeasurementDefinitionManager();
MeasurementDefinitionCriteria crit = new MeasurementDefinitionCriteria();
crit.addFilterResourceTypeName(RESOURCE_TYPE_NAME);
crit.addFilterName(METRIC_NAME);
- MeasurementDefinition distroNameDef =
- measurementDefinitionManager.findMeasurementDefinitionsByCriteria(freshUser(), crit).get(0);
+ MeasurementDefinition distroNameDef = measurementDefinitionManager.findMeasurementDefinitionsByCriteria(
+ freshUser(), crit).get(0);
long originalInterval = distroNameDef.getDefaultInterval();
@@ -489,12 +490,12 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
//let's just use the default configs so that we don't apply the changes suggested in
//the changed default configs created above
- ImportConfiguration systemSettingsConfiguration =
- new ImportConfiguration(SystemSettingsSynchronizer.class.getName(), new SystemSettingsSynchronizer()
- .getImporter().getImportConfigurationDefinition().getDefaultTemplate().createConfiguration());
- ImportConfiguration metricTemplatesConfiguration =
- new ImportConfiguration(MetricTemplateSynchronizer.class.getName(), new MetricTemplateSynchronizer()
- .getImporter().getImportConfigurationDefinition().getDefaultTemplate().createConfiguration());
+ ImportConfiguration systemSettingsConfiguration = new ImportConfiguration(
+ SystemSettingsSynchronizer.class.getName(), new SystemSettingsSynchronizer().getImporter()
+ .getImportConfigurationDefinition().getDefaultTemplate().createConfiguration());
+ ImportConfiguration metricTemplatesConfiguration = new ImportConfiguration(
+ MetricTemplateSynchronizer.class.getName(), new MetricTemplateSynchronizer().getImporter()
+ .getImportConfigurationDefinition().getDefaultTemplate().createConfiguration());
try {
synchronizationManager.importAllSubsystems(freshUser(), exportData,
@@ -529,9 +530,8 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
//now find the schedule for the measurement
MeasurementScheduleManagerLocal measurementScheduleManager = LookupUtil.getMeasurementScheduleManager();
- List<MeasurementSchedule> schedules =
- measurementScheduleManager.findSchedulesByResourceIdAndDefinitionIds(freshUser(), platformResourceId,
- new int[] { distroNameDef.getId() });
+ List<MeasurementSchedule> schedules = measurementScheduleManager.findSchedulesByResourceIdAndDefinitionIds(
+ freshUser(), platformResourceId, new int[] { distroNameDef.getId() });
assertEquals("Unexpected number of '" + METRIC_NAME + "' schedules found.", 1, schedules.size());
@@ -549,43 +549,42 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
try {
String export = getExportData();
- Document xml =
- DocumentBuilderFactory.newInstance().newDocumentBuilder()
- .parse(new InputSource(new StringReader(export)));
-
+ Document xml = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new InputSource(new StringReader(export)));
+
Element unknownValidator = xml.createElement("validator");
unknownValidator.setAttribute(SynchronizationConstants.CLASS_ATTRIBUTE, "org.nothing.UnknownValidator");
-
+
xml.getDocumentElement().insertBefore(unknownValidator, xml.getDocumentElement().getFirstChild());
-
+
export = documentToString(xml);
-
+
InputStream exportStream = createCompressedStream(export);
-
+
synchronizationManager.importAllSubsystems(freshUser(), exportStream, null);
} finally {
tearDown();
}
}
- public void testImporterConfiguredBeforeValidatorsObtained() throws Exception {
+ public void testImporterConfiguredBeforeValidatorsObtained() throws Exception {
setup(false);
-
+
try {
ImportConfigurationCheckingSynchronizer.reset();
-
+
synchronizationManager.setSynchronizerFactory(new SynchronizerFactory() {
@Override
public Set<Synchronizer<?, ?>> getAllSynchronizers() {
- return Collections.<Synchronizer<?, ?>>singleton(new ImportConfigurationCheckingSynchronizer());
+ return Collections.<Synchronizer<?, ?>> singleton(new ImportConfigurationCheckingSynchronizer());
}
});
-
+
export = synchronizationManager.exportAllSubsystems(freshUser());
-
+
//and import it back again, so that we actually invoke the import validation
synchronizationManager.importAllSubsystems(freshUser(), export.getExportFile(), null);
-
+
assertTrue(ImportConfigurationCheckingSynchronizer.importerConfigured);
assertTrue(ImportConfigurationCheckingSynchronizer.importValidatorsObtainedAfterConfiguration);
} finally {
@@ -596,8 +595,8 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
}
private String getExportData() throws IOException {
- InputStreamReader str =
- new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(export.getExportFile())), "UTF-8");
+ InputStreamReader str = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(
+ export.getExportFile())), "UTF-8");
try {
char[] buf = new char[32768];
StringBuilder bld = new StringBuilder();
@@ -634,17 +633,14 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(SynchronizationConstants.createConfigurationExportNamespaceContext());
- XPathExpression systemSettingsConfigurationPath =
- xpath
- .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.SystemSettingsSynchronizer']/:default-configuration/ci:simple-property[@name='propertiesToImport']");
+ XPathExpression systemSettingsConfigurationPath = xpath
+ .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.SystemSettingsSynchronizer']/:default-configuration/ci:simple-property[@name='propertiesToImport']");
- XPathExpression baseUrlSettingPath =
- xpath
- .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.SystemSettingsSynchronizer']/:entity/:data/systemSettings/entry[@key='CAM_BASE_URL']");
+ XPathExpression baseUrlSettingPath = xpath
+ .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.SystemSettingsSynchronizer']/:entity/:data/systemSettings/entry[@key='CAM_BASE_URL']");
- Element systemSettingsConfiguration =
- (Element) systemSettingsConfigurationPath.evaluate(new InputSource(new StringReader(exportXML)),
- XPathConstants.NODE);
+ Element systemSettingsConfiguration = (Element) systemSettingsConfigurationPath.evaluate(new InputSource(
+ new StringReader(exportXML)), XPathConstants.NODE);
String propsToImport = systemSettingsConfiguration.getAttribute("value");
propsToImport += ", CAM_BASE_URL";
@@ -653,8 +649,8 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
exportXML = documentToString(systemSettingsConfiguration.getOwnerDocument());
- Element baseUrlSetting =
- (Element) baseUrlSettingPath.evaluate(new InputSource(new StringReader(exportXML)), XPathConstants.NODE);
+ Element baseUrlSetting = (Element) baseUrlSettingPath.evaluate(new InputSource(new StringReader(exportXML)),
+ XPathConstants.NODE);
baseUrlSetting.setTextContent("http://testing.domain:7080");
@@ -665,12 +661,11 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(SynchronizationConstants.createConfigurationExportNamespaceContext());
- XPathExpression overridesPath =
- xpath
- .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.MetricTemplateSynchronizer']/:default-configuration/ci:list-property[@name='metricUpdateOverrides']");
+ XPathExpression overridesPath = xpath
+ .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.MetricTemplateSynchronizer']/:default-configuration/ci:list-property[@name='metricUpdateOverrides']");
- Element overrides =
- (Element) overridesPath.evaluate(new InputSource(new StringReader(exportXML)), XPathConstants.NODE);
+ Element overrides = (Element) overridesPath.evaluate(new InputSource(new StringReader(exportXML)),
+ XPathConstants.NODE);
Document doc = overrides.getOwnerDocument();
@@ -691,13 +686,12 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
exportXML = documentToString(doc);
//now redefine the collection interval of the above metric so that we can see the change after the import
- XPathExpression distroNameMetricPath =
- xpath
- .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.MetricTemplateSynchronizer']/:entity/:data/metricTemplate[@metricName='"
- + METRIC_NAME + "']");
+ XPathExpression distroNameMetricPath = xpath
+ .compile("/:configuration-export/:entities[@id='org.rhq.enterprise.server.sync.MetricTemplateSynchronizer']/:entity/:data/metricTemplate[@metricName='"
+ + METRIC_NAME + "']");
- Element metric =
- (Element) distroNameMetricPath.evaluate(new InputSource(new StringReader(exportXML)), XPathConstants.NODE);
+ Element metric = (Element) distroNameMetricPath.evaluate(new InputSource(new StringReader(exportXML)),
+ XPathConstants.NODE);
doc = metric.getOwnerDocument();
@@ -730,7 +724,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
user = subjectManager.getOverlord();
return user;
}
-
+
private InputStream createCompressedStream(String exportData) throws UnsupportedEncodingException, IOException {
ByteArrayOutputStream compressed = new ByteArrayOutputStream();
OutputStreamWriter wrt = new OutputStreamWriter(new GZIPOutputStream(compressed), "UTF-8");
@@ -740,6 +734,6 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
wrt.close();
}
- return new ByteArrayInputStream(compressed.toByteArray());
+ return new ByteArrayInputStream(compressed.toByteArray());
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/system/SystemManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/system/SystemManagerBeanTest.java
index 8d27267..ede29a4 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/system/SystemManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/system/SystemManagerBeanTest.java
@@ -20,7 +20,7 @@ package org.rhq.enterprise.server.system;
import java.util.Properties;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -43,24 +43,25 @@ public class SystemManagerBeanTest extends AbstractEJB3Test {
@BeforeClass
public void setupServer() {
systemManager = LookupUtil.getSystemManager();
-
+ }
+
+ @BeforeMethod
+ public void beforeMethod() {
+ // do this each method so it doesn't expire
+ overlord = LookupUtil.getSubjectManager().getOverlord();
+
//we need this because the drift plugins are referenced from the system settings that we use in our tests
testServerPluginService = new TestServerPluginService();
prepareCustomServerPluginService(testServerPluginService);
testServerPluginService.startMasterPluginContainer();
}
- @AfterClass
+ @AfterMethod(alwaysRun = true)
public void tearDownServer() throws Exception {
unprepareServerPluginService();
- testServerPluginService.stopMasterPluginContainer();
- }
-
- @BeforeMethod
- public void beforeMethod() {
- overlord = LookupUtil.getSubjectManager().getOverlord();
}
+ @SuppressWarnings("deprecation")
public void testGetSystemConfiguration() {
assert null != systemManager.getSystemConfiguration(overlord);
}
@@ -88,7 +89,7 @@ public class SystemManagerBeanTest extends AbstractEJB3Test {
public void testVacuumAppdef() {
systemManager.vacuumAppdef(overlord);
}
-
+
@SuppressWarnings("deprecation")
public void testLegacySystemSettingsInCorrectFormat() throws Exception {
//some of the properties are represented differently
@@ -96,45 +97,45 @@ public class SystemManagerBeanTest extends AbstractEJB3Test {
//settings (and consequently database).
//These two still co-exist together in the codebase
//so let's make sure the values correspond to each other.
-
+
SystemSettings settings = systemManager.getSystemSettings(overlord);
Properties config = systemManager.getSystemConfiguration(overlord);
-
+
SystemSettings origSettings = new SystemSettings(settings);
-
+
try {
//let's make sure the values are the same
checkFormats(settings, config);
-
+
boolean currentJaasProvider = Boolean.valueOf(settings.get(SystemSetting.LDAP_BASED_JAAS_PROVIDER));
settings.put(SystemSetting.LDAP_BASED_JAAS_PROVIDER, Boolean.toString(!currentJaasProvider));
-
+
boolean currentUseSslForLdap = Boolean.valueOf(settings.get(SystemSetting.USE_SSL_FOR_LDAP));
settings.put(SystemSetting.USE_SSL_FOR_LDAP, Boolean.toString(!currentUseSslForLdap));
-
+
systemManager.setSystemSettings(overlord, settings);
-
+
settings = systemManager.getSystemSettings(overlord);
config = systemManager.getSystemConfiguration(overlord);
-
+
checkFormats(settings, config);
} finally {
systemManager.setSystemSettings(overlord, origSettings);
}
}
-
- private void checkFormats(SystemSettings settings, Properties config) {
+
+ private void checkFormats(SystemSettings settings, Properties config) {
assert settings.size() == config.size() : "The old and new style system settings differ in size";
-
- for(String name : config.stringPropertyNames()) {
+
+ for (String name : config.stringPropertyNames()) {
SystemSetting setting = SystemSetting.getByInternalName(name);
-
- String oldStyleValue = config.getProperty(name);
+
+ String oldStyleValue = config.getProperty(name);
String newStyleValue = settings.get(setting);
-
+
assert setting != null : "Could not find a system setting called '" + name + "'.";
-
- switch(setting) {
+
+ switch (setting) {
case USE_SSL_FOR_LDAP:
if (RHQConstants.LDAP_PROTOCOL_SECURED.equals(oldStyleValue)) {
assert Boolean.valueOf(newStyleValue) : "Secured LDAP protocol should be represented by a 'true' in new style settings.";
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
index 45bda40..566bc21 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/AbstractEJB3Test.java
@@ -72,6 +72,7 @@ public abstract class AbstractEJB3Test extends AssertJUnit {
private static EJB3StandaloneDeployer deployer;
private static Statistics stats;
+ @SuppressWarnings("unused")
private static long start; // see endTest() if you want to output this
private SchedulerService schedulerService;
private ServerPluginService serverPluginService;
@@ -257,6 +258,13 @@ public abstract class AbstractEJB3Test extends AssertJUnit {
return dummyJBossMBeanServer;
}
+ public void releaseJBossMBeanServer() {
+ if (dummyJBossMBeanServer != null) {
+ MBeanServerFactory.releaseMBeanServer(dummyJBossMBeanServer);
+ dummyJBossMBeanServer = null;
+ }
+ }
+
/**
* If you need to test round trips from server to agent and back, you first must install the server communications
* service that houses all the agent clients. Call this method and add your test agent services to the public fields
@@ -285,10 +293,18 @@ public abstract class AbstractEJB3Test extends AssertJUnit {
* {@link #prepareForTestAgents()}.
*/
public void unprepareForTestAgents() {
+ unprepareForTestAgents(false);
+ }
+
+ public void unprepareForTestAgents(boolean beanOnly) {
try {
- MBeanServer mbs = getJBossMBeanServer();
- if (mbs.isRegistered(ServerCommunicationsServiceMBean.OBJECT_NAME)) {
- mbs.unregisterMBean(ServerCommunicationsServiceMBean.OBJECT_NAME);
+ if (beanOnly) {
+ MBeanServer mbs = getJBossMBeanServer();
+ if (mbs.isRegistered(ServerCommunicationsServiceMBean.OBJECT_NAME)) {
+ mbs.unregisterMBean(ServerCommunicationsServiceMBean.OBJECT_NAME);
+ }
+ } else {
+ releaseJBossMBeanServer();
}
} catch (Exception e) {
throw new RuntimeException(e);
@@ -317,10 +333,25 @@ public abstract class AbstractEJB3Test extends AssertJUnit {
}
public void unprepareServerPluginService() throws Exception {
+ unprepareServerPluginService(false);
+ }
+
+ public void unprepareServerPluginService(boolean beanOnly) throws Exception {
if (serverPluginService != null) {
serverPluginService.stopMasterPluginContainer();
serverPluginService.stop();
- getJBossMBeanServer().unregisterMBean(ServerPluginService.OBJECT_NAME);
+ if (beanOnly) {
+ MBeanServer mbs = getJBossMBeanServer();
+ if (mbs.isRegistered(ServerPluginService.OBJECT_NAME)) {
+ getJBossMBeanServer().unregisterMBean(ServerPluginService.OBJECT_NAME);
+ }
+ if (mbs.isRegistered(ServerPluginServiceManagement.OBJECT_NAME)) {
+ getJBossMBeanServer().unregisterMBean(ServerPluginServiceManagement.OBJECT_NAME);
+ }
+
+ } else {
+ releaseJBossMBeanServer();
+ }
serverPluginService = null;
}
}
@@ -351,9 +382,21 @@ public abstract class AbstractEJB3Test extends AssertJUnit {
}
public void unprepareScheduler() throws Exception {
+ unprepareScheduler(false);
+ }
+
+ public void unprepareScheduler(boolean beanOnly) throws Exception {
if (schedulerService != null) {
schedulerService.stop();
- getJBossMBeanServer().unregisterMBean(SchedulerServiceMBean.SCHEDULER_MBEAN_NAME);
+ if (beanOnly) {
+ MBeanServer mbs = getJBossMBeanServer();
+ if (mbs.isRegistered(SchedulerServiceMBean.SCHEDULER_MBEAN_NAME)) {
+ getJBossMBeanServer().unregisterMBean(SchedulerServiceMBean.SCHEDULER_MBEAN_NAME);
+ }
+ } else {
+ releaseJBossMBeanServer();
+ }
+
schedulerService = null;
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/LargeGroupTestBase.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/LargeGroupTestBase.java
index 1fd16a9..cbafd46 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/LargeGroupTestBase.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/LargeGroupTestBase.java
@@ -25,8 +25,9 @@ import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.transaction.TransactionManager;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
@@ -86,20 +87,23 @@ public abstract class LargeGroupTestBase extends AbstractEJB3Test {
* Prepares things for the entire test class.
*/
@BeforeClass
- public void beforeClass() {
+ public void beforeClassBase() {
configurationManager = LookupUtil.getConfigurationManager();
resourceManager = LookupUtil.getResourceManager();
resourceGroupManager = LookupUtil.getResourceGroupManager();
subjectManager = LookupUtil.getSubjectManager();
+ }
+ @BeforeMethod
+ public void beforeMethodBase() throws Exception {
TestServerCommunicationsService agentServiceContainer = prepareForTestAgents();
setupMockAgentServices(agentServiceContainer);
prepareScheduler();
}
- @AfterClass(alwaysRun = true)
- public void afterClass() throws Exception {
+ @AfterMethod(alwaysRun = true)
+ public void afterMethodBase() throws Exception {
try {
unprepareForTestAgents();
} finally {
commit 875a2b7d7000ae8ccdb56d55ae89613e0ba010db
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jan 18 11:56:16 2012 -0500
[Bug 756184 - RFE: Drift UI needs better Template-Definition handling]
Add ability to expand rows in the drift template table. This gives users
the ability to see which drift definitions will be affected by changes to
a template. Or, to navigate to a derived template.
- Also:
- add explicit nav link to carousel
- fix nav issue DriftCarouselView.renderView which was too agressively
trying to nav to a detailed view
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LinkManager.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LinkManager.java
index ef99372..15f8331 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LinkManager.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/LinkManager.java
@@ -514,6 +514,11 @@ public class LinkManager {
return "#Resource/" + resourceId + "/Drift/Definitions";
}
+ public static String getDriftDefinitionCarouselLink(int resourceId, int driftDefId) {
+ return "#Resource/" + resourceId + "/Drift/Definitions/" + driftDefId + "/"
+ + DriftDefinitionsView.DetailView.Carousel.name();
+ }
+
public static String getDriftDefinitionEditLink(int resourceId, int driftDefId) {
return "#Resource/" + resourceId + "/Drift/Definitions/" + driftDefId + "/"
+ DriftDefinitionsView.DetailView.Edit.name();
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftCarouselView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftCarouselView.java
index d7477af..e29a63e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftCarouselView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftCarouselView.java
@@ -312,10 +312,10 @@ public class DriftCarouselView extends BookmarkableCarousel implements DetailsVi
categories.put(DriftCategory.FILE_REMOVED.name(), MSG.view_drift_category_fileRemoved());
LinkedHashMap<String, String> categoryIcons = new LinkedHashMap<String, String>(3);
categoryIcons.put(DriftCategory.FILE_ADDED.name(), ImageManager.getDriftCategoryIcon(DriftCategory.FILE_ADDED));
- categoryIcons.put(DriftCategory.FILE_CHANGED.name(), ImageManager
- .getDriftCategoryIcon(DriftCategory.FILE_CHANGED));
- categoryIcons.put(DriftCategory.FILE_REMOVED.name(), ImageManager
- .getDriftCategoryIcon(DriftCategory.FILE_REMOVED));
+ categoryIcons.put(DriftCategory.FILE_CHANGED.name(),
+ ImageManager.getDriftCategoryIcon(DriftCategory.FILE_CHANGED));
+ categoryIcons.put(DriftCategory.FILE_REMOVED.name(),
+ ImageManager.getDriftCategoryIcon(DriftCategory.FILE_REMOVED));
SelectItem categoryFilter = new EnumSelectItem(DriftDataSource.FILTER_CATEGORIES, MSG.common_title_category(),
DriftCategory.class, categories, categoryIcons);
@@ -354,10 +354,12 @@ public class DriftCarouselView extends BookmarkableCarousel implements DetailsVi
@Override
public void renderView(ViewPath viewPath) {
if (!viewPath.isEnd() && !viewPath.isNextEnd()) {
- this.useDriftDetailsView = !viewPath.isNextEnd() && "Drift".equals(viewPath.getNext().getPath());
+ String detail = viewPath.getNext().getPath();
+ if ("Drift".equals(detail) || "Snapshot".equals(detail)) {
+ this.useDriftDetailsView = !viewPath.isNextEnd() && "Drift".equals(viewPath.getNext().getPath());
+ super.renderView(viewPath);
+ }
}
-
- super.renderView(viewPath);
}
@Override
@@ -366,7 +368,7 @@ public class DriftCarouselView extends BookmarkableCarousel implements DetailsVi
return new DriftDetailsView(extendLocatorId("Drift"), id);
}
- return new DriftSnapshotView(extendLocatorId("Snapshot"), null, context.getResourceId(), driftDefId, Integer
- .valueOf(id), hasWriteAccess);
+ return new DriftSnapshotView(extendLocatorId("Snapshot"), null, context.getResourceId(), driftDefId,
+ Integer.valueOf(id), hasWriteAccess);
}
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
index bece740..99a4316 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionDataSource.java
@@ -43,10 +43,10 @@ import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.criteria.DriftDefinitionCriteria;
import org.rhq.core.domain.drift.DriftChangeSet;
import org.rhq.core.domain.drift.DriftComplianceStatus;
-import org.rhq.core.domain.drift.DriftDefinition;
-import org.rhq.core.domain.drift.DriftDefinitionComposite;
import org.rhq.core.domain.drift.DriftConfigurationDefinition.DriftHandlingMode;
+import org.rhq.core.domain.drift.DriftDefinition;
import org.rhq.core.domain.drift.DriftDefinition.BaseDirectory;
+import org.rhq.core.domain.drift.DriftDefinitionComposite;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
@@ -70,6 +70,7 @@ public class DriftDefinitionDataSource extends RPCDataSource<DriftDefinitionComp
public static final String ATTR_ENTITY = "object";
public static final String ATTR_ID = "id";
public static final String ATTR_NAME = "name";
+ public static final String ATTR_DESCRIPTION = "description";
public static final String ATTR_INTERVAL = "interval";
public static final String ATTR_DRIFT_HANDLING_MODE = "driftHandlingMode";
public static final String ATTR_BASE_DIR_STRING = "baseDirString";
@@ -418,12 +419,12 @@ public class DriftDefinitionDataSource extends RPCDataSource<DriftDefinitionComp
record.setAttribute(ATTR_IS_ENABLED, String.valueOf(def.isEnabled()));
record.setAttribute(ATTR_IS_ENABLED_ICON, ImageManager.getAvailabilityIcon(def.isEnabled()));
record.setAttribute(ATTR_COMPLIANCE, def.getComplianceStatus().ordinal());
- record.setAttribute(ATTR_COMPLIANCE_ICON, ImageManager
- .getAvailabilityIcon(def.getComplianceStatus() == DriftComplianceStatus.IN_COMPLIANCE));
+ record.setAttribute(ATTR_COMPLIANCE_ICON,
+ ImageManager.getAvailabilityIcon(def.getComplianceStatus() == DriftComplianceStatus.IN_COMPLIANCE));
// fixed value, just the edit icon
record.setAttribute(ATTR_EDIT, ImageManager.getEditIcon());
- record.setAttribute(ATTR_IS_PINNED, def.isPinned() ? ImageManager.getPinnedIcon() : ImageManager
- .getUnpinnedIcon());
+ record.setAttribute(ATTR_IS_PINNED,
+ def.isPinned() ? ImageManager.getPinnedIcon() : ImageManager.getUnpinnedIcon());
record.setAttribute(ATTR_ATTACHED, def.isAttached() ? MSG.common_val_yes() : MSG.common_val_no());
if (def.getTemplate() != null) {
record.setAttribute(ATTR_TEMPLATE, def.getTemplate().getName());
@@ -431,8 +432,8 @@ public class DriftDefinitionDataSource extends RPCDataSource<DriftDefinitionComp
record.setAttribute(ATTR_TEMPLATE, MSG.common_val_none());
}
- record.setAttribute(ATTR_CHANGE_SET_VERSION, (null != changeSet) ? String.valueOf(changeSet.getVersion()) : MSG
- .common_label_none());
+ record.setAttribute(ATTR_CHANGE_SET_VERSION,
+ (null != changeSet) ? String.valueOf(changeSet.getVersion()) : MSG.common_label_none());
record.setAttribute(ATTR_CHANGE_SET_CTIME, (null != changeSet) ? new Date(changeSet.getCtime()) : null);
return record;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionTemplatesView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionTemplatesView.java
index 3948f58..4ee1f42 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionTemplatesView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/drift/DriftDefinitionTemplatesView.java
@@ -22,30 +22,54 @@ package org.rhq.enterprise.gui.coregui.client.drift;
import java.util.ArrayList;
import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.smartgwt.client.data.DSRequest;
+import com.smartgwt.client.data.DSResponse;
+import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.SortSpecifier;
+import com.smartgwt.client.rpc.RPCResponse;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.Autofit;
+import com.smartgwt.client.types.ExpansionMode;
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.grid.CellFormatter;
+import com.smartgwt.client.widgets.grid.HoverCustomizer;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import org.rhq.core.domain.common.EntityContext;
+import org.rhq.core.domain.criteria.DriftDefinitionCriteria;
import org.rhq.core.domain.drift.DriftCategory;
+import org.rhq.core.domain.drift.DriftComplianceStatus;
+import org.rhq.core.domain.drift.DriftDefinition;
+import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
+import org.rhq.enterprise.gui.coregui.client.ImageManager;
+import org.rhq.enterprise.gui.coregui.client.LinkManager;
import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.admin.templates.DriftDefinitionTemplateTypeView;
import org.rhq.enterprise.gui.coregui.client.components.table.AbstractTableAction;
+import org.rhq.enterprise.gui.coregui.client.components.table.Table;
import org.rhq.enterprise.gui.coregui.client.components.table.TableActionEnablement;
import org.rhq.enterprise.gui.coregui.client.components.table.TableSection;
import org.rhq.enterprise.gui.coregui.client.drift.wizard.DriftAddDefinitionWizard;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.AncestryUtil;
+import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
+import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableListGrid;
+import org.rhq.enterprise.gui.coregui.client.util.selenium.SeleniumUtility;
/**
* A list view that displays a paginated table of {@link org.rhq.core.domain.drift.DriftDefinitionTemplate}s. It
* offers various options on the list like filtering (maybe) and sorting, add new/delete. Double-click drills
- * down to the detail view of the underlying Config. This view fully respects the user's authorization, and will not
- * allow actions on the templates unless the user is either the inventory manager or has MANAGE_DRIFT permission.
+ * down to the detail view of the underlying Config. Rows expand to reveal the drift definitions derived from
+ * the template. This view fully respects the user's authorization, and will not allow actions on the templates
+ * unless the user is either the inventory manager or has MANAGE_DRIFT permission.
*
* @author Jay Shaughnessy
*/
@@ -94,6 +118,11 @@ public class DriftDefinitionTemplatesView extends TableSection<DriftDefinitionTe
return this.dataSource;
}
+ @Override
+ protected LocatableListGrid createListGrid(String locatorId) {
+ return new DriftDefinitionTemplatesListGrid(locatorId);
+ }
+
public static String getTitle(ResourceType type) {
return DriftDefinitionTemplateTypeView.VIEW_ID.getTitle() + " [" + type.getName() + "]";
}
@@ -189,8 +218,8 @@ public class DriftDefinitionTemplatesView extends TableSection<DriftDefinitionTe
this.useSnapshotDetailsView = !viewPath.isNextEnd() && "Snapshot".equals(viewPath.getNext().getPath());
snapshotDriftDetailsId = null;
if (viewPath.viewsLeft() > 1) {
- snapshotDriftDetailsId = viewPath.getViewForIndex(viewPath.getCurrentIndex() + 2).getPath().substring(
- "0id_".length());
+ snapshotDriftDetailsId = viewPath.getViewForIndex(viewPath.getCurrentIndex() + 2).getPath()
+ .substring("0id_".length());
}
}
@@ -208,4 +237,244 @@ public class DriftDefinitionTemplatesView extends TableSection<DriftDefinitionTe
return new DriftDefinitionTemplateEditView(extendLocatorId("TemplateEdit"), driftTemplateId, hasWriteAccess);
}
+
+ /**
+ * The expandable list grid
+ */
+ private class DriftDefinitionTemplatesListGrid extends LocatableListGrid {
+
+ public DriftDefinitionTemplatesListGrid(String locatorId) {
+ super(locatorId);
+
+ setCanExpandRecords(true);
+ setCanExpandMultipleRecords(true);
+ setExpansionMode(ExpansionMode.RELATED);
+ }
+
+ @Override
+ protected Canvas getExpansionComponent(ListGridRecord record) {
+
+ int templateId = record.getAttributeAsInt(DriftDefinitionTemplateDataSource.ATTR_ID);
+ String templateName = record.getAttribute(DriftDefinitionTemplateDataSource.ATTR_NAME);
+
+ return new TemplateDefinitionsView(extendLocatorId(templateName), templateId);
+ }
+ }
+
+ /**
+ * The expanded row table view of definitions derived from the template
+ */
+ public class TemplateDefinitionsView extends Table<TemplateDefinitionsView.TemplateDefinitionsDataSource> {
+
+ private int templateId;
+ private TemplateDefinitionsDataSource dataSource;
+
+ public TemplateDefinitionsView(String locatorId, int templateId) {
+ super(locatorId, null, true);
+
+ this.templateId = templateId;
+
+ setShowFilterForm(false);
+ setShowHeader(false);
+ setShowFooter(false);
+
+ setWidth100();
+ setAutoHeight();
+ setOverflow(Overflow.VISIBLE);
+
+ setDataSource(getDataSource());
+ }
+
+ @Override
+ public TemplateDefinitionsDataSource getDataSource() {
+
+ if (null == dataSource) {
+ dataSource = new TemplateDefinitionsDataSource();
+ }
+
+ return dataSource;
+ }
+
+ @Override
+ protected LocatableListGrid createListGrid(String locatorId) {
+ return new TemplateDefinitionsListGrid(locatorId);
+ }
+
+ @Override
+ protected void configureTable() {
+ ArrayList<ListGridField> dataSourceFields = getDataSource().getListGridFields();
+ getListGrid().setFields(dataSourceFields.toArray(new ListGridField[dataSourceFields.size()]));
+
+ super.configureTable();
+ }
+
+ /**
+ * The definitions list grid
+ */
+ private class TemplateDefinitionsListGrid extends LocatableListGrid {
+
+ public TemplateDefinitionsListGrid(String locatorId) {
+ super(locatorId);
+
+ setDefaultHeight(10);
+ setAutoFitData(Autofit.VERTICAL);
+ }
+ }
+
+ public class TemplateDefinitionsDataSource extends RPCDataSource<DriftDefinition, DriftDefinitionCriteria> {
+
+ public TemplateDefinitionsDataSource() {
+ addDataSourceFields();
+ }
+
+ public ArrayList<ListGridField> getListGridFields() {
+ ArrayList<ListGridField> fields = new ArrayList<ListGridField>(6);
+
+ ListGridField nameField = new ListGridField(DriftDefinitionDataSource.ATTR_NAME,
+ MSG.common_title_name());
+ nameField.setCellFormatter(new CellFormatter() {
+ public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
+ Integer resourceId = listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID);
+ Integer driftDefId = listGridRecord.getAttributeAsInt("id");
+ String url = LinkManager.getDriftDefinitionCarouselLink(resourceId, driftDefId);
+ return SeleniumUtility.getLocatableHref(url, o.toString(), null);
+ }
+ });
+ fields.add(nameField);
+
+ ListGridField descriptionField = new ListGridField(DriftDefinitionDataSource.ATTR_DESCRIPTION,
+ MSG.common_title_description());
+ fields.add(descriptionField);
+
+ ListGridField attachedField = new ListGridField(DriftDefinitionDataSource.ATTR_ATTACHED,
+ MSG.view_drift_table_attached());
+ fields.add(attachedField);
+
+ ListGridField enabledField = new ListGridField(DriftDefinitionDataSource.ATTR_IS_ENABLED_ICON,
+ MSG.common_title_enabled());
+ enabledField.setType(ListGridFieldType.IMAGE);
+ enabledField.setAlign(Alignment.CENTER);
+ fields.add(enabledField);
+
+ ListGridField inComplianceField = new ListGridField(DriftDefinitionDataSource.ATTR_COMPLIANCE_ICON,
+ MSG.common_title_in_compliance());
+ inComplianceField.setType(ListGridFieldType.IMAGE);
+ inComplianceField.setAlign(Alignment.CENTER);
+ inComplianceField.setShowHover(true);
+ inComplianceField.setHoverCustomizer(new HoverCustomizer() {
+ @Override
+ public String hoverHTML(Object o, ListGridRecord record, int row, int column) {
+ int complianceCode = record.getAttributeAsInt(DriftDefinitionDataSource.ATTR_COMPLIANCE);
+ DriftComplianceStatus complianceStatus = DriftComplianceStatus.fromCode(complianceCode);
+ switch (complianceStatus) {
+ case OUT_OF_COMPLIANCE_NO_BASEDIR:
+ return MSG.view_drift_table_hover_outOfCompliance_noBaseDir();
+ case OUT_OF_COMPLIANCE_DRIFT:
+ return MSG.view_drift_table_hover_outOfCompliance_drift();
+ default:
+ return "";
+ }
+ }
+ });
+ fields.add(inComplianceField);
+
+ ListGridField resourceNameField = new ListGridField(AncestryUtil.RESOURCE_NAME,
+ MSG.common_title_resource());
+ resourceNameField.setCellFormatter(new CellFormatter() {
+ public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
+ Integer resourceId = listGridRecord.getAttributeAsInt(AncestryUtil.RESOURCE_ID);
+ String url = LinkManager.getResourceLink(resourceId);
+ return SeleniumUtility.getLocatableHref(url, o.toString(), null);
+ }
+ });
+ resourceNameField.setShowHover(true);
+ resourceNameField.setHoverCustomizer(new HoverCustomizer() {
+ public String hoverHTML(Object value, ListGridRecord listGridRecord, int rowNum, int colNum) {
+ return AncestryUtil.getResourceHoverHTML(listGridRecord, 0);
+ }
+ });
+ fields.add(resourceNameField);
+
+ ListGridField ancestryField = AncestryUtil.setupAncestryListGridField();
+ fields.add(ancestryField);
+
+ nameField.setWidth("15%");
+ descriptionField.setWidth("25%");
+ attachedField.setWidth(70);
+ enabledField.setWidth(60);
+ inComplianceField.setWidth(100);
+ resourceNameField.setWidth("20%");
+ ancestryField.setWidth("*");
+
+ return fields;
+ }
+
+ @Override
+ protected void executeFetch(final DSRequest request, final DSResponse response,
+ DriftDefinitionCriteria criteria) {
+
+ GWTServiceLookup.getDriftService().findDriftDefinitionsByCriteria(criteria,
+ new AsyncCallback<PageList<DriftDefinition>>() {
+
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_drift_failure_load(), caught);
+ response.setStatus(RPCResponse.STATUS_FAILURE);
+ processResponse(request.getRequestId(), response);
+ }
+
+ public void onSuccess(final PageList<DriftDefinition> result) {
+ response.setData(buildRecords(result));
+ response.setTotalRows(result.getTotalSize());
+ processResponse(request.getRequestId(), response);
+ }
+ });
+ }
+
+ @Override
+ protected DriftDefinitionCriteria getFetchCriteria(DSRequest request) {
+
+ DriftDefinitionCriteria criteria = new DriftDefinitionCriteria();
+ criteria.addFilterTemplateId(templateId);
+ criteria.fetchResource(true);
+
+ return criteria;
+ }
+
+ @Override
+ public DriftDefinition copyValues(Record from) {
+ return null;
+ }
+
+ @Override
+ public ListGridRecord copyValues(DriftDefinition from) {
+ ListGridRecord record = new ListGridRecord();
+
+ record.setAttribute(DriftDefinitionDataSource.ATTR_ID, from.getId());
+
+ record.setAttribute(DriftDefinitionDataSource.ATTR_NAME, from.getName());
+ record.setAttribute(DriftDefinitionDataSource.ATTR_DESCRIPTION, from.getDescription());
+
+ record.setAttribute(DriftDefinitionDataSource.ATTR_IS_ENABLED, String.valueOf(from.isEnabled()));
+ record.setAttribute(DriftDefinitionDataSource.ATTR_IS_ENABLED_ICON,
+ ImageManager.getAvailabilityIcon(from.isEnabled()));
+ record.setAttribute(DriftDefinitionDataSource.ATTR_COMPLIANCE, from.getComplianceStatus().ordinal());
+ record
+ .setAttribute(DriftDefinitionDataSource.ATTR_COMPLIANCE_ICON, ImageManager.getAvailabilityIcon(from
+ .getComplianceStatus() == DriftComplianceStatus.IN_COMPLIANCE));
+
+ record.setAttribute(DriftDefinitionDataSource.ATTR_ATTACHED, from.isAttached() ? MSG.common_val_yes()
+ : MSG.common_val_no());
+
+ // for ancestry handling
+ Resource resource = from.getResource();
+ record.setAttribute(AncestryUtil.RESOURCE_ID, resource.getId());
+ record.setAttribute(AncestryUtil.RESOURCE_NAME, resource.getName());
+ record.setAttribute(AncestryUtil.RESOURCE_ANCESTRY, resource.getAncestry());
+ record.setAttribute(AncestryUtil.RESOURCE_TYPE_ID, resource.getResourceType().getId());
+
+ return record;
+ }
+ }
+ }
+
}
commit 70d4bb0592c57d36ed61112cd03aaeea2377b739
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Jan 19 13:11:31 2012 +0100
BZ 772726 - Disable tests by default for now
diff --git a/modules/plugins/oracle/pom.xml b/modules/plugins/oracle/pom.xml
index 5b08a19..9a1f93e 100644
--- a/modules/plugins/oracle/pom.xml
+++ b/modules/plugins/oracle/pom.xml
@@ -28,6 +28,24 @@
<profiles>
<profile>
+ <id>default</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <skipTests>true</skipTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+
+ <profile>
<id>ojdbc-driver</id>
<activation>
<property>
commit 2b63ea39a293e4b60552ce2fbc9ccc9cfb3eaefd
Author: Elias Ross <genman(a)noderunner.net>
Date: Thu Jan 19 11:06:27 2012 +0100
BZ 772726 - Oracle Plugin. Bugfixes feature counting active and total connections per user.
diff --git a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
index d8906f7..34df7bd 100644
--- a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
+++ b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableComponent.java
@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
@@ -73,7 +74,9 @@ public class CustomTableComponent implements DatabaseComponent<DatabaseComponent
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception {
- String query = this.context.getPluginConfiguration().getSimpleValue("metricQuery", null);
+
+ Configuration conf = this.context.getPluginConfiguration();
+ String query = conf.getSimpleValue("metricQuery", null);
if (query == null) {
ResourceType type = this.context.getResourceType();
@@ -88,10 +91,10 @@ public class CustomTableComponent implements DatabaseComponent<DatabaseComponent
return;
}
- query = CustomTableRowDiscoveryComponent.formatMessage(query, this.context.getPluginConfiguration()
- .getSimpleValue("key", null));
+ query = CustomTableRowDiscoveryComponent.formatMessage(query, conf.getSimpleValue("key", null));
+
+ Map<String, Double> values = DatabaseQueryUtility.getNumericQueryValueMap(this, query);
- Map<String, Double> values = DatabaseQueryUtility.getNumericQueryValues(this, query);
for (MeasurementScheduleRequest request : metrics) {
Double value = values.get(request.getName());
if (value != null) {
diff --git a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
index 630b575..56d9ddd 100644
--- a/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
+++ b/modules/plugins/database/src/main/java/org/rhq/plugins/database/CustomTableRowDiscoveryComponent.java
@@ -27,6 +27,8 @@ import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
@@ -43,17 +45,21 @@ import org.rhq.core.util.jdbc.JDBCUtil;
* @author Greg Hinkle
*/
public class CustomTableRowDiscoveryComponent implements ResourceDiscoveryComponent<DatabaseComponent<?>> {
+
+ private final Log log = LogFactory.getLog(getClass());
+
public Set<DiscoveredResourceDetails> discoverResources(
ResourceDiscoveryContext<DatabaseComponent<?>> resourceDiscoveryContext)
throws InvalidPluginConfigurationException, Exception {
Statement statement = null;
ResultSet resultSet = null;
+
+ Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration();
+ String table = config.getSimpleValue("table", null);
+ String keyColumn = config.getSimpleValue("keyColumn", null);
try {
Connection conn = resourceDiscoveryContext.getParentResourceComponent().getConnection();
- Configuration config = resourceDiscoveryContext.getDefaultPluginConfiguration();
- String table = config.getSimpleValue("table", null);
- String keyColumn = config.getSimpleValue("keyColumn", null);
String resourceName = config.getSimpleValue("name", null);
String resourceDescription = config.getSimpleValue("description", "");
@@ -82,7 +88,7 @@ public class CustomTableRowDiscoveryComponent implements ResourceDiscoveryCompon
return found;
} catch (SQLException e) {
- // table not found, don't inventory
+ log.debug("table " + table + " column " + keyColumn, e);
} finally {
JDBCUtil.safeClose(resultSet);
JDBCUtil.safeClose(statement);
@@ -95,10 +101,13 @@ public class CustomTableRowDiscoveryComponent implements ResourceDiscoveryCompon
* Format a message with {<key>} formatted replacement keys.
*
* @param message the message to format
+ * @param key to replace; if null returns the message as-is
*
* @return the formatted text with variables replaced
*/
public static String formatMessage(String message, String key) {
+ if (key == null)
+ return message;
key = Matcher.quoteReplacement(key);
message = message.replaceAll("\\{key\\}", key);
return message;
diff --git a/modules/plugins/oracle/pom.xml b/modules/plugins/oracle/pom.xml
index 4b52d63..5b08a19 100644
--- a/modules/plugins/oracle/pom.xml
+++ b/modules/plugins/oracle/pom.xml
@@ -68,102 +68,6 @@
</profile>
<profile>
- <id>integration-tests</id>
- <activation>
- <property>
- <name>maven.test.skip</name>
- <value>!true</value>
- </property>
- </activation>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <phase>pre-integration-test</phase>
- <configuration>
- <tasks>
- <echo>Setting up plugin dependencies for ${project.artifactId}-${project.version}.jar...</echo>
- <property name="settings.localRepository" location="${user.home}/.m2/repository" />
- <mkdir dir="target/itest" />
- <mkdir dir="target/itest/plugins" />
- <mkdir dir="target/itest/lib" />
- <copy toDir="target/itest/plugins" flatten="true">
- <fileset dir="${settings.localRepository}/">
- <include name="org/rhq/rhq-platform-plugin/${project.version}/rhq-platform-plugin-${project.version}.jar" />
- <include name="org/rhq/rhq-database-plugin/${project.version}/rhq-database-plugin-${project.version}.jar" />
- </fileset>
- <fileset dir="${project.build.directory}">
- <include name="${project.artifactId}-${project.version}.jar" />
- </fileset>
- </copy>
- <unzip dest="target/itest/lib">
- <fileset dir="${settings.localRepository}/org/hyperic/sigar-dist/${sigar.version}" includes="*.zip" />
- <patternset>
- <include name="**/lib/sigar.jar" />
- <include name="**/lib/bcel*.jar" />
- <include name="**/lib/*.so" />
- <include name="**/lib/*.sl" />
- <include name="**/lib/*.dll" />
- <include name="**/lib/*.dylib" />
- </patternset>
- </unzip>
- <move todir="target/itest/lib" flatten="true">
- <fileset dir="target/itest/lib">
- <include name="**/lib/*" />
- </fileset>
- </move>
- <delete dir="target/itest/lib/hyperic-sigar-${sigar.version}" />
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- Integration testing voodoo to load and test this plugin with its plugin dependencies -->
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <skip>true</skip>
- </configuration>
- <executions>
- <execution>
- <id>surefire-it</id>
- <phase>integration-test</phase>
- <goals>
- <goal>test</goal>
- </goals>
- <configuration>
- <skip>${maven.test.skip}</skip>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <useSystemClassLoader>false</useSystemClassLoader>
- <argLine>-Dorg.hyperic.sigar.path=${basedir}/target/itest/lib</argLine>
- <!--<argLine>-Dorg.hyperic.sigar.path=${basedir}/target/itest/lib -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine>-->
- <systemProperties>
- <property>
- <name>project.artifactId</name>
- <value>${project.artifactId}</value>
- </property>
- <property>
- <name>project.version</name>
- <value>${project.version}</value>
- </property>
- </systemProperties>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
- </build>
- </profile>
-
- <profile>
<id>dev</id>
<properties>
@@ -176,22 +80,22 @@
<plugins>
<plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
<execution>
<id>deploy</id>
<phase>compile</phase>
<configuration>
- <tasks>
- <mkdir dir="${rhq.deploymentDir}" />
- <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
- <echo>*** Updating ${deployment.file}...</echo>
- <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" />
- </tasks>
+ <tasks>
+ <mkdir dir="${rhq.deploymentDir}" />
+ <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
+ <echo>*** Updating ${deployment.file}...</echo>
+ <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" />
+ </tasks>
</configuration>
<goals>
- <goal>run</goal>
+ <goal>run</goal>
</goals>
</execution>
@@ -199,18 +103,20 @@
<id>deploy-jar-meta-inf</id>
<phase>package</phase>
<configuration>
- <tasks>
- <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
- <echo>*** Updating META-INF dir in ${deployment.file}...</echo>
- <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}">
- <patternset><include name="META-INF/**" /></patternset>
- </unjar>
- <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" update="true">
- </jar>
- </tasks>
+ <tasks>
+ <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
+ <echo>*** Updating META-INF dir in ${deployment.file}...</echo>
+ <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}">
+ <patternset>
+ <include name="META-INF/**" />
+ </patternset>
+ </unjar>
+ <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" update="true">
+ </jar>
+ </tasks>
</configuration>
<goals>
- <goal>run</goal>
+ <goal>run</goal>
</goals>
</execution>
@@ -218,107 +124,151 @@
<id>undeploy</id>
<phase>clean</phase>
<configuration>
- <tasks>
- <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
- <echo>*** Deleting ${deployment.file}...</echo>
- <delete file="${deployment.file}" />
- </tasks>
+ <tasks>
+ <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" />
+ <echo>*** Deleting ${deployment.file}...</echo>
+ <delete file="${deployment.file}" />
+ </tasks>
</configuration>
<goals>
- <goal>run</goal>
+ <goal>run</goal>
</goals>
</execution>
- </executions>
+ </executions>
</plugin>
</plugins>
</build>
</profile>
- <profile>
- <id>cobertura-plugins</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <dependencies>
- <dependency>
- <groupId>net.sourceforge.cobertura</groupId>
- <artifactId>cobertura</artifactId>
- <version>${cobertura.version}</version>
- </dependency>
- </dependencies>
- <executions>
- <execution>
- <id>cobertura-instrument</id>
- <phase>pre-integration-test</phase>
- <configuration>
- <tasks>
+
+ <profile>
+ <id>oracle-test</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>ojdbc5</artifactId>
+ <version>${ojdbc5.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemProperties>
+ <property>
+ <name>oracle.url</name>
+ <value>${oracle.url}</value>
+ </property>
+ <property>
+ <name>oracle.userid</name>
+ <value>${oracle.userid}</value>
+ </property>
+ <property>
+ <name>oracle.password</name>
+ <value>${oracle.password}</value>
+ </property>
+ </systemProperties>
+ <!-- The below is required for tests to run against Oracle.
+ <additionalClasspathElements>
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ -->
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+
+ <profile>
+ <id>cobertura-plugins</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>net.sourceforge.cobertura</groupId>
+ <artifactId>cobertura</artifactId>
+ <version>${cobertura.version}</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <id>cobertura-instrument</id>
+ <phase>pre-integration-test</phase>
+ <configuration>
+ <tasks>
<!-- prepare directory structure for cobertura-->
- <mkdir dir="target/cobertura" />
- <mkdir dir="target/cobertura/backup" />
+ <mkdir dir="target/cobertura" />
+ <mkdir dir="target/cobertura/backup" />
<!-- backup all classes so that we can instrument the original classes-->
- <copy toDir="target/cobertura/backup" verbose="true" overwrite="true">
- <fileset dir="target/classes">
- <include name="**/*.class" />
- </fileset>
- </copy>
+ <copy toDir="target/cobertura/backup" verbose="true" overwrite="true">
+ <fileset dir="target/classes">
+ <include name="**/*.class" />
+ </fileset>
+ </copy>
<!-- create a properties file and save there location of cobertura data file-->
- <touch file="target/classes/cobertura.properties" />
- <echo file="target/classes/cobertura.properties">net.sourceforge.cobertura.datafile=${project.build.directory}/cobertura/cobertura.ser</echo>
- <taskdef classpathref="maven.plugin.classpath" resource="tasks.properties" />
+ <touch file="target/classes/cobertura.properties" />
+ <echo file="target/classes/cobertura.properties">net.sourceforge.cobertura.datafile=${project.build.directory}/cobertura/cobertura.ser</echo>
+ <taskdef classpathref="maven.plugin.classpath" resource="tasks.properties" />
<!-- instrument all classes in target/classes directory -->
- <cobertura-instrument datafile="${project.build.directory}/cobertura/cobertura.ser" todir="${project.build.directory}/classes">
- <fileset dir="${project.build.directory}/classes">
- <include name="**/*.class" />
- </fileset>
- </cobertura-instrument>
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- <execution>
- <id>cobertura-report</id>
- <phase>post-integration-test</phase>
- <configuration>
- <tasks>
- <taskdef classpathref="maven.plugin.classpath" resource="tasks.properties" />
+ <cobertura-instrument datafile="${project.build.directory}/cobertura/cobertura.ser" todir="${project.build.directory}/classes">
+ <fileset dir="${project.build.directory}/classes">
+ <include name="**/*.class" />
+ </fileset>
+ </cobertura-instrument>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>cobertura-report</id>
+ <phase>post-integration-test</phase>
+ <configuration>
+ <tasks>
+ <taskdef classpathref="maven.plugin.classpath" resource="tasks.properties" />
<!-- prepare directory structure for cobertura-->
- <mkdir dir="target/cobertura" />
- <mkdir dir="target/site/cobertura" />
+ <mkdir dir="target/cobertura" />
+ <mkdir dir="target/site/cobertura" />
<!-- restore classes from backup folder to classes folder -->
- <copy toDir="target/classes" verbose="true" overwrite="true">
- <fileset dir="target/cobertura/backup">
- <include name="**/*.class" />
- </fileset>
- </copy>
+ <copy toDir="target/classes" verbose="true" overwrite="true">
+ <fileset dir="target/cobertura/backup">
+ <include name="**/*.class" />
+ </fileset>
+ </copy>
<!-- delete backup folder-->
- <delete dir="target/cobertura/backup" />
+ <delete dir="target/cobertura/backup" />
<!-- create a code coverage report -->
- <cobertura-report format="html" datafile="${project.build.directory}/cobertura/cobertura.ser" destdir="${project.build.directory}/site/cobertura">
- <fileset dir="${basedir}/src/main/java">
- <include name="**/*.java" />
- </fileset>
- </cobertura-report>
+ <cobertura-report format="html" datafile="${project.build.directory}/cobertura/cobertura.ser" destdir="${project.build.directory}/site/cobertura">
+ <fileset dir="${basedir}/src/main/java">
+ <include name="**/*.java" />
+ </fileset>
+ </cobertura-report>
<!-- delete cobertura.properties file -->
- <delete file="target/classes/cobertura.properties" />
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </profile>
+ <delete file="target/classes/cobertura.properties" />
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
</project>
diff --git a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
index 2686440..3d70eef 100644
--- a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
+++ b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleServerComponent.java
@@ -34,6 +34,7 @@ import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
import org.rhq.core.pluginapi.inventory.ResourceContext;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
+import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.plugins.database.DatabaseComponent;
import org.rhq.plugins.database.DatabaseQueryUtility;
@@ -47,23 +48,21 @@ public class OracleServerComponent implements DatabaseComponent, MeasurementFace
private ResourceContext resourceContext;
+ private boolean started;
+
public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception {
this.resourceContext = resourceContext;
this.connection = buildConnection(resourceContext.getPluginConfiguration());
+ this.started = true;
}
public void stop() {
- if (this.connection != null) {
- try {
- this.connection.close();
- } catch (SQLException e) {
- LOG.debug("Unable to close oracle connection", e);
- }
- }
+ removeConnection();
+ this.started = false;
}
public AvailabilityType getAvailability() {
- if (getConnection() != null) {
+ if (started && getConnection() != null) {
return AvailabilityType.UP;
} else {
return AvailabilityType.DOWN;
@@ -88,18 +87,18 @@ public class OracleServerComponent implements DatabaseComponent, MeasurementFace
}
public Connection getConnection() {
- if (this.connection == null) {
- try {
+ try {
+ if (this.connection == null || connection.isClosed()) {
this.connection = buildConnection(this.resourceContext.getPluginConfiguration());
- } catch (SQLException e) {
- LOG.info("Unable to create oracle connection", e);
}
+ } catch (SQLException e) {
+ LOG.info("Unable to create oracle connection", e);
}
-
return this.connection;
}
public void removeConnection() {
+ JDBCUtil.safeClose(connection);
this.connection = null;
}
diff --git a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
index da386d1..49999fd 100644
--- a/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
+++ b/modules/plugins/oracle/src/main/java/org/rhq/plugins/oracle/OracleUserComponent.java
@@ -21,8 +21,12 @@ package org.rhq.plugins.oracle;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementReport;
@@ -36,18 +40,27 @@ import org.rhq.plugins.database.DatabaseQueryUtility;
* @author Greg Hinkle
*/
public class OracleUserComponent extends AbstractDatabaseComponent implements MeasurementFacet {
+
+ private static final String SQL_USER = "SELECT COUNT(*) FROM DBA_USERS WHERE username = ?";
+ private static final String SESSIONS =
+ "SELECT SUM(DECODE(Status, 'ACTIVE', 1, 0)) active, COUNT(1) connections " +
+ "FROM V$SESSION where username = ?";
+
+
+ private static Log log = LogFactory.getLog(OracleUserComponent.class);
+
public AvailabilityType getAvailability() {
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
- statement = getConnection().prepareStatement("SELECT COUNT(*) FROM DBA_USERS WHERE username = ?");
+ statement = getConnection().prepareStatement(SQL_USER);
statement.setString(1, this.resourceContext.getResourceKey());
resultSet = statement.executeQuery();
if (resultSet.next() && (resultSet.getInt(1) == 1)) {
return AvailabilityType.UP;
}
} catch (SQLException e) {
- // Problems ? Mark the resource as down
+ log.debug("unable to query", e);
} finally {
JDBCUtil.safeClose(statement, resultSet);
}
@@ -56,15 +69,12 @@ public class OracleUserComponent extends AbstractDatabaseComponent implements Me
}
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception {
+ Map<String, Double> values = DatabaseQueryUtility.getNumericQueryValues(this, SESSIONS,
+ this.resourceContext.getResourceKey());
for (MeasurementScheduleRequest request : metrics) {
- if (request.getName().equals("sessions")) {
- Map<String, Double> values = DatabaseQueryUtility
- .getNumericQueryValues(this, "SELECT COUNT(*) as activeConnections FROM V$SESSION WHERE username = ?",
- this.resourceContext.getResourceKey());
- Double sessions = values.get("count");
- if (sessions != null) {
- report.addData(new MeasurementDataNumeric(request, sessions));
- }
+ Double d = values.get(request.getName().toUpperCase(Locale.US));
+ if (d != null) {
+ report.addData(new MeasurementDataNumeric(request, d));
}
}
}
diff --git a/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
index fea33f1..27c9033 100644
--- a/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/oracle/src/main/resources/META-INF/rhq-plugin.xml
@@ -46,7 +46,7 @@
<metric property="session stored procedure space"/>
<metric property="CPU used when call started" displayType="summary"/>
<metric property="CPU used by this session"/>
- <metric property="DB time"/>
+ <metric property="DB time" measurementType="trendsup"/>
<metric property="cluster wait time"/>
<metric property="concurrency wait time"/>
<metric property="application wait time" />
@@ -385,12 +385,12 @@
<service name="Oracle Detailed Statistics"
discovery="org.rhq.plugins.database.CustomTableDiscoveryComponent"
class="org.rhq.plugins.database.CustomTableComponent">
-
+
<plugin-configuration>
<c:simple-property name="table" default="V$SYSMETRIC"/>
<c:simple-property name="metricQuery" default="SELECT metric_name, value from V$SYSMETRIC"/>
- <c:simple-property name="name" default="Oracle 10g Advanced Statistics"/>
- <c:simple-property name="description" default="Detailed Oracle 10g Statistics"/>
+ <c:simple-property name="name" default="Oracle Advanced Statistics"/>
+ <c:simple-property name="description" default="Detailed Oracle Statistics"/>
</plugin-configuration>
<metric property="Buffer Cache Hit Ratio" units="percentage"/>
@@ -578,16 +578,17 @@
<plugin-configuration>
<c:simple-property name="table" default="DBA_USERS"/>
- <c:simple-property name="metricQuery" default="SELECT * FROM DBA_USERS"/>
+ <c:simple-property name="metricQuery" default="SELECT {key} FROM DBA_USERS"/>
<c:simple-property name="keyColumn" default="username"/>
<c:simple-property name="name" default="{key}"/>
<c:simple-property name="description" default="Oracle User"/>
</plugin-configuration>
- <metric property="activeConnections" displayName="Active Connections" displayType="summary"/>
+ <metric property="connections" displayName="Total Connections" displayType="summary"/>
+ <metric property="active" displayName="Active Connections" displayType="summary"/>
</service>
</server>
-</plugin>
\ No newline at end of file
+</plugin>
diff --git a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
new file mode 100644
index 0000000..8eeed0c
--- /dev/null
+++ b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/ComponentTest.java
@@ -0,0 +1,281 @@
+package org.rhq.plugins.oracle;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.fail;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.rhq.core.clientapi.agent.metadata.PluginMetadataManager;
+import org.rhq.core.clientapi.descriptor.AgentPluginDescriptorUtil;
+import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.measurement.AvailabilityType;
+import org.rhq.core.domain.measurement.MeasurementDataNumeric;
+import org.rhq.core.domain.measurement.MeasurementDefinition;
+import org.rhq.core.domain.measurement.MeasurementReport;
+import org.rhq.core.domain.measurement.MeasurementSchedule;
+import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
+import org.rhq.core.domain.resource.Resource;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.pc.PluginContainer;
+import org.rhq.core.pc.PluginContainerConfiguration;
+import org.rhq.core.pc.content.ContentContextImpl;
+import org.rhq.core.pc.event.EventContextImpl;
+import org.rhq.core.pc.event.EventManager;
+import org.rhq.core.pc.inventory.InventoryManager;
+import org.rhq.core.pc.inventory.ResourceContainer;
+import org.rhq.core.pc.operation.OperationContextImpl;
+import org.rhq.core.pc.upgrade.plugins.multi.base.NothingDiscoveringDiscoveryComponent;
+import org.rhq.core.pluginapi.content.ContentContext;
+import org.rhq.core.pluginapi.event.EventContext;
+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException;
+import org.rhq.core.pluginapi.inventory.PluginContainerDeployment;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
+import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.core.pluginapi.measurement.MeasurementFacet;
+import org.rhq.core.pluginapi.operation.OperationContext;
+import org.rhq.core.system.SystemInfo;
+import org.rhq.core.system.SystemInfoFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * Base class for RHQ Component Testing.
+ * Initializes a plugin configuration.
+ */
+public abstract class ComponentTest {
+
+ static {
+ ResourceComponent.class.toString();
+ }
+
+ protected final Log log = LogFactory.getLog(getClass());
+ private static File temp = new File(System.getProperty("java.io.tmpdir"));
+
+ /**
+ * Associates a resource component with a resource.
+ */
+ protected Map<ResourceComponent, Resource> components = new LinkedHashMap<ResourceComponent, Resource>();
+
+ protected EventManager eventManager;
+ protected ResourceDiscoveryContext resourceDiscoveryContext;
+ protected PluginContainer pluginContainer = PluginContainer.getInstance();
+ protected SystemInfo systemInfo = SystemInfoFactory.createSystemInfo();
+
+ // TODO
+
+ PluginMetadataManager pmm = new PluginMetadataManager();
+ ResourceDiscoveryComponent resourceDiscoveryComponent = new NothingDiscoveringDiscoveryComponent();
+ File temporaryDirectory = temp;
+ File dataDirectory = temp;
+ String pluginContainerName = "rhq";
+ OperationContext operationContext = new OperationContextImpl(0);
+ ContentContext contentContext = new ContentContextImpl(0);
+ Executor availCollectorThreadPool = Executors.newCachedThreadPool();
+ PluginContainerDeployment pluginContainerDeployment = null;
+
+ /**
+ * Constructs a new component test.
+ */
+ protected ComponentTest() {
+ // Speed up propagation of events by adjusting delay/period to 1 second
+ PluginContainerConfiguration pcc = new PluginContainerConfiguration();
+ pcc.setEventSenderInitialDelay(1);
+ pcc.setEventSenderPeriod(1);
+
+ pluginContainer.setConfiguration(pcc);
+ pluginContainer.initialize();
+ eventManager = pluginContainer.getEventManager();
+ }
+
+ /**
+ * Initializes all components in the system; using auto-discovery where possible.
+ */
+ @BeforeTest
+ protected void before() throws Exception {
+
+ InputStream is = getClass().getResourceAsStream("/META-INF/rhq-plugin.xml");
+ PluginDescriptor pd = AgentPluginDescriptorUtil.parsePluginDescriptor(is);
+ ResourceType platformType = pmm.addTestPlatformType();
+ Set<ResourceType> rts = pmm.loadPlugin(pd);
+ for (ResourceType resourceType : pmm.loadPlugin(pd)) {
+ String componentType = pmm.getComponentClass(resourceType);
+ ResourceComponent component = (ResourceComponent) Class.forName(componentType).newInstance();
+ Configuration configuration = resourceType.getPluginConfigurationDefinition().getDefaultTemplate().createConfiguration();
+
+ setConfiguration(configuration, resourceType);
+
+ Resource resource = new Resource();
+ resource.setResourceKey(this.toString());
+ resource.setResourceType(resourceType);
+ resource.setPluginConfiguration(configuration);
+ resource.setName(resourceType.getName());
+ ResourceComponent parentResourceComponent = null;
+
+ components.put(component, resource);
+ resource.setParentResource(pluginContainer.getInventoryManager().getPlatform());
+
+ ResourceDiscoveryComponent resourceDiscoveryComponent = new NothingDiscoveringDiscoveryComponent();
+ EventContext eventContext = new EventContextImpl(resource);
+ ResourceContext context = new ResourceContext(resource, parentResourceComponent,
+ resourceDiscoveryComponent, systemInfo, temporaryDirectory, dataDirectory,
+ pluginContainerName, eventContext, operationContext, contentContext,
+ availCollectorThreadPool, pluginContainerDeployment);
+ component.start(context);
+
+ resourceDiscoveryContext = new ResourceDiscoveryContext(resourceType, parentResourceComponent, context, systemInfo,
+ Collections.emptyList(), Collections.emptyList(), pluginContainerName, pluginContainerDeployment);
+
+ for (ResourceType rt : resourceType.getChildResourceTypes()) {
+ processChild(rt, component, resource);
+ }
+ }
+
+ log.info("ResourceComponent map: " + components);
+ }
+
+ /**
+ * Process a child
+ * @param component parent component
+ * @param resource parent resource
+ * @param resourceType child resource type
+ */
+ private void processChild(ResourceType resourceType, ResourceComponent component, Resource resource) throws Exception {
+ Configuration configuration = resourceType.getPluginConfigurationDefinition().getDefaultTemplate().createConfiguration();
+ setConfiguration(configuration, resourceType);
+ log.info("childResource " + resourceType + " properties " + configuration.getProperties());
+
+ String s = pmm.getDiscoveryClass(resourceType);
+ ResourceDiscoveryComponent rdc = (ResourceDiscoveryComponent) Class.forName(s).newInstance();
+ log.debug("rdc=" + rdc);
+
+ EventContext eventContext = new EventContextImpl(resource);
+ ResourceContext context = new ResourceContext(resource, component,
+ resourceDiscoveryComponent, systemInfo, temporaryDirectory, dataDirectory,
+ pluginContainerName, eventContext, operationContext, contentContext,
+ availCollectorThreadPool, pluginContainerDeployment);
+ ResourceDiscoveryContext resourceDiscoveryContext = new ResourceDiscoveryContext(resourceType, component, context, systemInfo,
+ Collections.emptyList(), Collections.emptyList(), pluginContainerName, pluginContainerDeployment);
+ Assert.assertNotNull(context.getEventContext());
+ Set<DiscoveredResourceDetails> d = rdc.discoverResources(resourceDiscoveryContext);
+ for (DiscoveredResourceDetails drd : d) {
+ log.debug("discovered " + drd);
+ createChild(drd, resource, configuration, component);
+ }
+
+ }
+
+ private void createChild(DiscoveredResourceDetails drd,
+ Resource resource,
+ Configuration configuration,
+ ResourceComponent parentComponent) throws Exception
+ {
+ ResourceType type = pmm.getType(drd.getResourceType());
+
+ Resource cresource = new Resource();
+ cresource.setResourceType(type);
+ cresource.setPluginConfiguration(configuration);
+ cresource.setResourceKey(drd.getResourceKey());
+ cresource.setParentResource(resource);
+ cresource.setName(drd.getResourceName());
+
+ String rclassname = pmm.getComponentClass(type);
+ ResourceComponent component = (ResourceComponent) Class.forName(rclassname).newInstance();
+
+ EventContext eventContext = new EventContextImpl(resource);
+ ResourceContext context = new ResourceContext(cresource, parentComponent,
+ resourceDiscoveryComponent, systemInfo, temporaryDirectory, dataDirectory,
+ pluginContainerName, eventContext, operationContext, contentContext,
+ availCollectorThreadPool, pluginContainerDeployment);
+
+ component.start(context);
+ components.put(component, cresource);
+ }
+
+ /**
+ * Called before the configuration is processed; override to set specific plugin parameters.
+ * @see #configuration
+ */
+ protected void setConfiguration(Configuration configuration, ResourceType resourceType) {
+ }
+
+ /**
+ * Stops all components, stops the plugin container.
+ */
+ @AfterTest
+ protected void after() throws Exception {
+ for (ResourceComponent c : components.keySet())
+ c.stop();
+ PluginContainer.getInstance().shutdown();
+ }
+
+ /**
+ * Returns a measurement report.
+ */
+ protected MeasurementReport getMeasurementReport(ResourceComponent component) throws Exception {
+ Resource resource = this.components.get(component);
+ ResourceType type = resource.getResourceType();
+ MeasurementReport report = new MeasurementReport();
+ Set<MeasurementScheduleRequest> s = new HashSet<MeasurementScheduleRequest>();
+ for (MeasurementDefinition md : type.getMetricDefinitions())
+ s.add(new MeasurementScheduleRequest(new MeasurementSchedule(md, resource)));
+ ((MeasurementFacet)component).getValues(report, s);
+ return report;
+ }
+
+ /**
+ * Finds the first resource component by resource name, or asserts failure if not found.
+ * By default this is the resource type, or for a discovered resource the discovered
+ * resource name.
+ */
+ protected ResourceComponent byName(String name) {
+ for (Map.Entry<ResourceComponent, Resource> c : components.entrySet())
+ if (c.getValue().getName().equals(name))
+ return c.getKey();
+ fail("component not found " + name + " in " + components.entrySet());
+ return null;
+ }
+
+ /**
+ * From a measurement report, returns a measurement value, or asserts failure if no such value exists.
+ */
+ protected Double getValue(MeasurementReport report, String name) {
+ for (MeasurementDataNumeric m: report.getNumericData()) {
+ if (m.getName().equals(name)) {
+ log.debug("measurement name " + name + " " + m.getValue());
+ return m.getValue();
+ }
+ }
+ fail("report does not incude " + name + " report " + report.getNumericData());
+ return null;
+ }
+
+ /**
+ * Asserts the resource component is available.
+ */
+ protected void assertUp(ResourceComponent component) {
+ assertEquals("up " + component, AvailabilityType.UP, component.getAvailability());
+ }
+
+ /**
+ * Asserts the resource component is unavailable.
+ */
+ protected void assertDown(ResourceComponent component) {
+ assertEquals("down " + component, AvailabilityType.DOWN, component.getAvailability());
+ }
+
+}
diff --git a/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
new file mode 100644
index 0000000..949aaae
--- /dev/null
+++ b/modules/plugins/oracle/src/test/java/org/rhq/plugins/oracle/OracleServerComponentTest.java
@@ -0,0 +1,95 @@
+package org.rhq.plugins.oracle;
+
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.measurement.MeasurementReport;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+public class OracleServerComponentTest extends ComponentTest {
+
+ private static final String ORACLE_SERVER = "Oracle Server";
+ private ResourceComponent<?> server;
+ private ResourceComponent<?> details;
+
+ // Login username; test USERS resource
+ private String username;
+
+ @BeforeMethod
+ public void reset() {
+ }
+
+ @BeforeTest
+ @Override
+ protected void before() throws Exception {
+ log.info("before");
+ super.before();
+ server = byName(ORACLE_SERVER);
+ assertNotNull(server);
+ details = byName("Oracle Advanced Statistics");
+ assertNotNull(details);
+ }
+
+ @AfterTest
+ protected void after() throws Exception {
+ super.after();
+ assertDown(server);
+ }
+
+ @Override
+ protected void setConfiguration(Configuration configuration, ResourceType resourceType) {
+ if (resourceType.getName().equals(ORACLE_SERVER)) {
+ log.info(configuration.getProperties());
+ Pattern p = Pattern.compile("jdbc:.*:@(.*):(\\d+)/(\\w++)");
+ String url = System.getProperty("oracle.url");
+ if (url == null)
+ throw new IllegalStateException("oracle.url system property not set");
+ Matcher matcher = p.matcher(url);
+ if (!matcher.matches())
+ throw new IllegalStateException("Cannot match " + p.pattern() + " against " + url);
+ configuration.getSimple("host").setStringValue(matcher.group(1));
+ configuration.getSimple("port").setIntegerValue(Integer.parseInt(matcher.group(2)));
+ configuration.getSimple("sid").setStringValue(matcher.group(3));
+ username = System.getProperty("oracle.username");
+ String password = System.getProperty("oracle.password");
+ configuration.getSimple("principal").setStringValue(username);
+ configuration.getSimple("credentials").setStringValue(password);
+ }
+ }
+
+ @Test
+ public void up() throws Exception {
+ log.info("testUp");
+ assertUp(server);
+ MeasurementReport report = getMeasurementReport(server);
+ Double rt;
+ rt = getValue(report, "totalSize");
+ assertTrue(rt > 100);
+ rt = getValue(report, "user calls");
+ assertTrue(rt > 0);
+
+ assertUp(details);
+ report = getMeasurementReport(details);
+ rt = getValue(report, "Buffer Cache Hit Ratio");
+ log.debug("hit " + rt);
+
+ ResourceComponent<?> user = byName(username.toUpperCase());
+ assertUp(user);
+ report = getMeasurementReport(user);
+ rt = getValue(report, "active");
+ assertTrue("have at least one active connection", rt >= 1);
+ rt = getValue(report, "connections");
+ assertTrue("have at least one connection", rt >= 1);
+ }
+
+
+}
diff --git a/modules/plugins/oracle/src/test/resources/log4j.xml b/modules/plugins/oracle/src/test/resources/log4j.xml
new file mode 100644
index 0000000..69a897c
--- /dev/null
+++ b/modules/plugins/oracle/src/test/resources/log4j.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- tests configuration that only dumps WARN or higher messages due to appender threadhold -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Threshold" value="ERROR"/>
+ <param name="Target" value="System.out"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%t] (%c{5}) - %m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="FILE" class="org.apache.log4j.FileAppender">
+ <param name="File" value="target/test.log"/>
+ <param name="Threshold" value="DEBUG"/>
+ <param name="Append" value="false"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} (%F:%M:%L) -%m%n"/>
+ </layout>
+ </appender>
+
+ <category name="org.jboss.on">
+ <priority value="DEBUG"/>
+ </category>
+
+ <root>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ </root>
+
+</log4j:configuration>
commit 7a155eadc7989be7de1a26fd135ad461660b0959
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Wed Jan 18 17:19:58 2012 -0500
[BZ 782612][BZ 772318] the agent registration now requires a token. null tokens are rejected unless its a new agent.
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 5359c3c..c7e0cfc 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
@@ -751,8 +751,8 @@ public class AgentMain {
try {
shutdownPluginContainer();
} catch (Throwable ignore) {
- LOG.warn(AgentI18NResourceKeys.FAILED_TO_SHUTDOWN_COMPONENT, "Plugin Container", ThrowableUtil
- .getAllMessages(ignore));
+ LOG.warn(AgentI18NResourceKeys.FAILED_TO_SHUTDOWN_COMPONENT, "Plugin Container",
+ ThrowableUtil.getAllMessages(ignore));
}
///////
@@ -984,8 +984,8 @@ public class AgentMain {
LOG.debug(AgentI18NResourceKeys.FAILOVER_LIST_LOADED, failoverListFile, list.size());
} catch (Exception e) {
list = new FailoverListComposite(new ArrayList<ServerEntry>());
- LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_LOADED, failoverListFile, ThrowableUtil
- .getAllMessages(e));
+ LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_LOADED, failoverListFile,
+ ThrowableUtil.getAllMessages(e));
}
}
@@ -1191,8 +1191,10 @@ public class AgentMain {
// store is the default value.
// But first we need to backup these original preferences in case the config file fails to load -
// we'll restore the original values in that case.
-
+ // Note that we squirrel away any security token we already have - we need to preserve this when we can
+ // because otherwise the agent will not be able to re-register with any previous name is was registered with.
Preferences preferencesNode = getPreferencesNode();
+ String securityToken = preferencesNode.get(AgentConfigurationConstants.AGENT_SECURITY_TOKEN, null);
ByteArrayOutputStream backup = new ByteArrayOutputStream();
preferencesNode.exportSubtree(backup);
preferencesNode.clear();
@@ -1213,10 +1215,26 @@ public class AgentMain {
ByteArrayInputStream new_config_input_stream = new ByteArrayInputStream(new_config.getBytes());
Preferences.importPreferences(new_config_input_stream);
- if (new AgentConfiguration(preferencesNode).getAgentConfigurationVersion() == 0) {
+ AgentConfiguration newAgentConfig = new AgentConfiguration(preferencesNode);
+ if (newAgentConfig.getAgentConfigurationVersion() == 0) {
throw new IllegalArgumentException(MSG.getMsg(AgentI18NResourceKeys.BAD_NODE_NAME_IN_CONFIG_FILE,
file_name, m_agentPreferencesNodeName));
}
+
+ // If we had a security token, restore it so we can maintain our known registration with the server.
+ // Note that if the configuration file already had a security token defined, it will be used and the old
+ // token we had will be thrown away.
+ if (securityToken != null) {
+ if (newAgentConfig.getAgentSecurityToken() == null) {
+ LOG.debug(AgentI18NResourceKeys.RESTORING_SECURITY_TOKEN);
+ newAgentConfig.setAgentSecurityToken(securityToken);
+ } else {
+ LOG.info(AgentI18NResourceKeys.NOT_RESTORING_SECURITY_TOKEN);
+ }
+ }
+
+ preferencesNode.flush();
+
} catch (Exception e) {
// a problem occurred importing the config file; let's restore our original values
try {
@@ -2297,8 +2315,8 @@ public class AgentMain {
*/
private void prepareAutoDiscoveryListener() throws Exception {
if (m_configuration.isServerAutoDetectionEnabled()) {
- ServiceContainerConfiguration comm_config = new ServiceContainerConfiguration(m_configuration
- .getPreferences());
+ ServiceContainerConfiguration comm_config = new ServiceContainerConfiguration(
+ m_configuration.getPreferences());
if (comm_config.isMulticastDetectorEnabled()) {
m_autoDiscoveryListener = new AgentAutoDiscoveryListener(this, createServerRemoteCommunicator(null,
false, false));
@@ -2469,8 +2487,8 @@ public class AgentMain {
if (wait > 0) {
long now = System.currentTimeMillis();
if ((started + wait) < now) {
- throw new RuntimeException(MSG
- .getMsg(AgentI18NResourceKeys.CANNOT_WAIT_TO_BE_REGISTERED_ANY_LONGER));
+ throw new RuntimeException(
+ MSG.getMsg(AgentI18NResourceKeys.CANNOT_WAIT_TO_BE_REGISTERED_ANY_LONGER));
}
}
@@ -2570,27 +2588,27 @@ public class AgentMain {
Map<String, String> config = new HashMap<String, String>();
if (SecurityUtil.isTransportSecure(uri)) {
- config.put(SSLSocketBuilder.REMOTING_KEY_STORE_FILE_PATH, m_configuration
- .getClientSenderSecurityKeystoreFile());
- config.put(SSLSocketBuilder.REMOTING_KEY_STORE_ALGORITHM, m_configuration
- .getClientSenderSecurityKeystoreAlgorithm());
+ config.put(SSLSocketBuilder.REMOTING_KEY_STORE_FILE_PATH,
+ m_configuration.getClientSenderSecurityKeystoreFile());
+ config.put(SSLSocketBuilder.REMOTING_KEY_STORE_ALGORITHM,
+ m_configuration.getClientSenderSecurityKeystoreAlgorithm());
config.put(SSLSocketBuilder.REMOTING_KEY_STORE_TYPE, m_configuration.getClientSenderSecurityKeystoreType());
- config.put(SSLSocketBuilder.REMOTING_KEY_STORE_PASSWORD, m_configuration
- .getClientSenderSecurityKeystorePassword());
- config.put(SSLSocketBuilder.REMOTING_KEY_PASSWORD, m_configuration
- .getClientSenderSecurityKeystoreKeyPassword());
- config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_FILE_PATH, m_configuration
- .getClientSenderSecurityTruststoreFile());
- config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_ALGORITHM, m_configuration
- .getClientSenderSecurityTruststoreAlgorithm());
- config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_TYPE, m_configuration
- .getClientSenderSecurityTruststoreType());
- config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_PASSWORD, m_configuration
- .getClientSenderSecurityTruststorePassword());
+ config.put(SSLSocketBuilder.REMOTING_KEY_STORE_PASSWORD,
+ m_configuration.getClientSenderSecurityKeystorePassword());
+ config.put(SSLSocketBuilder.REMOTING_KEY_PASSWORD,
+ m_configuration.getClientSenderSecurityKeystoreKeyPassword());
+ config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_FILE_PATH,
+ m_configuration.getClientSenderSecurityTruststoreFile());
+ config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_ALGORITHM,
+ m_configuration.getClientSenderSecurityTruststoreAlgorithm());
+ config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_TYPE,
+ m_configuration.getClientSenderSecurityTruststoreType());
+ config.put(SSLSocketBuilder.REMOTING_TRUST_STORE_PASSWORD,
+ m_configuration.getClientSenderSecurityTruststorePassword());
config.put(SSLSocketBuilder.REMOTING_SSL_PROTOCOL, m_configuration.getClientSenderSecuritySocketProtocol());
config.put(SSLSocketBuilder.REMOTING_KEY_ALIAS, m_configuration.getClientSenderSecurityKeystoreAlias());
- config.put(SSLSocketBuilder.REMOTING_SERVER_AUTH_MODE, Boolean.toString(m_configuration
- .isClientSenderSecurityServerAuthMode()));
+ config.put(SSLSocketBuilder.REMOTING_SERVER_AUTH_MODE,
+ Boolean.toString(m_configuration.isClientSenderSecurityServerAuthMode()));
config.put(SSLSocketBuilder.REMOTING_SOCKET_USE_CLIENT_MODE, "true");
// since we do not know the server's client-auth mode, assume we need a keystore and let's make sure we have one
@@ -2600,10 +2618,10 @@ public class AgentMain {
dummy_sslbuilder.setKeyStoreURL(m_configuration.getClientSenderSecurityKeystoreFile());
} catch (Exception e) {
// this probably is due to the fact that the keystore doesn't exist yet - let's prepare one now
- SecurityUtil.createKeyStore(m_configuration.getClientSenderSecurityKeystoreFile(), m_configuration
- .getClientSenderSecurityKeystoreAlias(), "CN=RHQ, OU=RedHat, O=redhat.com, C=US", m_configuration
- .getClientSenderSecurityKeystorePassword(), m_configuration
- .getClientSenderSecurityKeystoreKeyPassword(), "DSA", 36500);
+ SecurityUtil.createKeyStore(m_configuration.getClientSenderSecurityKeystoreFile(),
+ m_configuration.getClientSenderSecurityKeystoreAlias(), "CN=RHQ, OU=RedHat, O=redhat.com, C=US",
+ m_configuration.getClientSenderSecurityKeystorePassword(),
+ m_configuration.getClientSenderSecurityKeystoreKeyPassword(), "DSA", 36500);
// now try to set it again, if an exception is still thrown, it's an unrecoverable error
dummy_sslbuilder.setKeyStoreURL(m_configuration.getClientSenderSecurityKeystoreFile());
@@ -2702,8 +2720,8 @@ public class AgentMain {
StreamUtil.copy(byteStream, fileStream, true);
LOG.debug(AgentI18NResourceKeys.FAILOVER_LIST_PERSISTED, failoverListFile);
} catch (Exception e) {
- LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_PERSISTED, failoverListFile, ThrowableUtil
- .getAllMessages(e));
+ LOG.warn(e, AgentI18NResourceKeys.FAILOVER_LIST_CANNOT_BE_PERSISTED, failoverListFile,
+ ThrowableUtil.getAllMessages(e));
}
// let's be kind to the user - if any server address is "localhost" or "127.0.0.#"
@@ -2773,8 +2791,8 @@ public class AgentMain {
break;
}
} catch (Throwable t) {
- m_output.println(MSG.getMsg(AgentI18NResourceKeys.COMMAND_FAILURE, cmd, ThrowableUtil
- .getAllMessages(t)));
+ m_output.println(MSG.getMsg(AgentI18NResourceKeys.COMMAND_FAILURE, cmd,
+ ThrowableUtil.getAllMessages(t)));
LOG.debug(t, AgentI18NResourceKeys.COMMAND_FAILURE_STACK_TRACE);
}
}
@@ -2890,7 +2908,7 @@ public class AgentMain {
* @throws HelpException if help was requested and the agent should not be created
*/
private void processArguments(String[] args) throws Exception {
- String sopts = "-:hdlasntguD:i:o:c:p:e:";
+ String sopts = "-:hdlLasntguD:i:o:c:p:e:";
LongOpt[] lopts = { new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
new LongOpt("input", LongOpt.REQUIRED_ARGUMENT, null, 'i'),
new LongOpt("output", LongOpt.REQUIRED_ARGUMENT, null, 'o'),
@@ -2899,6 +2917,7 @@ public class AgentMain {
new LongOpt("console", LongOpt.REQUIRED_ARGUMENT, null, 'e'),
new LongOpt("daemon", LongOpt.NO_ARGUMENT, null, 'd'),
new LongOpt("cleanconfig", LongOpt.NO_ARGUMENT, null, 'l'),
+ new LongOpt("cleanallconfig", LongOpt.NO_ARGUMENT, null, 'L'),
new LongOpt("advanced", LongOpt.NO_ARGUMENT, null, 'a'),
new LongOpt("setup", LongOpt.NO_ARGUMENT, null, 's'),
new LongOpt("nostart", LongOpt.NO_ARGUMENT, null, 'n'),
@@ -2908,6 +2927,7 @@ public class AgentMain {
String config_file_name = null;
boolean clean_config = false;
+ boolean clean_token = false; // only used if clean_config = true
boolean purge_data = false;
boolean purge_plugins = false;
AgentInputReaderFactory.ConsoleType console_type = null;
@@ -2967,6 +2987,13 @@ public class AgentMain {
break;
}
+ case 'L': {
+ clean_config = true;
+ purge_data = true;
+ clean_token = true;
+ break;
+ }
+
case 'u': {
purge_data = true;
break;
@@ -3051,7 +3078,21 @@ public class AgentMain {
// now that all the arguments were processed, let's load in our config (this allows the -p to come after -c)
if (clean_config) {
- getPreferencesNode().removeNode();
+ Preferences prefsNode = getPreferencesNode();
+ if (clean_token) {
+ prefsNode.removeNode();
+ } else {
+ // remove everything EXCEPT the security token
+ String[] prefKeys = prefsNode.keys();
+ if (prefKeys != null && prefKeys.length > 0) {
+ for (String prefKey : prefKeys) {
+ if (!prefKey.equals(AgentConfigurationConstants.AGENT_SECURITY_TOKEN)) {
+ prefsNode.remove(prefKey);
+ }
+ }
+ }
+ }
+ prefsNode.flush();
}
if (config_file_name != null) {
@@ -3260,6 +3301,8 @@ public class AgentMain {
preferencesNode.put(ServiceContainerConfigurationConstants.DATA_DIRECTORY, data_dir);
}
+ prefs.flush();
+
LOG.debug(AgentI18NResourceKeys.CONFIGURATION, agent_configuration);
return;
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 59702fc..0b41bb7 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
@@ -613,7 +613,8 @@ public interface AgentI18NResourceKeys {
+ "\\ -g, --purgeplugins Deletes all plugins, forcing the agent to re-download all of them\\n\\\n"
+ "\\ -h, --help Shows this help message (default)\\n\\\n"
+ "\\ -i, --input=<filename> Specifies a script file to be used for input\\n\\\n"
- + "\\ -l, --cleanconfig Clears out any existing configuration and data files so the agent starts with a totally clean slate\\n\\\n"
+ + "\\ -l, --cleanconfig Clears out existing configuration and data files, except for the security token.\\n\\\n"
+ + "\\ -L, --cleanallconfig Clears out all existing configuration and data files so the agent starts with a totally clean slate\\n\\\n"
+ "\\ -n, --nostart If specified, the agent will not be automatically started\\n\\\n"
+ "\\ -o, --output=<filename> Specifies a file to write all output (excluding log messages)\\n\\\n"
+ "\\ -p, --pref=<preferences name> Specifies the agent preferences name used to identify what configuration to use\\n\\\n"
@@ -2104,4 +2105,10 @@ public interface AgentI18NResourceKeys {
@I18NMessage("Restarting the plugin container due to previous failure to merge the upgrade results with the server.")
String RESTARTING_PLUGIN_CONTAINER_AFTER_UPGRADE_MERGE_FAILURE = "AgentMain.pc-conditional-restart";
+
+ @I18NMessage("Restoring the original security token.")
+ String RESTORING_SECURITY_TOKEN = "AgentMain.restoring-security-token";
+
+ @I18NMessage("The config file already has a security token defined. The original security token will be thrown away.")
+ String NOT_RESTORING_SECURITY_TOKEN = "AgentMain.not-restoring-security-token";
}
\ No newline at end of file
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java
index fd2286c..90d7042 100644
--- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java
+++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/ha/ViewAgentUIBean.java
@@ -56,6 +56,9 @@ public class ViewAgentUIBean extends PagedDataTableUIBean {
hasPermission();
int agentId = FacesContextUtility.getRequiredRequestParameter("agentId", Integer.class);
agent = agentManager.getAgentByID(agentId);
+ if (!hasPermissionToViewSecurityToken()) {
+ agent.setAgentToken("******");
+ }
}
return agent;
}
@@ -94,4 +97,9 @@ public class ViewAgentUIBean extends PagedDataTableUIBean {
+ "] does not have the proper permissions to view or manage agents");
}
}
+
+ private boolean hasPermissionToViewSecurityToken() {
+ Subject subject = EnterpriseFacesContextUtility.getSubject();
+ return LookupUtil.getAuthorizationManager().hasGlobalPermission(subject, Permission.MANAGE_SECURITY);
+ }
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
index e380b6e..75c4d65 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
@@ -104,14 +104,10 @@ public class CoreServerServiceImpl implements CoreServerService {
* something else".
*
* If there is no original token with the request, this is either a brand new agent never before registered, or it
- * is an agent that has been registered before but for some reason lost its token. In this case, we will look at
- * this registration's host/port of this new agent. If it matches the host/port of another agent but the
- * existing name and the new agent's name don't match, the server will abort and tell the agent, "You don't know
- * who you are, but I know there is already an agent with the host and port you are trying to register with
- * under a different name - so I'm going to trust this original agent and not allow you to register that name
- * under a different host/port. If you are that original agent, then you need to register with that original
- * name". When the agent registers again, this time with the correct name, the agent will be given its token.
- * This usually will occur if you reinstall the agent and try to register it under a different name.
+ * is an agent that has been registered before but for some reason lost its token.
+ * In this case, if there is no agent with the name being requested, we register this as a new agent.
+ * If, however, the agent name is already in use, we abort the request. An agent cannot register with an
+ * existing agent without sending that agent's security token.
*/
if (request.getOriginalToken() != null) {
@@ -140,19 +136,24 @@ public class CoreServerServiceImpl implements CoreServerService {
// the agent request provided a name that already is in use by an agent. However, the request
// provided a security token that was not assigned to any agent! How can this be? Something is fishy.
String msg = "The agent asking for registration under the name [" + request.getName()
- + "] provided an invalid security token. This request will fail.";
+ + "] provided an invalid security token. This request will fail. "
+ + "Please consult an administrator to reconfigure this agent with its proper security token.";
throw new AgentRegistrationException(msg);
}
Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(),
request.getPort());
if (agentByAddressPort != null) {
- // the agent request provided a security token but it is an unknown/unused/bogus token.
+ // The agent is requesting to register an unused agent name - so this is considered a new agent.
+ // It provided a security token but it is an unknown/obsolete/bogus token (usually due to the
+ // fact that someone purged the platform/agent from the server database but the old agent is
+ // still around with its old token).
// However, the IP/port it wants to use is already in-use. This sounds fishy. If we let this
// go through, this agent with an unknown/bogus token will essentially hijack this IP/port
// belonging to an existing agent. If the agent wants to reuse an IP/port already in existence, it should
// already know its security token associated with that IP/port. Thus, we will abort this request.
String msg = "The agent asking for registration under the name [" + request.getName()
- + "] is attempting to authenticate using an unknown security token. This request will fail.";
+ + "] is attempting to take another agent's address/port [" + request.getAddress() + ":"
+ + request.getPort() + "] with an unknown security token. This request will fail.";
throw new AgentRegistrationException(msg);
}
}
@@ -167,23 +168,25 @@ public class CoreServerServiceImpl implements CoreServerService {
+ request.getPort()
+ "] that is already registered under a different name ["
+ agentByAddressPort.getName()
- + "]; if this new agent is actually the same as the original, then re-register with the same name";
+ + "]; if this new agent is actually the same as the original, then re-register with the same name"
+ + " and same security token.";
throw new AgentRegistrationException(msg);
+ } else {
+ String msg = "The agent [" + request.getName()
+ + "] is attempting to re-register without a security token. "
+ + "Please consult an administrator to reconfigure this agent with its proper security token.";
+ throw new AgentRegistrationException(msg);
+
}
} else {
if (agentByName != null) {
- // the name being registered already exists, however, the agent request is trying to set it
- // to some unknown IP/port combination and there is no security token to authenticate this request!
+ // the name being registered already exists - but there is no security token to authenticate this request!
// Therefore, because this agent name is already registered and because this current request
// cannot authenticate itself with the proper security token, we fail.
String msg = "An agent is trying to register with an existing agent name ["
+ request.getName()
- + "]. The registration request is attempting to assign the agent an unknown address/port ["
- + request.getAddress()
- + ":"
- + request.getPort()
+ "] without providing a valid security token. If you are attempting to re-register this agent, "
- + "make sure you register with its prior address/port.";
+ + "please consult an administrator to reconfigure this agent with its proper security token.";
throw new AgentRegistrationException(msg);
}
}
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
index a3dda5e..5a702ff 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
@@ -41,12 +41,57 @@ import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.Server.OperationMode;
import org.rhq.core.domain.common.ProductInfo;
import org.rhq.core.domain.resource.Agent;
+import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.util.LookupUtil;
/**
+ * This tests the core server service. This includes agent registration.
+ *
* @author John Mazzitelli
*/
+
+// These are the agent registration unit test cases.
+// (allowed) means the registration should succeed.
+// (REJECT) means the server should reject that agent registration request.
+// ---
+// A. testNewAgentRegistrationWithOldToken
+// 1) register a new agent with a non-null, unknown security token (allowed)
+// B. testChangeAddressPort
+// 1) register a new agent Z with null security token (allowed)
+// 2) re-register agent Z with its token but change its host (allowed)
+// 3) re-register agent Z with its token but change its port (allowed)
+// 4) re-register agent Z with its token but change its host and port (allowed)
+// 5) re-register agent Z with its token but change nothing (allowed)
+// 6) re-register agent Z with NO token but change its host (REJECT)
+// 7) re-register agent Z with NO token but change its port (REJECT)
+// 8) re-register agent Z with NO token but change its host and port (REJECT)
+// 9) re-register agent Z with NO token but change nothing (REJECT)
+// C. testNormalAgentRegistration
+// 1) register a new agent A with a null security token (allowed, same as B.1)
+// D. testHijackExistingAgentAddressPort
+// 1) register a new agent B with null security token but using A's host/port (REJECT)
+// E. testHijackExistingAgentName
+// 1) register an agent using an already-existing agent name A, and using A's host but a different port with a null token (REJECT - missing the token)
+// 2) register an agent using an already-existing agent name A, and using A's port but a different host with a null token (REJECT - missing the token)
+// 3) register an agent using an already-existing agent name A, and using a different port and host with a null token (REJECT - missing the token)
+// F. testHijackExistingAgentAddressPortWithBogusToken
+// 1) register a new agent B with A's host and port but with a bogus token (REJECT)
+// G. testHijackExistingAgentNameWithBogusToken
+// 1) re-register agent A with its original host and port but with a bogus token (REJECT)
+// 2) re-register agent A with its original host, different port but with bogus token (REJECT)
+// 3) re-register agent A with different host, original port but with bogus token (REJECT)
+// 4) re-register agent A with different host and port but with bogus token (REJECT)
+// H. testHijackExistingAgentNameWithAnotherAgentToken
+// 1) re-register agent A with its original host and port but with Z's security token (REJECT - you cannot authenticate using another agent's token)
+// 2) re-register agent A with different host and original port but with Z's security token (REJECT - you cannot authenticate using another agent's token)
+// 3) re-register agent A with original host and different port but with Z's security token (REJECT - you cannot authenticate using another agent's token)
+// 4) re-register agent A with different host and port but with Z's security token (REJECT - you cannot authenticate using another agent's token)
+// I. testAgentHijackingAnotherAgentAddressPort
+// 1) re-register agent A using A's correct security token but with Z's host and Z's port (REJECT - one agent cannot steal another agent's host/port endpoint) NOTE: this is not D.1 because in D.1, the request doesn't have a token. This I.1 test has a token and it really authenticates the agent A making the request. This also isn't F.1 because F.1, while it has a token, it is not a valid token, thus its agent is not authentic.
+// J. testAttemptToChangeAgentName
+// 1) register agent "newName" but with Z's host/port/token. In effect, this is trying to change the agent's name. (REJECT - you are not allowed to rename agents)
+
@Test
public class CoreServerServiceImplTest extends AbstractEJB3Test {
private static final String TEST_AGENT_NAME_PREFIX = "CoreServerServiceImplTest.Agent";
@@ -67,7 +112,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
public void testNewAgentRegistrationWithOldToken() throws Exception {
// this tests the case where someone purged an agent from the DB, but then
// changed their mind and want to re-run that agent and re-register it again.
- // In this case, the agent (if not using --cleanconfig) would still have the old token.
+ // In this case, the agent (if not using --cleanallconfig) would still have the old token.
// The agent should still be allowed to register again.
CoreServerServiceImpl service = new CoreServerServiceImpl();
AgentRegistrationRequest request = createRequest(prefixName("old"), "hostOld", 12345, "oldtoken");
@@ -128,18 +173,40 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
assert agent.getAddress().equals("hostZdoubleprime");
assert agent.getPort() == 55552;
- // now don't change Z's host/port but re-register everything the same, but with no token
- request = createRequest(zName, "hostZdoubleprime", 55552, null);
- results = service.registerAgent(request);
- assert results != null;
- agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
- assert agent.getName().equals(zName);
- assert agent.getAddress().equals("hostZdoubleprime");
- assert agent.getPort() == 55552;
-
// remember this agent so our later tests can use it
zReq = request;
zResults = results;
+
+ // Try to re-register changes to host and/or port but do not send any token.
+ // Because there is no token, these should fail.
+ request = createRequest(zName, B_HOST, zReq.getPort(), null);
+ try {
+ service.registerAgent(request);
+ assert false : "(1) Should not have been able to register without a token";
+ } catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
+ }
+ request = createRequest(zName, zReq.getAddress(), B_PORT, null);
+ try {
+ service.registerAgent(request);
+ assert false : "(2) Should not have been able to register without a token";
+ } catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
+ }
+ request = createRequest(zName, B_HOST, B_PORT, null);
+ try {
+ service.registerAgent(request);
+ assert false : "(3) Should not have been able to register without a token";
+ } catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
+ }
+ request = createRequest(zName, zReq.getAddress(), zReq.getPort(), null);
+ try {
+ service.registerAgent(request);
+ assert false : "(4) Should not have been able to register without a token";
+ } catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
+ }
}
@Test(dependsOnMethods = "testChangeAddressPort")
@@ -159,6 +226,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used host/port with new agent name";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -171,18 +239,21 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name without a token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), null);
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name without a token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, B_PORT, null);
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name without a token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -195,6 +266,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used host/port with new agent name and invalid token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -207,24 +279,28 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name with an invalid token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, "badtoken");
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name with an invalid token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), "badtoken");
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name with an invalid token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, B_PORT, "badtoken");
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack a used agent name with an invalid token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -237,24 +313,28 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "Should not have been able to hijack agent A using Z's token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), zResults.getAgentToken());
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack agent A using Z's token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, zResults.getAgentToken());
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack agent A using Z's token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
request = createRequest(aReq.getName(), B_HOST, B_PORT, zResults.getAgentToken());
try {
service.registerAgent(request);
assert false : "Should not have been able to hijack agent A using Z's token";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -267,6 +347,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "An agent should not have been able to hijack another agent's host/port";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -279,6 +360,7 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
service.registerAgent(request);
assert false : "An agent should not be able to change its name";
} catch (AgentRegistrationException ok) {
+ debugPrintThrowable(ok);
}
}
@@ -291,6 +373,12 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
return TEST_AGENT_NAME_PREFIX + name;
}
+ private void debugPrintThrowable(Throwable t) {
+ if (true) {
+ System.out.println(ThrowableUtil.getAllMessages(t));
+ }
+ }
+
@BeforeClass
public void prepare() throws Exception {
// mock the name of our server via the sysprop (in production, this is normally set in rhq-server.properties)
commit bb1f35f5994233e9f002952c7084ce4d8769c1e1
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 17 20:46:09 2012 +0100
BZ 708332 - Add support for reading/writing of system-properties and paths (partially cherry picked from commit 3e12e49)
Also enable system-properties and path for host controller and hosts.
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 cf0b5b9..6fa678b 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
@@ -241,7 +241,9 @@ public class ASConnection {
if (node==null) {
log.warn("Operation [" + op + "] returned null");
- return null;
+ Result failure = new Result();
+ failure.setFailureDescription("Operation [" + op + "] returned null");
+ return failure;
}
try {
Result res;
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
index cbed07e..4f72013 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
@@ -165,21 +165,25 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
* We may have a mismatch for groups where the <c:group name="children:*"> child is a list of maps
* but the result is actually the contained map
*/
- if (propDef instanceof PropertyDefinitionList && (propDef.getName().equals("*"))) {
+ String propertyName = propDef.getName();
+ if (propDef instanceof PropertyDefinitionList && (propertyName.startsWith("*"))) {
propDef = ((PropertyDefinitionList) propDef).getMemberDefinition();
+ String innerPropdefName = propDef.getName();
+
if (!(propDef instanceof PropertyDefinitionMap)) {
log.error("Embedded child is not a map");
return;
}
// Now we are at map level which matches the operations results
- PropertyList list = new PropertyList("*");
+ PropertyList list = new PropertyList(propertyName);
for (Map.Entry<String,Object> entry : results.entrySet()) {
Object val = entry.getValue();
+ String key = entry.getKey();
- PropertyMap propertyMap = loadHandlePropertyMap((PropertyDefinitionMap) propDef, val);
+ PropertyMap propertyMap = loadHandlePropertyMap((PropertyDefinitionMap) propDef, val, key);
if (propertyMap!=null)
list.add(propertyMap);
@@ -188,7 +192,6 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
config.put(list);
} else { // standard case
- String propertyName = propDef.getName();
Object valueObject = results.get(propertyName);
@@ -207,7 +210,7 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
config.put(propertyList);
}
else if (propDef instanceof PropertyDefinitionMap) {
- PropertyMap propertyMap = loadHandlePropertyMap((PropertyDefinitionMap) propDef, valueObject);
+ PropertyMap propertyMap = loadHandlePropertyMap((PropertyDefinitionMap) propDef, valueObject, null);
if (propertyMap!=null)
config.put(propertyMap);
@@ -239,20 +242,35 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
/**
* Handle a Map of ...
+ *
* @param propDef Definition of the map
* @param valueObject the objects to put into the map
+ * @param optionalEntryName
* @return the populated map
*/
- PropertyMap loadHandlePropertyMap(PropertyDefinitionMap propDef, Object valueObject) {
+ PropertyMap loadHandlePropertyMap(PropertyDefinitionMap propDef, Object valueObject, String optionalEntryName) {
if (valueObject==null)
return null;
- PropertyMap propertyMap = new PropertyMap(propDef.getName());
+ String propDefName = propDef.getName();
+ PropertyMap propertyMap = new PropertyMap(propDefName);
+ String specialNameProp = null;
+ if (propDefName.startsWith("*:")) {
+ specialNameProp = propDefName.substring(2);
+ PropertySimple additionalNameProperty = new PropertySimple(specialNameProp,optionalEntryName);
+ propertyMap.put(additionalNameProperty);
+ }
Map<String, PropertyDefinition> memberDefMap = propDef.getPropertyDefinitions();
+
+
+
Map<String,Object> objects = (Map<String, Object>) valueObject;
for (Map.Entry<String, PropertyDefinition> maEntry : memberDefMap.entrySet()) {
String key = maEntry.getKey();
+ if (key.equals(specialNameProp)) // Skip over specialName prop, as we have processed that already.
+ continue;
+
// special case: if the key is "*", we just pick the first element
Object o ;
if (key.equals("*"))
@@ -266,9 +284,9 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
else if (value instanceof PropertyDefinitionList)
property = loadHandlePropertyList((PropertyDefinitionList) value, o);
else if (value instanceof PropertyDefinitionMap)
- property = loadHandlePropertyMap((PropertyDefinitionMap) value, o);
+ property = loadHandlePropertyMap((PropertyDefinitionMap) value, o,null);
else
- throw new IllegalArgumentException("Unknown property type in map property [" + propDef.getName() +"]");
+ throw new IllegalArgumentException("Unknown property type in map property [" + propDefName +"]");
if (property!=null)
propertyMap.put(property);
@@ -320,7 +338,7 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
Map<String,Object> map = (Map<String, Object>) obj;
PropertyMap propertyMap = loadHandlePropertyMap(
- (PropertyDefinitionMap) propDef.getMemberDefinition(), map);
+ (PropertyDefinitionMap) propDef.getMemberDefinition(), map, null);
if (propertyMap!=null)
propertyList.add(propertyMap);
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
index 4f07bfc..fbf0509 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
@@ -43,6 +43,7 @@ import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.CompositeOperation;
import org.rhq.modules.plugins.jbossas7.json.Operation;
+import org.rhq.modules.plugins.jbossas7.json.ReadChildrenResources;
import org.rhq.modules.plugins.jbossas7.json.Result;
import org.rhq.modules.plugins.jbossas7.json.WriteAttribute;
@@ -55,6 +56,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
private ConfigurationDefinition configurationDefinition;
private String namePropLocator;
private String type;
+ private boolean addNewChildren;
/**
* Create a new configuration delegate, that reads the attributes for the resource at address.
@@ -114,10 +116,17 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
for (PropertyGroupDefinition pgd: configurationDefinition.getGroupDefinitions()) {
String groupName = pgd.getName();
namePropLocator = null;
- if (groupName.startsWith("children:")) {
+ if (groupName.startsWith("children:")) { // children, where the key in key=value from the path is known
type = groupName.substring("children:".length());
if (type.contains(":")) {
namePropLocator = type.substring(type.indexOf(":") + 1);
+ if (namePropLocator.endsWith("+")) { // ending in + -> we need to :add new entries
+ namePropLocator=namePropLocator.substring(0,namePropLocator.length()-1);
+ addNewChildren = true;
+ }
+ else {
+ addNewChildren = false;
+ }
type = type.substring(0, type.indexOf(":"));
}
else {
@@ -128,7 +137,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
for (PropertyDefinition def : definitions) {
updateProperty(conf,cop,def, address);
}
- } if (groupName.startsWith("child:")) {
+ } if (groupName.startsWith("child:")) { // one named child resource
String subPath = groupName.substring("child:".length());
if (!subPath.contains("="))
throw new IllegalArgumentException("subPath of 'child:' expression has no =");
@@ -156,17 +165,54 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
return;
// Handle the special case
- if (propDef instanceof PropertyDefinitionList && propDef.getName().equals("*")) {
+ String propDefName = propDef.getName();
+ if (propDef instanceof PropertyDefinitionList && propDefName.startsWith("*")) {
propDef = ((PropertyDefinitionList) propDef).getMemberDefinition();
- PropertyList pl = (PropertyList) conf.get("*"); // TODO loop over the list content
+ PropertyList pl = (PropertyList) conf.get(propDefName);
+
+ // check if we need to see if that property exists - get the current state of affairs from the AS
+ List<String> existingPropnames = new ArrayList<String>();
+ if (addNewChildren) {
+ Operation op = new ReadChildrenResources(baseAddress,type);
+ Result tmp = connection.execute(op);
+ if (tmp.isSuccess()) {
+ Map<String,Object> tmpResMap = (Map<String, Object>) tmp.getResult();
+ existingPropnames.addAll(tmpResMap.keySet());
+ }
+ }
+ // Loop over the list - i.e. the individual rows that come from the server
for (Property prop2 : pl.getList()) {
- updateHandlePropertyMapSpecial(cop, (PropertyMap) prop2, (PropertyDefinitionMap) propDef, baseAddress);
+ updateHandlePropertyMapSpecial(cop, (PropertyMap) prop2, (PropertyDefinitionMap) propDef, baseAddress,
+ existingPropnames);
}
+ // now check about removed properties
+ for (String existingName : existingPropnames ) {
+ boolean found=false;
+ for (Property prop2 : pl.getList()) {
+ PropertyMap propMap2 = (PropertyMap) prop2;
+ String itemName = propMap2.getSimple(namePropLocator).getStringValue();
+ if (itemName==null) {
+ throw new IllegalArgumentException("Map contains no entry with name '" + namePropLocator + "'");
+ }
+ if (itemName.equals(existingName)) {
+ found=true;
+ break;
+ }
+ }
+
+ if (!found) {
+ Address tmpAddr = new Address(baseAddress);
+ tmpAddr.add(type, existingName);
+ Operation operation = new Operation("remove",tmpAddr);
+ cop.addStep(operation);
+ }
+ }
+
}
else {
// Normal cases
- Property prop = conf.get(propDef.getName());
+ Property prop = conf.get(propDefName);
if (prop instanceof PropertySimple) {
updateHandlePropertySimple(cop, (PropertySimple)prop, (PropertyDefinitionSimple) propDef, baseAddress);
@@ -188,18 +234,36 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
private void updateHandlePropertyMapSpecial(CompositeOperation cop, PropertyMap prop, PropertyDefinitionMap propDef,
- Address address) {
+ Address address, List<String> existingPropNames) {
Map<String,Object> results = updateHandleMap(prop,propDef, address);
if (prop.get(namePropLocator)==null) {
throw new IllegalArgumentException("There is no element in the map with the name " + namePropLocator);
}
String addrVal= ((PropertySimple)prop.get(namePropLocator)).getStringValue();
+
+
+ // determine key from map as propDefName
+ String key = prop.getSimpleValue(namePropLocator, null);
+ if (key==null) {
+ throw new IllegalArgumentException("Map contains no entry with name '" + namePropLocator + "'");
+ }
+
Address addr = new Address(address);
addr.add(type,addrVal);
for (Map.Entry<String,Object> entry : results.entrySet()) {
- Operation writeAttribute = new WriteAttribute(addr,entry.getKey(),entry.getValue());
- cop.addStep(writeAttribute);
+ Operation operation;
+ if (!addNewChildren || existingPropNames.contains(key))
+ operation = new WriteAttribute(addr,entry.getKey(),entry.getValue());
+ else {
+ Address tmpAddr = new Address(address);
+ tmpAddr.add(type, key);
+ operation = new Operation("add",tmpAddr);
+ operation.addAdditionalProperty("name",key);
+ operation.addAdditionalProperty("value",entry.getValue());
+ }
+ cop.addStep(operation);
}
+
}
private void updateHandlePropertyList(CompositeOperation cop, PropertyList prop, PropertyDefinitionList propDef,
@@ -265,4 +329,4 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
return results;
}
-}
\ No newline at end of file
+}
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 bdcf227..7198463 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
@@ -203,8 +203,30 @@
</c:list-property>
</c:group>
-->
+ <c:group name="children:system-property:name+" displayName="System-properties">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:map-property name="*:name" displayName="Name" readOnly="true">
+ <c:simple-property name="name" displayName="Property-Name" readOnly="true"/>
+ <c:simple-property name="value" displayName="Value"/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
+
+ <c:group name="children:path:name+" displayName="Path">
+ <c:list-property name="*3" displayName="Path" required="false"
+ description="The standard paths provided by the system include: jboss.home - the root directory of the JBoss AS distribution; user.home - user's home directory; user.dir - user's current working directory; java.home - java installation directory; jboss.server.base.dir - root directory for an individual server instance; jboss.server.data.dir - directory the server will use for persistent data file storage; jboss.server.log.dir - directory the server will use for log file storage; jboss.server.tmp.dir - directory the server will use for temporary file storage; jboss.domain.servers.dir - directory under which a host controller will create the working area for individual server instances">
+ <c:map-property name="*" displayName="Entry">
+ <c:simple-property name="name" required="true" type="string" readOnly="false"
+ description="The name of the path. Cannot be one of the standard fixed paths provided by the system"/>
+ <c:simple-property name="path" required="true" type="string" readOnly="false"
+ description="The actual filesystem path. Treated as an absolute path, unless the 'relative-to' attribute is specified, in which case the value is treated as relative to that path."/>
+ <c:simple-property name="relative-to" required="false" type="string" readOnly="false"
+ description="The name of another previously named path, or of one of the standard paths provided by the system. If 'relative-to' is provided, the value of the 'path' attribute is treated as relative to the path specified by this attribute."/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
- <c:group name="children:extension" displayName="Installed extensions" hiddenByDefault="true">
+ <c:group name="children:extension:module" displayName="Installed extensions" hiddenByDefault="true">
<c:list-property name="*" displayName="Installed extensions" readOnly="true" required="false">
<c:map-property name="*" displayName="Name" readOnly="true">
<c:simple-property name="module" displayName="Module name" readOnly="true"/>
@@ -277,6 +299,31 @@
<c:simple-property name="operationResult" description="Outcome of the delete server operation"/>
</results>
</operation>
+
+ <resource-configuration>
+ <c:group name="children:system-property:name+" displayName="System-properties">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:map-property name="*:name" displayName="Name" readOnly="true">
+ <c:simple-property name="name" displayName="Property-Name" readOnly="true"/>
+ <c:simple-property name="value" displayName="Value"/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
+ <c:group name="children:path:name+" displayName="Path">
+ <c:list-property name="*3" displayName="Path" required="false"
+ description="The standard paths provided by the system include: jboss.home - the root directory of the JBoss AS distribution; user.home - user's home directory; user.dir - user's current working directory; java.home - java installation directory; jboss.server.base.dir - root directory for an individual server instance; jboss.server.data.dir - directory the server will use for persistent data file storage; jboss.server.log.dir - directory the server will use for log file storage; jboss.server.tmp.dir - directory the server will use for temporary file storage; jboss.domain.servers.dir - directory under which a host controller will create the working area for individual server instances">
+ <c:map-property name="*" displayName="Entry">
+ <c:simple-property name="name" required="true" type="string" readOnly="false"
+ description="The name of the path. Cannot be one of the standard fixed paths provided by the system"/>
+ <c:simple-property name="path" required="true" type="string" readOnly="false"
+ description="The actual filesystem path. Treated as an absolute path, unless the 'relative-to' attribute is specified, in which case the value is treated as relative to that path."/>
+ <c:simple-property name="relative-to" required="false" type="string" readOnly="false"
+ description="The name of another previously named path, or of one of the standard paths provided by the system. If 'relative-to' is provided, the value of the 'path' attribute is treated as relative to the path specified by this attribute."/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
+
+ </resource-configuration>
</server>
<service name="DomainDeployment"
@@ -338,12 +385,6 @@
description="The absolute path to a JRE or JDK installation directory containing
the JVM that should be used to start and shutdown the JBossAS instance;
defaults to the home directory of the RHQ agent JRE."/>
- <c:list-property name="system-properties">
- <c:map-property name="system-property">
- <c:simple-property name="key" readOnly="true"/>
- <c:simple-property name="value" readOnly="true"/>
- </c:map-property>
- </c:list-property>
&logSources;
<c:group name="event" displayName="Events">
@@ -435,19 +476,32 @@
<resource-configuration>
-<!--
- <c:group name="attribute:schema-locations" displayName="Schema locations">
+ <c:group name="children:system-property:name+" displayName="System-properties">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:map-property name="*:name" displayName="Name" readOnly="true">
+ <c:simple-property name="name" displayName="Property-Name" readOnly="true"/>
+ <c:simple-property name="value" displayName="Value"/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
- <c:list-property name="schema-locations" displayName="Schema locations" readOnly="true" required="false">
- <c:map-property name="*">
- <c:simple-property name="*" readOnly="true" displayName="Schema name"/>
+ <c:group name="children:path:name+" displayName="Path">
+ <c:list-property name="*3" displayName="Path" required="false"
+ description="The standard paths provided by the system include: jboss.home - the root directory of the JBoss AS distribution; user.home - user's home directory; user.dir - user's current working directory; java.home - java installation directory; jboss.server.base.dir - root directory for an individual server instance; jboss.server.data.dir - directory the server will use for persistent data file storage; jboss.server.log.dir - directory the server will use for log file storage; jboss.server.tmp.dir - directory the server will use for temporary file storage; jboss.domain.servers.dir - directory under which a host controller will create the working area for individual server instances">
+ <c:map-property name="*" displayName="Entry">
+ <c:simple-property name="name" required="true" type="string" readOnly="false"
+ description="The name of the path. Cannot be one of the standard fixed paths provided by the system"/>
+ <c:simple-property name="path" required="true" type="string" readOnly="false"
+ description="The actual filesystem path. Treated as an absolute path, unless the 'relative-to' attribute is specified, in which case the value is treated as relative to that path."/>
+ <c:simple-property name="relative-to" required="false" type="string" readOnly="false"
+ description="The name of another previously named path, or of one of the standard paths provided by the system. If 'relative-to' is provided, the value of the 'path' attribute is treated as relative to the path specified by this attribute."/>
</c:map-property>
</c:list-property>
</c:group>
--->
- <c:group name="children:extension" displayName="Installed extensions" hiddenByDefault="true">
- <c:list-property name="*" displayName="Installed extensions" readOnly="true" required="false">
+ <c:group name="children:extension:module" displayName="Installed extensions" hiddenByDefault="true">
+
+ <c:list-property name="*1" displayName="Installed extensions" readOnly="true" required="false">
<c:map-property name="*" displayName="Name" readOnly="true">
<c:simple-property name="module" displayName="Module name" readOnly="true"/>
</c:map-property>
@@ -529,10 +583,8 @@
</results>
</operation>
- <metric property="server-state" dataType="trait" displayName="Server state" description="Detailed server state"
+ <metric property="status" dataType="trait" displayName="Server state" description="Detailed server state"
displayType="summary"/>
- <metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
- <metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
<event name="logEntry" description="an entry in a log file"/>
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 e1627e3..1af2f2f 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
@@ -18,6 +18,9 @@
*/
package org.rhq.modules.plugins.jbossas7;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
@@ -89,6 +92,22 @@ public class AbstractConfigurationHandlingTest {
return null;
}
+ protected String loadJsonFromFile(String fileName) throws Exception {
+ InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ try {
+ StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ builder.append(line);
+ }
+ return builder.toString();
+ }
+ finally {
+ reader.close();
+ }
+ }
+
/**
* Provide a fake connection, that will return the
* content we provide via #setContent
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
index e895dd4..8e3704b 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
@@ -463,20 +463,4 @@ public class ConfigurationLoadingTest extends AbstractConfigurationHandlingTest
}
- private String loadJsonFromFile(String fileName) throws Exception {
- InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- try {
- StringBuilder builder = new StringBuilder();
- String line;
- while ((line = reader.readLine()) != null) {
- builder.append(line);
- }
- return builder.toString();
- }
- finally {
- reader.close();
- }
- }
-
}
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
index 09439f3..703722a 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
@@ -21,6 +21,7 @@ package org.rhq.modules.plugins.jbossas7;
import java.util.List;
import java.util.Map;
+import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.testng.annotations.BeforeSuite;
@@ -32,6 +33,7 @@ import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.modules.plugins.jbossas7.json.Address;
+import org.rhq.modules.plugins.jbossas7.json.ComplexResult;
import org.rhq.modules.plugins.jbossas7.json.CompositeOperation;
import org.rhq.modules.plugins.jbossas7.json.Operation;
@@ -362,4 +364,63 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
assert step2.getAdditionalProperties().get("value").equals("23");
}
+
+ public void test10() throws Exception {
+
+ ConfigurationDefinition definition = loadDescriptor("test10");
+
+ FakeConnection connection = new FakeConnection();
+ String resultString = loadJsonFromFile("system-props.json");
+
+ ObjectMapper mapper = new ObjectMapper();
+ ComplexResult result = mapper.readValue(resultString,ComplexResult.class);
+ JsonNode json = mapper.valueToTree(result);
+
+ connection.setContent(json);
+
+
+ ConfigurationWriteDelegate delegate = new ConfigurationWriteDelegate(definition,connection,null);
+
+ Configuration conf = new Configuration();
+
+ // We have properties 'bar' and 'hello' on the server
+ // update 'bar', add 'hulla' and remove 'hello'
+
+ PropertyList propertyList = new PropertyList("*2");
+ PropertyMap propertyMap = new PropertyMap("*");
+ propertyMap.put(new PropertySimple("name","hulla"));
+ propertyMap.put(new PropertySimple("value","hopp"));
+ propertyList.add(propertyMap);
+ propertyMap = new PropertyMap("*");
+ propertyMap.put(new PropertySimple("name","bar"));
+ propertyMap.put(new PropertySimple("value","42!"));
+ propertyList.add(propertyMap);
+ conf.put(propertyList);
+
+
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
+
+ assert cop.numberOfSteps() == 3 : "#Steps should be 3 but were " + cop.numberOfSteps();
+
+ Operation step1 = cop.step(0);
+ Operation step2 = cop.step(1);
+ Operation step3 = cop.step(2);
+
+ assert step1.getAddress().size()==1;
+ assert step2.getAddress().size()==1;
+ assert step3.getAddress().size()==1;
+ assert step1.getAddress().get(0).equals("system-property=hulla");
+ assert step2.getAddress().get(0).equals("system-property=bar");
+ assert step3.getAddress().get(0).equals("system-property=hello");
+ assert step1.getOperation().equals("add");
+ assert step2.getOperation().equals("write-attribute");
+ assert step3.getOperation().equals("remove");
+
+ assert step1.getAdditionalProperties().get("name").equals("hulla");
+ assert step1.getAdditionalProperties().get("value").equals("hopp");
+ assert step2.getAdditionalProperties().get("name").equals("value"); // This is the name of the property
+ assert step2.getAdditionalProperties().get("value").equals("42!");
+ assert step3.getAdditionalProperties().isEmpty();
+
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/test/resources/system-props.json b/modules/plugins/jboss-as-7/src/test/resources/system-props.json
new file mode 100644
index 0000000..da211cc
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/system-props.json
@@ -0,0 +1,10 @@
+{
+ "outcome" : "success",
+ "result" :
+ {
+ "bar" :
+ {"value" : "44"},
+ "hello" :
+ {"value" : "world"}
+ }
+}
\ No newline at end of file
diff --git a/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml b/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
index 53f351a..173d2be 100644
--- a/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
+++ b/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
@@ -104,6 +104,19 @@
</resource-configuration>
</server>
+ <server class="foo" discovery="foo" name="test10">
+ <resource-configuration>
+ <c:group name="children:system-property:name+" displayName="System-properties">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:map-property name="*:name" displayName="Name" readOnly="true">
+ <c:simple-property name="name" displayName="Property-Name" readOnly="true"/>
+ <c:simple-property name="value" displayName="Value"/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
+ </resource-configuration>
+ </server>
+
<server class="foo" discovery="foo" name="simple1">
<resource-configuration>
commit 81533f2742439923e77ae6d51166f9ed4f6caaa1
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Jan 17 14:48:11 2012 -0500
[BZ 772318] forgot to test the most obvious and most common scenario - re-starting the agent. My original fix broke that. This fixes it back again and adds a unit test for it.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
index 85aa364..e380b6e 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
@@ -125,7 +125,7 @@ public class CoreServerServiceImpl implements CoreServerService {
} else {
Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(),
request.getPort());
- if (agentByAddressPort != null) {
+ if (agentByAddressPort != null && !agentByAddressPort.getName().equals(request.getName())) {
// the agent request provided information about an authentic agent but it is trying to
// steal another agent's host/port. Thus, we will abort this request.
String msg = "The agent asking for registration [" + request.getName()
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
index 0abbbeb..a3dda5e 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
@@ -119,6 +119,15 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
assert agent.getAddress().equals("hostZdoubleprime");
assert agent.getPort() == 55552;
+ // now don't change Z's host/port but re-register everything the same with its token
+ request = createRequest(zName, "hostZdoubleprime", 55552, results.getAgentToken());
+ results = service.registerAgent(request);
+ assert results != null;
+ agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(zName);
+ assert agent.getAddress().equals("hostZdoubleprime");
+ assert agent.getPort() == 55552;
+
// now don't change Z's host/port but re-register everything the same, but with no token
request = createRequest(zName, "hostZdoubleprime", 55552, null);
results = service.registerAgent(request);
@@ -343,6 +352,8 @@ public class CoreServerServiceImplTest extends AbstractEJB3Test {
MBeanServer mbs = getJBossMBeanServer();
mbs.unregisterMBean(CoreServerMBean.OBJECT_NAME);
+ unprepareForTestAgents();
+
// in case this was set before our tests, put it back the way it was
if (oldServerNamePropertyValue != null) {
System.setProperty(RHQ_SERVER_NAME_PROPERTY, oldServerNamePropertyValue);
commit 6f1033574f6e2541677382373f9960f29f8a2956
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Jan 17 12:04:00 2012 -0500
[BZ 772318] the agent registration process was lax and allowed somethings that it shouldn't have. This closes the known holes and adds unit tests to check that all known use-cases are handled properly.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
index 3b5ecc7..85aa364 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CoreServerServiceImpl.java
@@ -94,9 +94,6 @@ public class CoreServerServiceImpl implements CoreServerService {
// If not, no point in continuing - the server won't be able to talk to the agent anyway.
pingEndpoint(request.getRemoteEndpoint());
- // TODO (ghinkle): Check platform limit - do we still care about this?
- //getPlatformManager().enforceLicenseLimit(args.getCpuCount());
-
Agent agentByName = getAgentManager().getAgentByName(request.getName());
/*
@@ -125,6 +122,38 @@ public class CoreServerServiceImpl implements CoreServerService {
String msg = "The agent asking for registration is already registered with the name ["
+ agentByToken.getName() + "], it cannot change its name to [" + request.getName() + "]";
throw new AgentRegistrationException(msg);
+ } else {
+ Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(),
+ request.getPort());
+ if (agentByAddressPort != null) {
+ // the agent request provided information about an authentic agent but it is trying to
+ // steal another agent's host/port. Thus, we will abort this request.
+ String msg = "The agent asking for registration [" + request.getName()
+ + "] is trying to register the same address/port [" + request.getAddress() + ":"
+ + request.getPort() + "] that is already registered under a different name ["
+ + agentByAddressPort.getName() + "]";
+ throw new AgentRegistrationException(msg);
+ }
+ }
+ } else {
+ if (agentByName != null) {
+ // the agent request provided a name that already is in use by an agent. However, the request
+ // provided a security token that was not assigned to any agent! How can this be? Something is fishy.
+ String msg = "The agent asking for registration under the name [" + request.getName()
+ + "] provided an invalid security token. This request will fail.";
+ throw new AgentRegistrationException(msg);
+ }
+ Agent agentByAddressPort = getAgentManager().getAgentByAddressAndPort(request.getAddress(),
+ request.getPort());
+ if (agentByAddressPort != null) {
+ // the agent request provided a security token but it is an unknown/unused/bogus token.
+ // However, the IP/port it wants to use is already in-use. This sounds fishy. If we let this
+ // go through, this agent with an unknown/bogus token will essentially hijack this IP/port
+ // belonging to an existing agent. If the agent wants to reuse an IP/port already in existence, it should
+ // already know its security token associated with that IP/port. Thus, we will abort this request.
+ String msg = "The agent asking for registration under the name [" + request.getName()
+ + "] is attempting to authenticate using an unknown security token. This request will fail.";
+ throw new AgentRegistrationException(msg);
}
}
} else {
@@ -141,6 +170,22 @@ public class CoreServerServiceImpl implements CoreServerService {
+ "]; if this new agent is actually the same as the original, then re-register with the same name";
throw new AgentRegistrationException(msg);
}
+ } else {
+ if (agentByName != null) {
+ // the name being registered already exists, however, the agent request is trying to set it
+ // to some unknown IP/port combination and there is no security token to authenticate this request!
+ // Therefore, because this agent name is already registered and because this current request
+ // cannot authenticate itself with the proper security token, we fail.
+ String msg = "An agent is trying to register with an existing agent name ["
+ + request.getName()
+ + "]. The registration request is attempting to assign the agent an unknown address/port ["
+ + request.getAddress()
+ + ":"
+ + request.getPort()
+ + "] without providing a valid security token. If you are attempting to re-register this agent, "
+ + "make sure you register with its prior address/port.";
+ throw new AgentRegistrationException(msg);
+ }
}
}
@@ -196,8 +241,8 @@ public class CoreServerServiceImpl implements CoreServerService {
// the agent does not yet exist, we need to create it
try {
- agentByName = new Agent(request.getName(), request.getAddress(), request.getPort(), request
- .getRemoteEndpoint(), generateAgentToken());
+ agentByName = new Agent(request.getName(), request.getAddress(), request.getPort(),
+ request.getRemoteEndpoint(), generateAgentToken());
agentByName.setServer(registeringServer);
agentManager.createAgent(agentByName);
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
new file mode 100644
index 0000000..0abbbeb
--- /dev/null
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/core/CoreServerServiceImplTest.java
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.server.core;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.persistence.Query;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.core.clientapi.server.core.AgentRegistrationException;
+import org.rhq.core.clientapi.server.core.AgentRegistrationRequest;
+import org.rhq.core.clientapi.server.core.AgentRegistrationResults;
+import org.rhq.core.clientapi.server.core.AgentVersion;
+import org.rhq.core.domain.cloud.Server;
+import org.rhq.core.domain.cloud.Server.OperationMode;
+import org.rhq.core.domain.common.ProductInfo;
+import org.rhq.core.domain.resource.Agent;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+
+/**
+ * @author John Mazzitelli
+ */
+@Test
+public class CoreServerServiceImplTest extends AbstractEJB3Test {
+ private static final String TEST_AGENT_NAME_PREFIX = "CoreServerServiceImplTest.Agent";
+ private static final String RHQ_SERVER_NAME_PROPERTY = "rhq.server.high-availability.name";
+ private AgentVersion agentVersion;
+ private Server server;
+ private String oldServerNamePropertyValue = null;
+ private AgentRegistrationRequest aReq = null;
+ private AgentRegistrationResults aResults = null;
+ private AgentRegistrationRequest zReq = null;
+ private AgentRegistrationResults zResults = null;
+
+ private static final int A_PORT = 11111;
+ private static final String A_HOST = "hostA";
+ private static final int B_PORT = 22222;
+ private static final String B_HOST = "hostB";
+
+ public void testNewAgentRegistrationWithOldToken() throws Exception {
+ // this tests the case where someone purged an agent from the DB, but then
+ // changed their mind and want to re-run that agent and re-register it again.
+ // In this case, the agent (if not using --cleanconfig) would still have the old token.
+ // The agent should still be allowed to register again.
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request = createRequest(prefixName("old"), "hostOld", 12345, "oldtoken");
+ AgentRegistrationResults results = service.registerAgent(request);
+ assert results != null : "cannot re-register an old agent";
+ Agent agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(request.getName());
+ assert agent.getAddress().equals(request.getAddress());
+ assert agent.getPort() == request.getPort();
+ LookupUtil.getAgentManager().deleteAgent(agent);
+ }
+
+ public void testChangeAddressPort() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ AgentRegistrationResults results;
+
+ String zName = prefixName("Z");
+
+ // create a new agent Z with host/port of hostZ/55550
+ request = createRequest(zName, "hostZ", 55550, null);
+ results = service.registerAgent(request);
+ assert results != null : "got null results";
+
+ // now change Z's host to hostZprime
+ request = createRequest(zName, "hostZprime", 55550, results.getAgentToken());
+ results = service.registerAgent(request);
+ assert results != null;
+ Agent agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(zName);
+ assert agent.getAddress().equals("hostZprime");
+ assert agent.getPort() == 55550;
+
+ // now change Z's port to 55551
+ request = createRequest(zName, "hostZprime", 55551, results.getAgentToken());
+ results = service.registerAgent(request);
+ assert results != null;
+ agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(zName);
+ assert agent.getAddress().equals("hostZprime");
+ assert agent.getPort() == 55551;
+
+ // now change Z's host/port to hostZdoubleprime/55552
+ request = createRequest(zName, "hostZdoubleprime", 55552, results.getAgentToken());
+ results = service.registerAgent(request);
+ assert results != null;
+ agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(zName);
+ assert agent.getAddress().equals("hostZdoubleprime");
+ assert agent.getPort() == 55552;
+
+ // now don't change Z's host/port but re-register everything the same, but with no token
+ request = createRequest(zName, "hostZdoubleprime", 55552, null);
+ results = service.registerAgent(request);
+ assert results != null;
+ agent = LookupUtil.getAgentManager().getAgentByAgentToken(results.getAgentToken());
+ assert agent.getName().equals(zName);
+ assert agent.getAddress().equals("hostZdoubleprime");
+ assert agent.getPort() == 55552;
+
+ // remember this agent so our later tests can use it
+ zReq = request;
+ zResults = results;
+ }
+
+ @Test(dependsOnMethods = "testChangeAddressPort")
+ public void testNormalAgentRegistration() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ aReq = createRequest(prefixName("A"), A_HOST, A_PORT, null);
+ aResults = service.registerAgent(aReq);
+ assert aResults != null : "got null results";
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testHijackExistingAgentAddressPort() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(prefixName("B"), aReq.getAddress(), aReq.getPort(), null);
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used host/port with new agent name";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testHijackExistingAgentName() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, null);
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name without a token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), null);
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name without a token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, B_PORT, null);
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name without a token";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testHijackExistingAgentAddressPortWithBogusToken() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(prefixName("B"), aReq.getAddress(), aReq.getPort(), "badtoken");
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used host/port with new agent name and invalid token";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testHijackExistingAgentNameWithBogusToken() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(aReq.getName(), aReq.getAddress(), aReq.getPort(), "badtoken");
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name with an invalid token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, "badtoken");
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name with an invalid token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), "badtoken");
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name with an invalid token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, B_PORT, "badtoken");
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack a used agent name with an invalid token";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testHijackExistingAgentNameWithAnotherAgentToken() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(aReq.getName(), aReq.getAddress(), aReq.getPort(), zResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack agent A using Z's token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, aReq.getPort(), zResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack agent A using Z's token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), aReq.getAddress(), B_PORT, zResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack agent A using Z's token";
+ } catch (AgentRegistrationException ok) {
+ }
+ request = createRequest(aReq.getName(), B_HOST, B_PORT, zResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "Should not have been able to hijack agent A using Z's token";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testAgentHijackingAnotherAgentAddressPort() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(aReq.getName(), zReq.getAddress(), zReq.getPort(), aResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "An agent should not have been able to hijack another agent's host/port";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ @Test(dependsOnMethods = "testNormalAgentRegistration")
+ public void testAttemptToChangeAgentName() throws Exception {
+ CoreServerServiceImpl service = new CoreServerServiceImpl();
+ AgentRegistrationRequest request;
+ request = createRequest(prefixName("newName"), zReq.getAddress(), zReq.getPort(), zResults.getAgentToken());
+ try {
+ service.registerAgent(request);
+ assert false : "An agent should not be able to change its name";
+ } catch (AgentRegistrationException ok) {
+ }
+ }
+
+ private AgentRegistrationRequest createRequest(String name, String address, int port, String token) {
+ return new AgentRegistrationRequest(name, address, port, "socket://" + address + ":" + port
+ + "/?rhq.communications.connector.rhqtype=agent", true, token, agentVersion);
+ }
+
+ private String prefixName(String name) {
+ return TEST_AGENT_NAME_PREFIX + name;
+ }
+
+ @BeforeClass
+ public void prepare() throws Exception {
+ // mock the name of our server via the sysprop (in production, this is normally set in rhq-server.properties)
+ oldServerNamePropertyValue = System.getProperty(RHQ_SERVER_NAME_PROPERTY);
+ String newServerNamePropertyValue = "CoreServerServiceImplTest.Server";
+ System.setProperty(RHQ_SERVER_NAME_PROPERTY, newServerNamePropertyValue);
+
+ // mock up our core server MBean that provides information about where the jboss home dir is
+ MBeanServer mbs = getJBossMBeanServer();
+ DummyCoreServer mbean = new DummyCoreServer();
+ mbs.registerMBean(mbean, CoreServerMBean.OBJECT_NAME);
+
+ // in order to register, we need to mock out the agent version file used by the server
+ // to determine the agent version it supports.
+ agentVersion = new AgentVersion("1.2.3", "12345");
+ File agentVersionFile = new File(mbean.getJBossServerHomeDir(),
+ "deploy/rhq.ear/rhq-downloads/rhq-agent/rhq-server-agent-versions.properties");
+ agentVersionFile.getParentFile().mkdirs();
+ agentVersionFile.delete();
+ Properties agentVersionProps = new Properties();
+ agentVersionProps.put("rhq-agent.latest.version", agentVersion.getVersion());
+ agentVersionProps.put("rhq-agent.latest.build-number", agentVersion.getBuild());
+ FileOutputStream fos = new FileOutputStream(agentVersionFile);
+ try {
+ agentVersionProps.store(fos, "This file was created by " + CoreServerServiceImplTest.class.getName());
+ } finally {
+ fos.close();
+ }
+
+ // this mocks out the endpoint ping - the server will think the agent that is registering is up and pingable
+ prepareForTestAgents();
+
+ // mock our server
+ server = new Server();
+ server.setName(newServerNamePropertyValue);
+ server.setAddress("CoreServerServiceImplTest.localhost");
+ server.setPort(12345);
+ server.setSecurePort(12346);
+ server.setOperationMode(OperationMode.NORMAL);
+ int serverId = LookupUtil.getServerManager().create(server);
+ server.setId(serverId);
+ }
+
+ @AfterClass
+ public void unprepare() throws Exception {
+ // clean up any agents we might have created
+ Query q = getEntityManager().createQuery(
+ "select a from Agent a where name like '" + TEST_AGENT_NAME_PREFIX + "%'");
+ List<Agent> doomed = (List<Agent>) q.getResultList();
+ for (Agent deleteMe : doomed) {
+ LookupUtil.getAgentManager().deleteAgent(deleteMe);
+ }
+
+ // cleanup our test server
+ LookupUtil.getCloudManager().updateServerMode(new Integer[] { server.getId() }, OperationMode.DOWN);
+ LookupUtil.getCloudManager().deleteServer(server.getId());
+
+ // shutdown our mock mbean server
+ MBeanServer mbs = getJBossMBeanServer();
+ mbs.unregisterMBean(CoreServerMBean.OBJECT_NAME);
+
+ // in case this was set before our tests, put it back the way it was
+ if (oldServerNamePropertyValue != null) {
+ System.setProperty(RHQ_SERVER_NAME_PROPERTY, oldServerNamePropertyValue);
+ }
+ }
+
+ interface DummyCoreServerMBean extends CoreServerMBean {
+ };
+
+ class DummyCoreServer implements DummyCoreServerMBean {
+
+ @Override
+ public String getName() {
+ return "CoreServer";
+ }
+
+ @Override
+ public int getState() {
+ return 0;
+ }
+
+ @Override
+ public String getStateString() {
+ return "";
+ }
+
+ @Override
+ public void jbossInternalLifecycle(String arg0) throws Exception {
+ }
+
+ @Override
+ public void create() throws Exception {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ public void start() throws Exception {
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ @Override
+ public String getVersion() {
+ return null;
+ }
+
+ @Override
+ public String getBuildNumber() {
+ return null;
+ }
+
+ @Override
+ public Date getBootTime() {
+ return null;
+ }
+
+ @Override
+ public File getInstallDir() {
+ return null;
+ }
+
+ @Override
+ public File getJBossServerHomeDir() {
+ return new File(System.getProperty("java.io.tmpdir"), "CoreServerServiceImplTest");
+ }
+
+ @Override
+ public File getJBossServerDataDir() {
+ return null;
+ }
+
+ @Override
+ public File getJBossServerTempDir() {
+ return null;
+ }
+
+ @Override
+ public ProductInfo getProductInfo() {
+ return null;
+ }
+ }
+}
commit e5d30c973fd0c8e7410c331ebdd991d330f4049c
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 17 14:10:50 2012 +0100
Use the secured script engine in the JNDI integration tests.
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
index f20d4f1..c6140a0 100644
--- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
@@ -177,11 +177,7 @@ public class JndiAccessTest extends AbstractEJB3Test {
private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
- ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
-
- PermissionCollection perms = new StandardScriptPermissions();
-
- return new SandboxedScriptEngine(engine, perms);
+ return ScriptEngineFactory.getSecuredScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings, new StandardScriptPermissions());
}
private static void checkIsDesiredSecurityException(ScriptException e) {
commit 2c9a0b72daaefbab9697d0a14494106a957b2dac
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 16 15:47:14 2012 -0500
[Bug 769719 - resource key not HTML-escaped in search results and resource detail]
Treat the key value as needing to be html escaped in the resource
overview and search views. Although, it is not typically displayed in
search results anyway.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java
index c60236c..27db60f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/table/EscapedHtmlCellFormatter.java
@@ -2,7 +2,7 @@ package org.rhq.enterprise.gui.coregui.client.components.table;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGridRecord;
-import org.rhq.enterprise.gui.coregui.client.ImageManager;
+
import org.rhq.enterprise.gui.coregui.client.util.StringUtility;
/**
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java
index c9210e9..a164620 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/ResourceSearchView.java
@@ -139,38 +139,40 @@ public class ResourceSearchView extends Table {
List<ListGridField> fields = createFields();
setListGridFields(fields.toArray(new ListGridField[fields.size()]));
- addTableAction(extendLocatorId("Uninventory"), MSG.common_button_uninventory(), MSG
- .view_inventory_resources_uninventoryConfirm(), new ResourceAuthorizedTableAction(ResourceSearchView.this,
- TableActionEnablement.ANY, Permission.DELETE_RESOURCE, new RecordExtractor<Integer>() {
-
- public Collection<Integer> extract(Record[] records) {
- List<Integer> result = new ArrayList<Integer>(records.length);
- for (Record record : records) {
- result.add(record.getAttributeAsInt("id"));
+ addTableAction(extendLocatorId("Uninventory"), MSG.common_button_uninventory(),
+ MSG.view_inventory_resources_uninventoryConfirm(), new ResourceAuthorizedTableAction(
+ ResourceSearchView.this, TableActionEnablement.ANY, Permission.DELETE_RESOURCE,
+ new RecordExtractor<Integer>() {
+
+ public Collection<Integer> extract(Record[] records) {
+ List<Integer> result = new ArrayList<Integer>(records.length);
+ for (Record record : records) {
+ result.add(record.getAttributeAsInt("id"));
+ }
+
+ return result;
}
+ }) {
- return result;
- }
- }) {
-
- public void executeAction(ListGridRecord[] selection, Object actionValue) {
- int[] resourceIds = TableUtility.getIds(selection);
- ResourceGWTServiceAsync resourceManager = GWTServiceLookup.getResourceService();
+ public void executeAction(ListGridRecord[] selection, Object actionValue) {
+ int[] resourceIds = TableUtility.getIds(selection);
+ ResourceGWTServiceAsync resourceManager = GWTServiceLookup.getResourceService();
- resourceManager.uninventoryResources(resourceIds, new AsyncCallback<List<Integer>>() {
- public void onFailure(Throwable caught) {
- CoreGUI.getErrorHandler().handleError(MSG.view_inventory_resources_uninventoryFailed(), caught);
- }
+ resourceManager.uninventoryResources(resourceIds, new AsyncCallback<List<Integer>>() {
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_inventory_resources_uninventoryFailed(),
+ caught);
+ }
- public void onSuccess(List<Integer> result) {
- CoreGUI.getMessageCenter().notify(
- new Message(MSG.view_inventory_resources_uninventorySuccessful(), Severity.Info));
+ public void onSuccess(List<Integer> result) {
+ CoreGUI.getMessageCenter().notify(
+ new Message(MSG.view_inventory_resources_uninventorySuccessful(), Severity.Info));
- onUninventorySuccess();
- }
- });
- }
- });
+ onUninventorySuccess();
+ }
+ });
+ }
+ });
setListGridDoubleClickHandler(new DoubleClickHandler() {
public void onDoubleClick(DoubleClickEvent event) {
@@ -226,6 +228,7 @@ public class ResourceSearchView extends Table {
fields.add(nameField);
ListGridField keyField = new ListGridField(KEY.propertyName(), KEY.title(), 170);
+ keyField.setCellFormatter(new EscapedHtmlCellFormatter());
fields.add(keyField);
ListGridField ancestryField = AncestryUtil.setupAncestryListGridField();
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/OverviewForm.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/OverviewForm.java
index 3db8f68..50bf723 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/OverviewForm.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/OverviewForm.java
@@ -40,8 +40,8 @@ import org.rhq.core.domain.resource.composite.ResourceComposite;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.components.form.EditableFormItem;
import org.rhq.enterprise.gui.coregui.client.components.form.EnhancedDynamicForm;
-import org.rhq.enterprise.gui.coregui.client.components.form.StringLengthValidator;
import org.rhq.enterprise.gui.coregui.client.components.form.SimpleEditableFormItem.ValueEditedHandler;
+import org.rhq.enterprise.gui.coregui.client.components.form.StringLengthValidator;
import org.rhq.enterprise.gui.coregui.client.components.table.TimestampCellFormatter;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.ResourceGWTServiceAsync;
@@ -153,6 +153,7 @@ public class OverviewForm extends EnhancedDynamicForm {
// Key
StaticTextItem keyItem = new StaticTextItem(ResourceDataSourceField.KEY.propertyName(),
ResourceDataSourceField.KEY.title());
+ keyItem.setAttribute(OUTPUT_AS_HTML_ATTRIBUTE, true);
keyItem.setValue(resource.getResourceKey());
formItems.add(keyItem);
@@ -189,8 +190,8 @@ public class OverviewForm extends EnhancedDynamicForm {
public void onSuccess(Void result) {
titleBar.displayResourceName(newName);
CoreGUI.getMessageCenter().notify(
- new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(String
- .valueOf(resource.getId()), oldName, newName), Message.Severity.Info));
+ new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(
+ String.valueOf(resource.getId()), oldName, newName), Message.Severity.Info));
}
});
}
@@ -218,8 +219,8 @@ public class OverviewForm extends EnhancedDynamicForm {
OverviewForm.this.resourceService.updateResource(resource, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(
- MSG.view_summaryOverviewForm_error_descriptionChangeFailure(String.valueOf(resource
- .getId()), oldDescription, newDescription), caught);
+ MSG.view_summaryOverviewForm_error_descriptionChangeFailure(
+ String.valueOf(resource.getId()), oldDescription, newDescription), caught);
// We failed to update it on the Server, so change back the Resource and the form item to
// the original value.
resource.setDescription(oldDescription);
@@ -227,11 +228,10 @@ public class OverviewForm extends EnhancedDynamicForm {
}
public void onSuccess(Void result) {
- CoreGUI.getMessageCenter()
- .notify(
- new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(String
- .valueOf(resource.getId()), oldDescription, newDescription),
- Message.Severity.Info));
+ CoreGUI.getMessageCenter().notify(
+ new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(
+ String.valueOf(resource.getId()), oldDescription, newDescription),
+ Message.Severity.Info));
}
});
}
@@ -259,8 +259,8 @@ public class OverviewForm extends EnhancedDynamicForm {
OverviewForm.this.resourceService.updateResource(resource, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(
- MSG.view_summaryOverviewForm_error_locationChangeFailure(String.valueOf(resource
- .getId()), oldLocation, newLocation), caught);
+ MSG.view_summaryOverviewForm_error_locationChangeFailure(
+ String.valueOf(resource.getId()), oldLocation, newLocation), caught);
// We failed to update it on the Server, so change back the Resource and the form item to
// the original value.
resource.setLocation(oldLocation);
@@ -268,9 +268,11 @@ public class OverviewForm extends EnhancedDynamicForm {
}
public void onSuccess(Void result) {
- CoreGUI.getMessageCenter().notify(
- new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(String
- .valueOf(resource.getId()), oldLocation, newLocation), Message.Severity.Info));
+ CoreGUI.getMessageCenter()
+ .notify(
+ new Message(MSG.view_summaryOverviewForm_message_nameChangeSuccess(
+ String.valueOf(resource.getId()), oldLocation, newLocation),
+ Message.Severity.Info));
}
});
}
commit 13546f899490b333b4527ce963d1b39b3a097153
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 16 13:45:09 2012 -0500
[Bug 758503 - Various AS-5 plugin types have unset read-only plugin config props]
required/read-only contextPath and filename props were not being set
[reliably] at discovery time. Removed filename props, which did not seem
to be used by the plugin. Set contextPath props to required="false".
The value does not seem to be used by the plugin but the property is
at least defined in the code.
diff --git a/modules/plugins/jboss-as-5/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/jboss-as-5/src/main/resources/META-INF/rhq-plugin.xml
index 2729d31..bac3e20 100644
--- a/modules/plugins/jboss-as-5/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/jboss-as-5/src/main/resources/META-INF/rhq-plugin.xml
@@ -2278,7 +2278,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="The name of this EAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="ear" readOnly="true"/>
@@ -2335,8 +2334,8 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this WAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
- <c:simple-property name="contextPath" description="this WAR's context path (e.g. /admin-console)" readOnly="true"/>
+ <!-- setting to required=false since this is not usually set properly at discovery time -->
+ <c:simple-property name="contextPath" description="this WAR's context path (e.g. /admin-console)" required="false" readOnly="false"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="war" readOnly="true"/>
@@ -2418,7 +2417,8 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this WAR" readOnly="true"/>
- <c:simple-property name="contextPath" description="this WAR's context path (e.g. /admin-console" readOnly="true"/>
+ <!-- setting to required=false since this is not usually set properly at discovery time -->
+ <c:simple-property name="contextPath" description="this WAR's context path (e.g. /admin-console" required="false" readOnly="false"/>
</c:group>
<c:group name="ResponseTime">
<c:simple-property name="responseTimeLogFile" required="false"
@@ -2485,7 +2485,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this EJB JAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="jar" readOnly="true"/>
@@ -2581,7 +2580,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this EJB JAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="jar" readOnly="true"/>
@@ -2654,7 +2652,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this EJB JAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="jar" readOnly="true"/>
@@ -2731,7 +2728,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this EJB JAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="jar" readOnly="true"/>
@@ -2793,7 +2789,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this RAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="rar" readOnly="true"/>
@@ -2839,7 +2834,6 @@
<plugin-configuration>
<c:group name="general" displayName="General">
<c:simple-property name="deploymentName" description="the name of this RAR" readOnly="true"/>
- <c:simple-property name="filename" readOnly="true"/>
</c:group>
<c:group name="advanced" displayName="Advanced" hiddenByDefault="true">
<c:simple-property name="extension" default="rar" readOnly="true"/>
commit 5b4ab4a5a34811b157ab8bcb889aa2f4a0274302
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 16 13:41:23 2012 +0100
Fixing the JNDI integration test's pom.
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
index 1991e0e..fad4127 100644
--- a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
+++ b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
@@ -80,6 +80,12 @@
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
@@ -94,6 +100,12 @@
<artifactId>rhq-server-client-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
@@ -300,7 +312,7 @@
<jnp.port>${jnp.port}</jnp.port>
<jnp.rmiPort>${jnp.rmiPort}</jnp.rmiPort>
</systemPropertyVariables>
- <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
+ <argLine>-Djava.security.manager -Djava.security.policy==${basedir}/target/test-classes/security.policy</argLine>
<additionalClasspathElements>
<!-- The below is required for tests to run against
Oracle. -->
commit eeeb3156b6b66fb4ead5cadec1f4eb3aa0af18c5
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 16 12:24:39 2012 +0100
Adding missing module references to the integration tests profile.
diff --git a/modules/pom.xml b/modules/pom.xml
index f0eaeef..ba4d1b5 100644
--- a/modules/pom.xml
+++ b/modules/pom.xml
@@ -156,9 +156,19 @@
<module>core</module>
<module>common</module>
<module>plugins</module>
+
<!-- these two are needed by the rhq-agent plugin -->
<module>enterprise/agent</module>
<module>enterprise/comm</module>
+
+ <!-- These 6 are needed for the JNDI intergration tests -->
+ <module>enterprise/server/container-lib</module>
+ <module>enterprise/server/xml-schemas</module>
+ <module>enterprise/server/safe-invoker</module>
+ <module>enterprise/server/jar</module>
+ <module>enterprise/binding</module>
+ <module>enterprise/server/client-api</module>
+
<module>integration-tests</module>
</modules>
</profile>
commit a5d162e2e77b65945eb56e0800b380de93ca1bba
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sun Jan 15 14:32:14 2012 +0100
Fix a small issue with opacity, that prevented the dots to show.
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
index 0f38577..4ff8174 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
@@ -160,12 +160,14 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
var line = d3.svg.line()
.x(function(d,i) { return x(d.timeStamp-dayMinTs); })
- .y(function(d) { return y(d.value); })
- lines.append("svg:path").attr("d", line(daydat)).style("stroke",colors[day]);
+ .y(function(d) { return y(d.value); });
+ lines.append("svg:path")
+ .attr("d", line(daydat))
+ .style("stroke",colors[day]);
var dot = svg.append("svg:g").attr("class","dotschart")
- .selectAll("dot").data(jsondata)
+ .selectAll("dot").data(jsondata);
dot.enter().append("svg:circle")
.attr("cx", function (d) {
@@ -175,8 +177,7 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
return y(d.value);
})
.style("stroke", colors[day])
- .attr("r", 1)
- .attr("opacity","0")
+ .attr("r", 1);
}
});
commit a6015157d51f146e824898b60108d5ea03ec030a
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sun Jan 15 14:31:32 2012 +0100
Allow to get and set baselines.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index 71a6a45..53255a6 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -36,6 +36,8 @@ import java.util.Set;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -62,6 +64,7 @@ import org.jboss.cache.Fqn;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.measurement.DataType;
+import org.rhq.core.domain.measurement.MeasurementBaseline;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.MeasurementSchedule;
@@ -70,6 +73,7 @@ import org.rhq.core.util.jdbc.JDBCUtil;
import org.rhq.enterprise.server.RHQConstants;
import org.rhq.enterprise.server.measurement.util.MeasurementDataManagerUtility;
import org.rhq.enterprise.server.resource.ResourceManagerLocal;
+import org.rhq.enterprise.server.rest.domain.Baseline;
import org.rhq.enterprise.server.rest.domain.Link;
import org.rhq.enterprise.server.rest.domain.MetricAggregate;
import org.rhq.enterprise.server.measurement.MeasurementAggregate;
@@ -93,6 +97,8 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
MeasurementScheduleManagerLocal scheduleManager;
@EJB
ResourceManagerLocal resMgr;
+ @PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
+ EntityManager em;
@javax.annotation.Resource(name = "RHQ_DS")
private DataSource rhqDs;
@@ -114,7 +120,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
startTime = endTime - EIGHT_HOURS;
}
- MeasurementSchedule schedule = obtainSchedule(scheduleId);
+ MeasurementSchedule schedule = obtainSchedule(scheduleId, false);
MeasurementAggregate aggr = dataManager.getAggregate(caller, scheduleId, startTime, endTime);
MetricAggregate res = new MetricAggregate(scheduleId, aggr.getMin(),aggr.getAvg(),aggr.getMax());
@@ -149,13 +155,16 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
/**
* Get the schedule for the passed schedule id
+ *
* @param scheduleId id to look up
+ * @param force
* @return schedule
* @throws StuffNotFoundException if there is no schedule with the passed id
*/
- private MeasurementSchedule obtainSchedule(int scheduleId) {
- MeasurementSchedule schedule;
- schedule = getFromCache(scheduleId,MeasurementSchedule.class);
+ private MeasurementSchedule obtainSchedule(int scheduleId, boolean force) {
+ MeasurementSchedule schedule=null;
+ if(!force)
+ schedule = getFromCache(scheduleId,MeasurementSchedule.class);
if (schedule==null) {
schedule = scheduleManager.getScheduleById(caller,scheduleId);
if (schedule==null) {
@@ -419,7 +428,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
throw new IllegalArgumentException("Start time is older than 7 days");
// Check if the schedule exists
- obtainSchedule(scheduleId);
+ obtainSchedule(scheduleId, false);
RawNumericStreamingOutput so = new RawNumericStreamingOutput();
so.scheduleId = scheduleId;
@@ -441,7 +450,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
NumericDataPoint point, @Context HttpHeaders headers, UriInfo uriInfo) {
MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
- MeasurementSchedule schedule = obtainSchedule(scheduleId);
+ MeasurementSchedule schedule = obtainSchedule(scheduleId, false);
Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>(1);
data.add(new MeasurementDataNumeric(point.getTimeStamp(),scheduleId,point.getValue()));
@@ -476,6 +485,50 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
}
+ @Override
+ @GET
+ @Path("data/{scheduleId}/baseline")
+ public Baseline getBaseline(@PathParam("scheduleId") int scheduleId, @Context HttpHeaders headers,
+ @Context UriInfo uriInfo) {
+ MeasurementSchedule schedule = obtainSchedule(scheduleId, true);
+ MeasurementBaseline mBase = schedule.getBaseline();
+
+ Baseline b;
+ if (mBase==null)
+ throw new StuffNotFoundException("Baseline for schedule [" + scheduleId +"]");
+ else
+ b = new Baseline(mBase.getMin(),mBase.getMax(),mBase.getMean(),mBase.getComputeTime().getTime());
+ return b;
+
+ }
+
+ @Override
+ @PUT
+ @Path("data/{scheduleId}/baseline")
+ public void setBaseline(@PathParam("scheduleId") int scheduleId,
+ Baseline baseline, HttpHeaders headers, @Context UriInfo uriInfo) {
+ MeasurementSchedule schedule = obtainSchedule(scheduleId, false);
+
+ // little bit of sanity checking
+ if (baseline.getMin()>baseline.getMean() || baseline.getMean()>baseline.getMax() || baseline.getMin()>baseline.getMax())
+ throw new IllegalArgumentException("Baseline not correct. it should be min<=mean<=max");
+
+ MeasurementBaseline mBase = schedule.getBaseline();
+ if (mBase == null) {
+ mBase = new MeasurementBaseline();
+ mBase.setSchedule(schedule);
+ schedule.setBaseline(mBase);
+ em.persist(mBase);
+ }
+ mBase.setMax(baseline.getMax());
+ mBase.setMin(baseline.getMin());
+ mBase.setMean(baseline.getMean());
+ mBase.setUserEntered(true);
+
+ scheduleManager.updateSchedule(caller,schedule);
+
+ }
+
/**
* Write the numeric data points to the output stream in JSON encoding
* without creating tons of objects in the middle to have them marshalled
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
index 6f76bce..6d9c174 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
@@ -39,6 +39,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
+import org.rhq.enterprise.server.rest.domain.Baseline;
import org.rhq.enterprise.server.rest.domain.MetricAggregate;
import org.rhq.enterprise.server.rest.domain.MetricSchedule;
import org.rhq.enterprise.server.rest.domain.NumericDataPoint;
@@ -155,4 +156,19 @@ public interface MetricHandlerLocal {
@Path("data/raw")
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
Response postMetricValues(Collection<NumericDataPoint> points, @Context HttpHeaders headers);
+
+ @GET
+ @Path("data/{scheduleId}/baseline")
+ @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
+ Baseline getBaseline(@PathParam("scheduleId") int scheduleId,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo);
+
+ @PUT
+ @Path("data/{scheduleId}/baseline")
+ @Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
+ void setBaseline(@PathParam("scheduleId") int scheduleId,
+ Baseline baseline,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo);
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java
new file mode 100644
index 0000000..d6a4073
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/Baseline.java
@@ -0,0 +1,58 @@
+package org.rhq.enterprise.server.rest.domain;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * A baseline
+ * @author Heiko W. Rupp
+ */
+@XmlRootElement
+public class Baseline {
+
+ double min;
+ double max;
+ double mean;
+ long computeTime;
+
+ public Baseline() {
+ }
+
+ public Baseline(double min, double max, double mean, long computeTime) {
+ this.min = min;
+ this.max = max;
+ this.mean = mean;
+ this.computeTime = computeTime;
+ }
+
+ public double getMin() {
+ return min;
+ }
+
+ public void setMin(double min) {
+ this.min = min;
+ }
+
+ public double getMax() {
+ return max;
+ }
+
+ public void setMax(double max) {
+ this.max = max;
+ }
+
+ public double getMean() {
+ return mean;
+ }
+
+ public void setMean(double mean) {
+ this.mean = mean;
+ }
+
+ public long getComputeTime() {
+ return computeTime;
+ }
+
+ public void setComputeTime(long computeTime) {
+ this.computeTime = computeTime;
+ }
+}
commit 10051994173b5b1467155bb957b7c4dbd579011c
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sun Jan 15 13:55:51 2012 +0100
BZ 781801 - if frequency is 0 print a note and return.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementBaselineManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementBaselineManagerBean.java
index 286a75e..1d64102 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementBaselineManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementBaselineManagerBean.java
@@ -115,7 +115,12 @@ public class MeasurementBaselineManagerBean implements MeasurementBaselineManage
// Determine how much data we need to calculate baselines for by determining the oldest and youngest
// measurement data to include in the calculations.
long amountOfData = Long.parseLong(baselineDataSetString);
- long baselinesOlderThanTime = System.currentTimeMillis() - Long.parseLong(baselineFrequencyString);
+ long baselineFrequency = Long.parseLong(baselineFrequencyString);
+ if (baselineFrequency==0) {
+ log.info("Baseline frequency is set to 0 - not recomputing baselines. Go to Admin->System settings to change this.");
+ return;
+ }
+ long baselinesOlderThanTime = System.currentTimeMillis() - baselineFrequency;
measurementBaselineManager.calculateAutoBaselines(amountOfData, baselinesOlderThanTime);
@@ -147,20 +152,20 @@ public class MeasurementBaselineManagerBean implements MeasurementBaselineManage
now = System.currentTimeMillis();
int totalInserted = 0;
while (true) {
- /*
+ /*
* each call is done in a separate xtn of at most 100K inserted rows; this helps to keep the xtn
* shorter to avoid timeouts in scenarios where baseline calculations bunch together. the idea was that
- * by basing a batch of baseline calculations off of the import time of the resource into inventory,
+ * by basing a batch of baseline calculations off of the import time of the resource into inventory,
* that the total work would naturally be staggered throughout the day. in practice, this didn't always
* work as intended for one of several reasons:
- *
- * 1) all servers in the cloud were down for a few days (maybe a slow product upgrade, maybe a cold
+ *
+ * 1) all servers in the cloud were down for a few days (maybe a slow product upgrade, maybe a cold
* data center relocation)
* 2) issues with running the job itself, if quartz had locking issues under severe load and somehow
* this job wasn't get executed for a few hours / days
* 3) the user tended to import all new resources / platforms at the same time of day, thus bypassing
* the implicit optimization of trying to stagger the calculations by resource commit time
- *
+ *
* 2/18/2010 NOTE: Limits weren't / aren't actually achieving the affect we want. The baseline query
* follows the general form of "insert into...select from <big query> having <subquery> limit X".
* In this case, the limit was reducing the number of rows inserted, but it was still taking the full
@@ -169,20 +174,20 @@ public class MeasurementBaselineManagerBean implements MeasurementBaselineManage
* part - the "big query". What we actually want to do is come of with a strategy that lessens the
* amount of data we need to select, thereby reducing the amount of time it takes to calculate the
* insertion list.
- *
+ *
* One proposed strategy for this would be to chunk on the scheduleId. So if there were, say,
* 5M scheduleIds in the systems, we might take 500K of them at a time and then execute the
* baseline insertion job 10 times against a much smaller set of data each time. But the
* complication here is how to calculate precise groups of 500K schedules at a time, and then
* walk that chunked list.
- *
+ *
* Another strategy would be to divy things up by resource type. Since a measurementSchedule is
* linked to a measurementDefinition which is linked to a resourceType, we could very easily chunk
* the insertion based off the schedules that belong to each resourceType. This would create
* one insert statement for each type of resource in system. The complication here, however,
* is that you may have millions of resources of one type, but hardly any resources of another.
* So there's still a chance that some insertions proceed slowly (in the worst case).
- *
+ *
* In any event, an appropriate chunking solution needs to be found, and that partitioning strategy
* needs to replace the limits in the query today.
*/
commit b68ebef3089a2358a64d1594c0357cd076ef4cf8
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Fri Jan 13 17:35:16 2012 -0500
[BZ 692948] config comparator GWT view now compares list-o-maps and maps
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java
index 15e0fb1..cbf4059 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/components/configuration/ConfigurationComparisonView.java
@@ -37,10 +37,14 @@ import com.smartgwt.client.widgets.tree.TreeNode;
import org.rhq.core.domain.configuration.AbstractPropertyMap;
import org.rhq.core.domain.configuration.AbstractResourceConfigurationUpdate;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.Property;
+import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.ResourceConfigurationUpdate;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.PropertyDefinition;
+import org.rhq.core.domain.configuration.definition.PropertyDefinitionList;
+import org.rhq.core.domain.configuration.definition.PropertyDefinitionMap;
import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple;
import org.rhq.core.domain.configuration.definition.PropertyGroupDefinition;
import org.rhq.core.domain.resource.ResourceType;
@@ -53,6 +57,8 @@ import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableWindow;
* @author Greg Hinkle
*/
public class ConfigurationComparisonView extends VLayout {
+ private static final String ATTRIB_ALL_SAME = "consistent";
+
private static final Messages MSG = CoreGUI.getMessages();
private ConfigurationDefinition definition;
@@ -83,7 +89,7 @@ public class ConfigurationComparisonView extends VLayout {
nameField.setFrozen(true);
nameField.setCellFormatter(new CellFormatter() {
public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
- if (listGridRecord == null || listGridRecord.getAttributeAsBoolean("consistent")) {
+ if (listGridRecord == null || listGridRecord.getAttributeAsBoolean(ATTRIB_ALL_SAME)) {
return String.valueOf(o);
} else {
return "<span style=\"color: red;\">" + String.valueOf(o) + "</span>";
@@ -103,7 +109,7 @@ public class ConfigurationComparisonView extends VLayout {
public String format(Object o, ListGridRecord listGridRecord, int i, int i1) {
if (!(listGridRecord instanceof ComparisonTreeNode)) {
return "";
- } else if (listGridRecord.getAttributeAsBoolean("consistent")) {
+ } else if (listGridRecord.getAttributeAsBoolean(ATTRIB_ALL_SAME)) {
return String.valueOf(o);
} else {
return "<span style=\"color: red;\">" + String.valueOf(o) + "</span>";
@@ -135,9 +141,7 @@ public class ConfigurationComparisonView extends VLayout {
}
for (PropertyGroupDefinition group : definition.getGroupDefinitions()) {
-
TreeNode groupNode = new TreeNode(group.getDisplayName());
-
buildNode(groupNode, definition.getPropertiesInGroup(group.getName()), configs);
children.add(groupNode);
}
@@ -152,23 +156,79 @@ public class ConfigurationComparisonView extends VLayout {
List<? extends AbstractPropertyMap> maps) {
ArrayList<TreeNode> children = new ArrayList<TreeNode>();
- parent.setAttribute("consistent", true);
+ parent.setAttribute(ATTRIB_ALL_SAME, true);
for (PropertyDefinition definition : definitions) {
if (definition instanceof PropertyDefinitionSimple) {
-
ArrayList<PropertySimple> properties = new ArrayList<PropertySimple>();
for (AbstractPropertyMap map : maps) {
properties.add(map.getSimple(definition.getName()));
}
ComparisonTreeNode node = new ComparisonTreeNode((PropertyDefinitionSimple) definition, properties,
titles);
- if (!node.getAttributeAsBoolean("consistent")) {
- parent.setAttribute("consistent", false);
+ if (!node.getAttributeAsBoolean(ATTRIB_ALL_SAME)) {
+ parent.setAttribute(ATTRIB_ALL_SAME, false);
}
children.add(node);
+ } else if (definition instanceof PropertyDefinitionMap) {
+ PropertyDefinitionMap defMap = (PropertyDefinitionMap) definition;
+ TreeNode mapNode = new TreeNode(defMap.getDisplayName());
+ ArrayList<PropertyMap> properties = new ArrayList<PropertyMap>();
+ for (AbstractPropertyMap map : maps) {
+ properties.add((PropertyMap) map);
+ }
+ buildNode(mapNode, defMap.getPropertyDefinitions().values(), properties);
+ if (!mapNode.getAttributeAsBoolean(ATTRIB_ALL_SAME)) {
+ parent.setAttribute(ATTRIB_ALL_SAME, false);
+ }
+ children.add(mapNode);
+ } else if (definition instanceof PropertyDefinitionList) {
+ PropertyDefinitionList defList = (PropertyDefinitionList) definition;
+ TreeNode listNode = new TreeNode(defList.getDisplayName());
+ listNode.setAttribute(ATTRIB_ALL_SAME, true);
+ if (defList.getMemberDefinition() instanceof PropertyDefinitionMap) { // support list-o-maps only
+ PropertyDefinition memberDef = defList.getMemberDefinition();
+ Collection<PropertyDefinition> memberDefColl = new ArrayList<PropertyDefinition>(1);
+ memberDefColl.add(memberDef);
+
+ int max = 0; // will be the largest size of any of our lists that are being compared
+ for (AbstractPropertyMap map : maps) {
+ try {
+ int size = map.getList(defList.getName()).getList().size();
+ if (size > max) {
+ max = size;
+ }
+ } catch (Throwable t) {
+ // paranoia - just skip so we don't kill entire compare window if our config doesn't have proper list-o-map
+ }
+ }
+ ArrayList<TreeNode> innerChildren = new ArrayList<TreeNode>();
+ for (int i = 0; i < max; i++) {
+ TreeNode listItemNode = new TreeNode(String.valueOf(i));
+ ArrayList<PropertyMap> properties = new ArrayList<PropertyMap>();
+ for (AbstractPropertyMap map : maps) {
+ try {
+ List<Property> list = map.getList(defList.getName()).getList();
+ if (list.size() < (i + 1)) {
+ properties.add(new PropertyMap()); // this list didn't have an i-th item, just use an empty map
+ } else {
+ properties.add((PropertyMap) list.get(i));
+ }
+ } catch (Throwable t) {
+ // paranoia - just skip so we don't kill entire compare window if our config doesn't have proper list-o-map
+ properties.add(new PropertyMap());
+ }
+ }
+ buildNode(listItemNode, memberDefColl, properties);
+ if (!listItemNode.getAttributeAsBoolean(ATTRIB_ALL_SAME)) {
+ parent.setAttribute(ATTRIB_ALL_SAME, false);
+ listNode.setAttribute(ATTRIB_ALL_SAME, false); // any diffs always causes this to indicate the diff
+ }
+ innerChildren.add(listItemNode);
+ }
+ listNode.setChildren(innerChildren.toArray(new TreeNode[innerChildren.size()]));
+ }
+ children.add(listNode);
}
-
- // TODO Add support for maps and lists of maps
}
parent.setChildren(children.toArray(new TreeNode[children.size()]));
}
@@ -232,25 +292,15 @@ public class ConfigurationComparisonView extends VLayout {
private static class ComparisonTreeNode extends TreeNode {
- PropertyDefinitionSimple definition;
- List<PropertySimple> properties;
-
private ComparisonTreeNode(PropertyDefinitionSimple definition, List<PropertySimple> properties,
List<String> titles) {
super(definition.getDisplayName());
-
- this.definition = definition;
- this.properties = properties;
-
setAttribute("type", definition.getType().name());
-
int i = 0;
boolean allTheSame = true;
String commonValue = null;
for (PropertySimple prop : properties) {
-
String value = prop != null ? prop.getStringValue() : null;
-
if (i == 0) {
commonValue = value;
} else if (allTheSame && commonValue == null && value != null
@@ -258,8 +308,7 @@ public class ConfigurationComparisonView extends VLayout {
allTheSame = false;
}
setAttribute(titles.get(i++), value);
-
- setAttribute("consistent", allTheSame);
+ setAttribute(ATTRIB_ALL_SAME, allTheSame);
}
}
}
commit ed0187d752ee3c47db6a7ac3b5b6566887ddc119
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Fri Jan 13 16:40:32 2012 -0500
[BZ 781621] fixing ldap ssl issue. Users unable to configure SSL support.
This was introduced with the other SystemSettings refactor changes. We thought we'd found all the places affected.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java
index d1f2294..fc09b0f 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/core/CustomJaasDeploymentService.java
@@ -165,7 +165,7 @@ public class CustomJaasDeploymentService implements CustomJaasDeploymentServiceM
configOptions.put(Context.INITIAL_CONTEXT_FACTORY, conf.getProperty(RHQConstants.LDAPFactory));
configOptions.put(Context.PROVIDER_URL, conf.getProperty(RHQConstants.LDAPUrl));
String value = conf.getProperty(SystemSetting.USE_SSL_FOR_LDAP.getInternalName());
- boolean ldapSsl = Boolean.TRUE.toString().equals(value);
+ boolean ldapSsl = "ssl".equalsIgnoreCase(value);
configOptions.put(Context.SECURITY_PROTOCOL, (ldapSsl) ? "ssl" : null);
configOptions.put("LoginProperty", conf.getProperty(RHQConstants.LDAPLoginProperty));
configOptions.put("Filter", conf.getProperty(RHQConstants.LDAPFilter));
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/LdapGroupManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/LdapGroupManagerBean.java
index 396b2c8..9dd2eb5 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/LdapGroupManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/group/LdapGroupManagerBean.java
@@ -443,7 +443,7 @@ public class LdapGroupManagerBean implements LdapGroupManagerLocal {
// Setup SSL if requested
String value = env.getProperty(SystemSetting.USE_SSL_FOR_LDAP.getInternalName());
- boolean ldapSsl = Boolean.TRUE.toString().equals(value);
+ boolean ldapSsl = "ssl".equalsIgnoreCase(value);
if (ldapSsl) {
String ldapSocketFactory = env.getProperty("java.naming.ldap.factory.socket");
if (ldapSocketFactory == null) {
commit a509359864fcdd3f19c37db99d62414181cc3bef
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Jan 13 17:18:53 2012 +0100
BZ 734495 - allow to provide JAVA_HOME
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 99c8cee..60f819f 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
@@ -113,6 +113,10 @@ public class BaseServerComponent extends BaseComponent {
processExecution.setWaitForCompletion(15000L); // 15 seconds // TODO: Should we wait longer than 15 seconds?
processExecution.setKillOnTimeout(false);
+ String javaHomeDir = pluginConfiguration.getSimpleValue("javaHomePath",null);
+ if (javaHomeDir!=null) {
+ processExecution.getEnvironmentVariables().put("JAVA_HOME", javaHomeDir);
+ }
if (log.isDebugEnabled()) {
log.debug("About to execute the following process: [" + processExecution + "]");
@@ -121,6 +125,8 @@ public class BaseServerComponent extends BaseComponent {
logExecutionResults(results);
if (results.getError()!=null) {
operationResult.setErrorMessage(results.getError().getMessage());
+ } else if (results.getExitCode()!=null) {
+ operationResult.setErrorMessage("Start failed with error code " + results.getExitCode() + ":\n" + results.getCapturedOutput());
} else {
operationResult.setSimpleResult("Success");
}
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 7e88906..bdcf227 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
@@ -70,6 +70,10 @@
<c:simple-property name="hostConfig" type="string" default="host.xml" description="Running configuration (host part)" displayName="Host Configuration"/>
<c:simple-property name="baseDir" type="file" description="Base directory of the server installation" displayName="Base directory" readOnly="true" required="false"/>
<c:simple-property name="startScript" type="file" default="bin/domain.sh" description="Script used to start the server. If the path is not absolute, it is relative to the base directory"/>
+ <c:simple-property name="javaHomePath" type="file" displayName="JAVA_HOME Path" required="false"
+ description="The absolute path to a JRE or JDK installation directory containing
+ the JVM that should be used to start and shutdown the HostController instance;
+ defaults to the home directory of the RHQ agent JRE."/>
<c:simple-property name="domainHost" type="string" readOnly="true" required="false" description="Host name within the AS7 domain"/>
&logSources;
@@ -330,6 +334,10 @@
<c:simple-property name="config" type="string" default="standalone.xml" description="Running configuration" displayName="Configuration"/>
<c:simple-property name="baseDir" type="file" description="Base directory of the server installation" displayName="Base directory" readOnly="true" required="false"/>
<c:simple-property name="startScript" type="file" default="bin/standalone.sh" description="Script used to start the server. If the path is not absolute, it is relative to the base directory"/>
+ <c:simple-property name="javaHomePath" type="file" displayName="JAVA_HOME Path" required="false"
+ description="The absolute path to a JRE or JDK installation directory containing
+ the JVM that should be used to start and shutdown the JBossAS instance;
+ defaults to the home directory of the RHQ agent JRE."/>
<c:list-property name="system-properties">
<c:map-property name="system-property">
<c:simple-property name="key" readOnly="true"/>
commit 94b7a562f4efb9e4d9922e090ceca49deef5c1fd
Merge: 3bf2fbf 7d14f74
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Jan 13 11:38:26 2012 +0100
Merge branch 'lkrejci/dissalow-alert-scripts-from-accessing-local-slsbs'
commit 3bf2fbfd118d30e2c0c9b616ff12ba7bc9e9492c
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Fri Jan 13 11:38:18 2012 +0100
Putting back the original version of secured JNDI access so that the latest
batch of fixes can be merged into it.
This reverts commit 0e36c3ee8f1954486b1c12ee22ddd4b90cf7e685.
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
index 894c953..5822d44 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
@@ -20,6 +20,7 @@
package org.rhq.bindings;
import java.io.FilePermission;
+import java.io.SerializablePermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.Permission;
@@ -83,6 +84,11 @@ public class StandardScriptPermissions extends PermissionCollection {
add(new PropertyPermission("*", "read"));
add(new ReflectPermission("suppressAccessChecks"));
+
+ //these 2 are required for server-side scripts to be able to
+ //invoke remote EJBs.
+ add(new SerializablePermission("enableSubclassImplementation"));
+ add(new RuntimePermission("reflectionFactoryAccess"));
}
public void add(Permission permission) {
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index e777e21..4dfd109 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -17,15 +17,35 @@
<properties>
<persistence-api.version>1.0</persistence-api.version>
+ <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
+ <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
+
+ <!-- dependency versions -->
+ <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
+
+ <clean.db>true</clean.db>
</properties>
<dependencies>
+
+ <!-- Note, the test deps are intentionally placed above the other scoped deps because of classpath
+ reasons. Maven orders the [test] classpath in the order listed in the pom. We specifically
+ need the embeddable-ejb3 jar above the standard ejb3 jars because we need the embeddble packages
+ loaded when testing. -->
+ <dependency>
+ <groupId>jboss.jboss-embeddable-ejb3</groupId>
+ <artifactId>jboss-ejb3-all</artifactId>
+ <version>${jboss-embeddable-ejb3.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.rhq</groupId>
<artifactId>rhq-script-bindings</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
+
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
@@ -40,20 +60,333 @@
section. -->
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3x</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <!-- Test deps - this insane list of deps is needed to get the embedded JBoss server with RHQ server deployed running -->
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate</groupId>
+ <artifactId>hibernate3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-entitymanager</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-javamail_1.3.1_spec</artifactId>
+ <!-- The Sun javamail jar isn't available from a public repo due to licensing issues,
+ so use the Geronimo one instead. -->
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz-oracle</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-annotations-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-cache</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-common</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed by the PoolClass annotation used on some
+ of our SLSB's -->
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-j2ee</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-jmx</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-system</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jbosssx</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jbpm</artifactId>
+ <version>3.1.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.7</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>trove</groupId>
+ <artifactId>trove</artifactId>
+ <version>1.0.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.opencsv</groupId>
+ <artifactId>opencsv</artifactId>
+ <version>1.8</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- for the transaction interrupt EJB3 interceptor -->
+ <dependency>
+ <groupId>org.jboss.transaction</groupId>
+ <artifactId>jboss-jta</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>tomcat</groupId>
+ <artifactId>catalina</artifactId>
+ <version>5.5.20</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>tomcat</groupId>
+ <artifactId>tomcat-jk</artifactId>
+ <version>4.1.31</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Needed by com.jboss.jbossnetwork.apl.actions.xml.XPathProcessor; TODO: Remove once APL has been excised. -->
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.jcraft</groupId>
+ <artifactId>jsch</artifactId>
+ <version>0.1.29</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jettison-provider</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-links</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.el</groupId>
+ <artifactId>jboss-el</artifactId>
+ <version>2.0.1.GA</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.18</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+
<plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <!-- <argLine>-Xdebug -Xnoagent -Djava.compiler=NONE
- -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> -->
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <!-- Everything but the web service tests, this is the standard test execution -->
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <groups>${rhq.testng.includedGroups}</groups>
+ <systemPropertyVariables>
+ <embeddedDeployment>true</embeddedDeployment>
+ <deploymentDirectory>target/test-classes</deploymentDirectory>
+ <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
+ <clean.db>${clean.db}</clean.db>
+ </systemPropertyVariables>
+ <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
+ <additionalClasspathElements>
+ <!-- The below is required for tests to run against Oracle. -->
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
</configuration>
- </plugin>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+
+ <!-- in order to get JMS to work properly in embedded test container, extract jms-rs.rar classes -->
+ <execution>
+ <id>Extract JMS classes from RAR needed for JMS tests</id>
+ <phase>process-classes</phase>
+ <configuration>
+ <tasks>
+ <unzip src="src/test/resources/jms-ra.rar" dest="target">
+ <patternset>
+ <include name="jms-ra.jar"/>
+ </patternset>
+ </unzip>
+ <unzip src="target/jms-ra.jar" dest="target/test-classes">
+ <patternset>
+ <include name="org/**"/>
+ </patternset>
+ </unzip>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
index 5f3ff90..e9f1e4d 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
@@ -20,6 +20,8 @@
package org.rhq.enterprise.client;
import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import org.apache.commons.logging.Log;
@@ -54,11 +56,21 @@ public class LocalClientProxy extends AbstractRhqFacadeProxy<LocalClient> {
}
}
- protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, Object[] args) throws Throwable {
+ protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, final Object[] args) throws Throwable {
try {
- Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
-
- return realMethod.invoke(localSLSB, args);
+ final Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
+
+ //run this through the privileged block to elevate the privs of the script
+ //the scripts don't have the AllowEjbAccessPermission but this code has
+ //all perms (or at least all perms assigned to it by the current context,
+ //which at the time of writing is defined by the rhq-server.policy file
+ //which gives all code all permissions).
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ return realMethod.invoke(localSLSB, args);
+ }
+ });
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Method [" + originalMethod + "] does not have a desimplified counterpart with arguments " + Arrays.asList(argTypes) + ".", e);
}
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
new file mode 100644
index 0000000..dc1fc83
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
@@ -0,0 +1,198 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.client.security.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.SerializablePermission;
+import java.security.PermissionCollection;
+import java.util.Collections;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.rhq.bindings.SandboxedScriptEngine;
+import org.rhq.bindings.ScriptEngineFactory;
+import org.rhq.bindings.StandardBindings;
+import org.rhq.bindings.StandardScriptPermissions;
+import org.rhq.bindings.util.PackageFinder;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class EjbAccessTest extends AbstractEJB3Test {
+
+ public void testEjbsAccessibleThroughPrivilegedCode() {
+ LookupUtil.getSubjectManager().getOverlord();
+ }
+
+ public void testEjbsAccessibleThroughLocalClient() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ engine.eval("SubjectManager.getSubjectByName('rhqadmin');");
+ }
+
+ public void testLocalEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/local');\n"
+ + "subjectManager.getOverlord();");
+
+ Assert.fail("The script shouldn't have been able to call local SLSB method.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testRemoteEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/remote');\n"
+ + "subjectManager.getSubjectByName('rhqadmin');");
+
+ Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testScriptCantUseSessionManagerMethods() throws Exception {
+
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ final ScriptEngine engine = getEngine(overlord);
+
+ class G {
+ private String sessionManager = ""
+ + "org.rhq.enterprise.server.auth.SessionManager.getInstance().";
+
+ public void testInvoke(String methodCall) throws ScriptException {
+ String code = sessionManager + methodCall;
+
+ try {
+ engine.eval(code);
+ Assert.fail("The script shouldn't have been able to call a method on a SessionManager: " + methodCall);
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+ };
+ G manager = new G();
+
+ manager.testInvoke("getlastAccess(0);");
+ manager.testInvoke("getOverlord()");
+ manager.testInvoke("getSubject(2);");
+ manager.testInvoke("invalidate(0);");
+ manager.testInvoke("invalidate(\"\");");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject());");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
+ }
+
+ public void testScriptCantObtainRawJDBCConnectionsWithoutCredentials() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "datasource = context.lookup('java:/RHQDS');\n"
+ + "con = datasource.getConnection();");
+
+ Assert.fail("The script shouldn't have been able to obtain the datasource from the JNDI.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testScriptCantUseEntityManager() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+
+ //try harder with manually specifying the initial context factory
+ try {
+ engine.eval(""
+ + "env = new java.util.Hashtable();"
+ + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.LocalOnlyContextFactory');"
+ + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');"
+ + "context = new javax.naming.InitialContext(env);\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager even using custom initial context factory.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
+ StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
+ ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
+
+ PermissionCollection perms = new StandardScriptPermissions();
+ perms.add(new SerializablePermission("enableSubclassImplementation"));
+
+ return new SandboxedScriptEngine(engine, perms);
+ }
+
+ private static void checkIsDesiredSecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
+ }
+}
diff --git a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
new file mode 100644
index 0000000..1951b84
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
@@ -0,0 +1,26 @@
+# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
+# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
+# WORK IN THIS MODULE.
+
+hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
+#hibernate.connection.release_mode=after_statement
+#hibernate.transaction.flush_before_completion=false
+#hibernate.transaction.auto_close_session=false
+#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
+#hibernate.hbm2ddl.auto=create-drop
+#hibernate.hbm2ddl.auto=create
+hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
+# Clustered cache with TreeCache
+#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
+#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
+#hibernate.dialect=org.hibernate.dialect.HSQLDialect
+hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+hibernate.bytecode.use_reflection_optimizer=false
+# I don't think this is honored, but EJB3Deployer uses it
+hibernate.bytecode.provider=javassist
+hibernate.jdbc.use_streams_for_binary=true
+hibernate.show_sql=false
+hibernate.format_sql=true
+hibernate.default_batch_fetch_size=16
+hibernate.jdbc.batch_size=20
diff --git a/modules/enterprise/server/client-api/src/test/resources/security.policy b/modules/enterprise/server/client-api/src/test/resources/security.policy
new file mode 100644
index 0000000..8860b47
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/security.policy
@@ -0,0 +1,10 @@
+// We need the SecurityManager installed to enable sandboxing of CLI scripts
+// but we don't define any other security measures on the RHQ server itself.
+//
+// Granting all permissions allows us to run the RHQ server as if no security
+// manager was in place (which is assumed by default by JBoss AS) but be able
+// to use it when we need it for our own purposes.
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/modules/enterprise/server/container-lib/pom.xml b/modules/enterprise/server/container-lib/pom.xml
index b832b06..0974431 100644
--- a/modules/enterprise/server/container-lib/pom.xml
+++ b/modules/enterprise/server/container-lib/pom.xml
@@ -39,6 +39,12 @@
<scope>provided</scope> <!-- by JBossAS -->
</dependency>
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jnpserver</artifactId>
+ <version>4.2.2.GA</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<profiles>
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
new file mode 100644
index 0000000..3046af7
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -0,0 +1,230 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.event.EventDirContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jnp.interfaces.NamingContextFactory;
+
+import org.rhq.jndi.context.AccessCheckingContextDecorator;
+import org.rhq.jndi.context.AccessCheckingContextDecoratorSetContext;
+import org.rhq.jndi.context.ContextDecorator;
+import org.rhq.jndi.context.URLPreferringContextDecoratorSetContext;
+import org.rhq.jndi.util.DecoratorPicker;
+
+/**
+ * This initial context factory builder is installed early on during the RHQ server startup
+ * and is later on used for obtaining the {@link Context}s for all JNDI lookups in the
+ * RHQ server.
+ * <p>
+ * We use a custom initial context factory builder to prevent the potential malicious 3rd party
+ * code (like CLI alert scripts) from supplying custom environment variables to {@link InitialContext}
+ * that would modify the JNDI lookup to skip our security access checks.
+ * <p>
+ * By using a builder we effectively take control of the initial context creation process
+ * and are free to ignore whatever the script is trying to supply.
+ * <p>
+ * This builder makes sure to install the RHQ server's security access checks to whatever
+ * initial context that is configured by the standard environment variables
+ * ({@link Context#INITIAL_CONTEXT_FACTORY}, etc.)
+ * <p>
+ * This class is heavily inspired by the implementation of a similar builder in JBoss AS 7.
+ *
+ * @see AllowRhqServerInternalsAccessPermission
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
+ private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
+
+ /**
+ * The list of JNDI name schemes that should be checked for security permissions
+ * (in addition to the names with no scheme).
+ *
+ * @see AccessCheckingContextDecorator
+ */
+ private static final String[] CHECKED_SCHEMES = { "java" };
+
+ private static final Set<Class<? extends Context>> SUPPORTED_CONTEXT_INTERFACES;
+
+ static {
+ SUPPORTED_CONTEXT_INTERFACES = new HashSet<Class<? extends Context>>();
+ SUPPORTED_CONTEXT_INTERFACES.add(Context.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(DirContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(EventContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(EventDirContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(LdapContext.class);
+ }
+
+ private static final Set<InetAddress> SERVER_BIND_IPS;
+ static {
+ SERVER_BIND_IPS = new HashSet<InetAddress>();
+
+ try {
+ String bindingAddressString = System.getProperty("jboss.bind.address");
+ InetAddress bindingAddress = InetAddress.getByName(bindingAddressString);
+
+ if (bindingAddress.isAnyLocalAddress()) {
+ Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+ while (ifaces.hasMoreElements()) {
+ NetworkInterface iface = ifaces.nextElement();
+ SERVER_BIND_IPS.addAll(Collections.list(iface.getInetAddresses()));
+ }
+ } else {
+ SERVER_BIND_IPS.add(bindingAddress);
+ }
+ } catch (SocketException e) {
+ LOG.error("Could not obtain the list of local IPs", e);
+ } catch (UnknownHostException e) {
+ LOG.error("Failed to get the binding address of the RHQ server.", e);
+ }
+ }
+
+ private static final int JNP_PORT = Integer.parseInt(System.getProperty("rhq.server.startup.namingservice.port",
+ "2099"));
+
+ /**
+ * This is the default initial context factory that is returned when no other is
+ * configured using the environment variables.
+ * <p>
+ * It uses {@link NamingContextFactory} as the underlying mechanism - the same
+ * as the default configuration in JBoss 4.
+ */
+ private static final InitialContextFactory DEFAULT_FACTORY = new InitialContextFactory() {
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return createSecureWrapper(new NamingContextFactory(), environment).getInitialContext(environment);
+ }
+ };
+
+ /**
+ * Create a InitialContext factory. If the environment does not override the factory class it will use the
+ * default context factory.
+ *
+ * @param environment The environment
+ * @return An initial context factory
+ * @throws NamingException If an error occurs loading the factory class.
+ */
+ public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
+ final String factoryClassName = (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
+ if (factoryClassName == null) {
+ return DEFAULT_FACTORY;
+ }
+ final ClassLoader classLoader = getContextClassLoader();
+ try {
+ final Class<?> factoryClass = Class.forName(factoryClassName, true, classLoader);
+ InitialContextFactory configuredFactory = (InitialContextFactory) factoryClass.newInstance();
+ return createSecureWrapper(configuredFactory, environment);
+ } catch (Exception e) {
+ throw new NamingException("Failed instantiate InitialContextFactory " + factoryClassName
+ + " from classloader " + classLoader);
+ }
+ }
+
+ private ClassLoader getContextClassLoader() {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ }
+
+ private static InitialContextFactory
+ createSecureWrapper(InitialContextFactory factory, Hashtable<?, ?> environment) {
+ String providerUrl = (String) environment.get(Context.PROVIDER_URL);
+
+ if (providerUrl == null) {
+ return getAccessCheckingFactory(factory);
+ } else {
+ try {
+ URI uri = new URI(providerUrl);
+ InetAddress providerHost = InetAddress.getByName(uri.getHost());
+
+ //check if we are accessing the RHQ server through some remoting
+ //interface.
+ if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
+ return getAccessCheckingFactory(factory);
+ } else {
+ return getURLPreferringFactory(factory);
+ }
+ } catch (URISyntaxException e) {
+ return getAccessCheckingFactory(factory);
+ } catch (UnknownHostException e) {
+ //let the factory deal with the unknown host...
+ //this most probably shouldn't be secured because localhost addresses
+ //should be resolvable.
+ return getURLPreferringFactory(factory);
+ }
+ }
+ }
+
+ private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
+ ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+ pickers.add(getURLPreferringDecoratorPicker());
+ pickers.add(getAccessCheckingDecoratorPicker());
+
+ return new DecoratingInitialContextFactory(original, pickers);
+ }
+
+ private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
+ ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+ pickers.add(getURLPreferringDecoratorPicker());
+
+ return new DecoratingInitialContextFactory(original, pickers);
+ }
+
+ private static DecoratorPicker<Context, ContextDecorator> getAccessCheckingDecoratorPicker() {
+ DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+ ret.setContext(new AccessCheckingContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES, CHECKED_SCHEMES));
+
+ return ret;
+ }
+
+ private static DecoratorPicker<Context, ContextDecorator> getURLPreferringDecoratorPicker() {
+ DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+ ret.setContext(new URLPreferringContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES));
+
+ return ret;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej
deleted file mode 100644
index 445fa3a..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej
+++ /dev/null
@@ -1,122 +0,0 @@
---- modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
-+++ modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
-@@ -27,7 +27,7 @@
- import java.net.UnknownHostException;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
--import java.util.ArrayList;
-+import java.util.Arrays;
- import java.util.Collections;
- import java.util.Enumeration;
- import java.util.HashSet;
-@@ -37,10 +37,6 @@
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import javax.naming.NamingException;
--import javax.naming.directory.DirContext;
--import javax.naming.event.EventContext;
--import javax.naming.event.EventDirContext;
--import javax.naming.ldap.LdapContext;
- import javax.naming.spi.InitialContextFactory;
- import javax.naming.spi.InitialContextFactoryBuilder;
-
-@@ -49,10 +45,16 @@
- import org.jnp.interfaces.NamingContextFactory;
-
- import org.rhq.jndi.context.AccessCheckingContextDecorator;
--import org.rhq.jndi.context.AccessCheckingContextDecoratorSetContext;
--import org.rhq.jndi.context.ContextDecorator;
--import org.rhq.jndi.context.URLPreferringContextDecoratorSetContext;
--import org.rhq.jndi.util.DecoratorPicker;
-+import org.rhq.jndi.context.AccessCheckingDirContextDecorator;
-+import org.rhq.jndi.context.AccessCheckingEventContextDecorator;
-+import org.rhq.jndi.context.AccessCheckingEventDirContextDecorator;
-+import org.rhq.jndi.context.AccessCheckingLdapContextDecorator;
-+import org.rhq.jndi.context.ContextDecoratorPicker;
-+import org.rhq.jndi.context.URLPreferringContextDecorator;
-+import org.rhq.jndi.context.URLPreferringDirContextDecorator;
-+import org.rhq.jndi.context.URLPreferringEventContextDecorator;
-+import org.rhq.jndi.context.URLPreferringEventDirContextDecorator;
-+import org.rhq.jndi.context.URLPreferringLdapContextDecorator;
-
- /**
- * This initial context factory builder is installed early on during the RHQ server startup
-@@ -87,17 +89,6 @@
- */
- private static final String[] CHECKED_SCHEMES = { "java" };
-
-- private static final Set<Class<? extends Context>> SUPPORTED_CONTEXT_INTERFACES;
--
-- static {
-- SUPPORTED_CONTEXT_INTERFACES = new HashSet<Class<? extends Context>>();
-- SUPPORTED_CONTEXT_INTERFACES.add(Context.class);
-- SUPPORTED_CONTEXT_INTERFACES.add(DirContext.class);
-- SUPPORTED_CONTEXT_INTERFACES.add(EventContext.class);
-- SUPPORTED_CONTEXT_INTERFACES.add(EventDirContext.class);
-- SUPPORTED_CONTEXT_INTERFACES.add(LdapContext.class);
-- }
--
- private static final Set<InetAddress> SERVER_BIND_IPS;
- static {
- SERVER_BIND_IPS = new HashSet<InetAddress>();
-@@ -200,31 +191,42 @@
- }
-
- private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
-- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
-- pickers.add(getURLPreferringDecoratorPicker());
-- pickers.add(getAccessCheckingDecoratorPicker());
--
-- return new DecoratingInitialContextFactory(original, pickers);
-+ return new DecoratingInitialContextFactory(original, Arrays.asList(
-+ getURLPreferringDecoratorPicker(), getAccessCheckingDecoratorPicker()));
- }
--
-+
- private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
-- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
-- pickers.add(getURLPreferringDecoratorPicker());
--
-- return new DecoratingInitialContextFactory(original, pickers);
-+ return new DecoratingInitialContextFactory(original, Arrays.asList(
-+ getURLPreferringDecoratorPicker()));
- }
-
-- private static DecoratorPicker<Context, ContextDecorator> getAccessCheckingDecoratorPicker() {
-- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
-- ret.setContext(new AccessCheckingContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES, CHECKED_SCHEMES));
--
-+ private static ContextDecoratorPicker getAccessCheckingDecoratorPicker() {
-+ ContextDecoratorPicker ret = new ContextDecoratorPicker();
-+
-+ ret.setConstructorParameters(new Object[] { CHECKED_SCHEMES });
-+ ret.setConstructorParameterTypes(new Class<?>[] { String[].class });
-+
-+ ret.getPossibleDecorators().add(AccessCheckingContextDecorator.class);
-+ ret.getPossibleDecorators().add(AccessCheckingDirContextDecorator.class);
-+ ret.getPossibleDecorators().add(AccessCheckingEventContextDecorator.class);
-+ ret.getPossibleDecorators().add(AccessCheckingEventDirContextDecorator.class);
-+ ret.getPossibleDecorators().add(AccessCheckingLdapContextDecorator.class);
-+
- return ret;
- }
-
-- private static DecoratorPicker<Context, ContextDecorator> getURLPreferringDecoratorPicker() {
-- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
-- ret.setContext(new URLPreferringContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES));
--
-+ private static ContextDecoratorPicker getURLPreferringDecoratorPicker() {
-+ ContextDecoratorPicker ret = new ContextDecoratorPicker();
-+
-+ ret.setConstructorParameters(null);
-+ ret.setConstructorParameterTypes(null);
-+
-+ ret.getPossibleDecorators().add(URLPreferringContextDecorator.class);
-+ ret.getPossibleDecorators().add(URLPreferringDirContextDecorator.class);
-+ ret.getPossibleDecorators().add(URLPreferringEventContextDecorator.class);
-+ ret.getPossibleDecorators().add(URLPreferringEventDirContextDecorator.class);
-+ ret.getPossibleDecorators().add(URLPreferringLdapContextDecorator.class);
-+
- return ret;
- }
- }
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
new file mode 100644
index 0000000..aa807d6
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
@@ -0,0 +1,36 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.security.BasicPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowRhqServerInternalsAccessPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 1L;
+
+ public AllowRhqServerInternalsAccessPermission() {
+ super("org.rhq.allow.server.internals.access");
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
new file mode 100644
index 0000000..19b30ea
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
@@ -0,0 +1,100 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.rhq.jndi.context.ContextDecorator;
+import org.rhq.jndi.util.DecoratorPicker;
+import org.rhq.jndi.util.DecoratingInvocationHandler;
+
+/**
+ * This class implements an initial context factory that decorates the contexts
+ * returned from a "wrapped" initial factory passed to this class in the constructor.
+ * <p>
+ * The contexts returned from the wrapped initial factory are hidden behind a proxy
+ * that implements the intersection of interfaces from the <code>supportedContextInterfaces</code>
+ * constructor parameter and the actual interfaces the wrapped context implements.
+ * <p>
+ * The proxy method calls are handled using the {@link DecoratingInvocationHandler} which is initialized
+ * with the list of {@link DecoratorPicker pickers} that are used to intercept the method
+ * calls on the wrapped context.
+ *
+ * @see DecoratorPicker
+ * @see DecoratingInvocationHandler
+ *
+ * @author Lukas Krejci
+ */
+public class DecoratingInitialContextFactory implements InitialContextFactory {
+
+ List<DecoratorPicker<Context, ContextDecorator>> pickers;
+ private InitialContextFactory factory;
+ private Set<Class<? extends Context>> supportedContextInterfaces;
+
+ public DecoratingInitialContextFactory(InitialContextFactory factory, List<DecoratorPicker<Context, ContextDecorator>> decoratorPickers) {
+ this.factory = factory;
+ this.pickers = decoratorPickers;
+ this.supportedContextInterfaces = new HashSet<Class<? extends Context>>();
+ for(DecoratorPicker<Context, ContextDecorator> picker : pickers) {
+ supportedContextInterfaces.addAll(picker.getContext().getSupportedInterfaces());
+ }
+ }
+
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ Context ctx = factory.getInitialContext(environment);
+
+ Set<Class<?>> implementedIfaces = getAllImplementedInterfaces(ctx.getClass());
+ Class<?>[] ii = new Class<?>[implementedIfaces.size()];
+ implementedIfaces.toArray(ii);
+
+ return (Context) Proxy.newProxyInstance(ctx.getClass().getClassLoader(), ii, new DecoratingInvocationHandler<Context, ContextDecorator>(pickers, ctx));
+ }
+
+ private Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
+ HashSet<Class<?>> ret = new HashSet<Class<?>>();
+ getAllImplementedInterfaces(cls, ret);
+
+ ret.retainAll(supportedContextInterfaces);
+
+ return ret;
+ }
+
+ private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
+ Class<?>[] ifaces = cls.getInterfaces();
+
+ for (Class<?> iface : Arrays.asList(ifaces)) {
+ output.add(iface);
+ getAllImplementedInterfaces(iface, output);
+ }
+
+ if (cls.getSuperclass() != null) {
+ getAllImplementedInterfaces(cls.getSuperclass(), output);
+ }
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
new file mode 100644
index 0000000..6bfec7e
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
@@ -0,0 +1,254 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ * This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
+ * applied security checks in each method (lookups, (un)bindings, etc).
+ * <p>
+ * The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
+ * <p>
+ * This decorator applies the security check on any JNDI name without a scheme and
+ * on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
+ * in the constructor.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingContextDecorator implements Context, ContextDecorator, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
+ private Context original;
+ private List<String> checkedSchemes;
+
+ public AccessCheckingContextDecorator(String... checkedSchemes) {
+ this.checkedSchemes = Arrays.asList(checkedSchemes);
+ }
+
+ public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
+ this.original = original;
+ this.checkedSchemes = Arrays.asList(checkedSchemes);
+ }
+
+ public void init(Context ctx) {
+ this.original = ctx;
+ }
+
+ protected Context getOriginal() {
+ return original;
+ }
+
+ protected static void check() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(PERM);
+ }
+
+ private void checkScheme(String scheme) {
+ if (scheme == null || checkedSchemes.contains(scheme)) {
+ check();
+ }
+ }
+
+ protected void check(String name) {
+ checkScheme(getURLScheme(name));
+ }
+
+ protected void check(Name name) {
+ if (name.size() == 0) {
+ check();
+ } else {
+ String first = name.get(0);
+ checkScheme(getURLScheme(first));
+ }
+ }
+
+ public Object lookup(Name name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public void bind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+ check();
+ return original.addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ check();
+ return original.removeFromEnvironment(propName);
+ }
+
+ public Hashtable<?, ?> getEnvironment() throws NamingException {
+ check();
+ return original.getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ check();
+ original.close();
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ check();
+ return original.getNameInNamespace();
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
new file mode 100644
index 0000000..284fd0c
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
@@ -0,0 +1,75 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
+
+ private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
+ static {
+ HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
+ tmp.add(AccessCheckingContextDecorator.class);
+ tmp.add(AccessCheckingDirContextDecorator.class);
+ tmp.add(AccessCheckingEventContextDecorator.class);
+ tmp.add(AccessCheckingEventDirContextDecorator.class);
+ tmp.add(AccessCheckingLdapContextDecorator.class);
+
+ DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
+ }
+
+ private Set<Class<? extends Context>> supportedInterfaces;
+ private String[] checkedSchemes;
+
+ public AccessCheckingContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces, String... checkedSchemes) {
+ this.supportedInterfaces = supportedInterfaces;
+ this.checkedSchemes = checkedSchemes;
+ }
+
+ public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
+ Constructor<? extends ContextDecorator> ctor = decoratorClass.getConstructor(String[].class);
+
+ return ctor.newInstance((Object)checkedSchemes);
+ }
+
+ public Set<Class<? extends Context>> getSupportedInterfaces() {
+ return supportedInterfaces;
+ }
+
+ public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
+ return DECORATOR_CLASSES;
+ }
+
+ public void init(ContextDecorator decorator, Context object) throws Exception {
+ decorator.init(object);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
new file mode 100644
index 0000000..1614180
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
@@ -0,0 +1,187 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+/**
+ * A decorator of {@link DirContext}.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingDirContextDecorator extends AccessCheckingContextDecorator implements DirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingDirContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingDirContextDecorator(DirContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected DirContext getOriginal() {
+ return (DirContext) super.getOriginal();
+ }
+
+ public Attributes getAttributes(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name);
+ }
+
+ public Attributes getAttributes(String name) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name);
+ }
+
+ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name, attrIds);
+ }
+
+ public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name, attrIds);
+ }
+
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mods);
+ }
+
+ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mods);
+ }
+
+ public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().bind(name, obj, attrs);
+ }
+
+ public void bind(String name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().bind(name, obj, attrs);
+ }
+
+ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().rebind(name, obj, attrs);
+ }
+
+ public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().rebind(name, obj, attrs);
+ }
+
+ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
+ check(name);
+ return getOriginal().createSubcontext(name, attrs);
+ }
+
+ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
+ check(name);
+ return getOriginal().createSubcontext(name, attrs);
+ }
+
+ public DirContext getSchema(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public DirContext getSchema(String name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public DirContext getSchemaClassDefinition(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getSchemaClassDefinition(name);
+ }
+
+ public DirContext getSchemaClassDefinition(String name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
+ throws NamingException {
+ check(name);
+ return getOriginal().search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filterExpr, filterArgs, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
+ SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filterExpr, filterArgs, cons);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
new file mode 100644
index 0000000..67a9527
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
@@ -0,0 +1,69 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingEventContextDecorator extends AccessCheckingContextDecorator implements EventContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingEventContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingEventContextDecorator(EventContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected EventContext getOriginal() {
+ return (EventContext) super.getOriginal();
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ check();
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ check();
+ return getOriginal().targetMustExist();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
new file mode 100644
index 0000000..ed7a848
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
@@ -0,0 +1,96 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.SearchControls;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingEventDirContextDecorator extends AccessCheckingDirContextDecorator implements
+ EventDirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingEventDirContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingEventDirContextDecorator(EventDirContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected EventDirContext getOriginal() {
+ return (EventDirContext) super.getOriginal();
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ check();
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ check();
+ return getOriginal().targetMustExist();
+ }
+
+ public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void
+ addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
+ NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
new file mode 100644
index 0000000..e361db8
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
@@ -0,0 +1,85 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.NamingException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingLdapContextDecorator extends AccessCheckingDirContextDecorator implements LdapContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingLdapContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingLdapContextDecorator(LdapContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected LdapContext getOriginal() {
+ return (LdapContext) super.getOriginal();
+ }
+
+ public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
+ check();
+ return getOriginal().extendedOperation(request);
+ }
+
+ public LdapContext newInstance(Control[] requestControls) throws NamingException {
+ check();
+ return getOriginal().newInstance(requestControls);
+ }
+
+ public void reconnect(Control[] connCtls) throws NamingException {
+ check();
+ getOriginal().reconnect(connCtls);
+ }
+
+ public Control[] getConnectControls() throws NamingException {
+ check();
+ return getOriginal().getConnectControls();
+ }
+
+ public void setRequestControls(Control[] requestControls) throws NamingException {
+ check();
+ getOriginal().setRequestControls(requestControls);
+ }
+
+ public Control[] getRequestControls() throws NamingException {
+ check();
+ return getOriginal().getRequestControls();
+ }
+
+ public Control[] getResponseControls() throws NamingException {
+ check();
+ return getOriginal().getResponseControls();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
new file mode 100644
index 0000000..5755ebd
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
@@ -0,0 +1,33 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public interface ContextDecorator extends Context {
+
+ void init(Context context) throws NamingException;
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
new file mode 100644
index 0000000..20077de
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
@@ -0,0 +1,212 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.io.Serializable;
+import java.util.Hashtable;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ * This is a wrapper class around another {@link Context} implementation that
+ * prefers to use an URL context for some operation if the JNDI name contains
+ * a scheme rather than the original. This is the behavior of {@link InitialContext}
+ * which we need to restore in the contexts created by the {@link AccessCheckingInitialContextFactoryBuilder}
+ * (which an {@link InitialContext} uses exclusively if the builder is set).
+ * <p>
+ * This is important because RHQ server has its own initial context factory
+ * builder that creates factories that in turn create contexts. If the default
+ * {@link InitialContext} implementation was used, we'd never be able to lookup
+ * scheme-based names because the default implementation of the {@link InitialContext}
+ * always uses the default context of the builder if one is installed no matter
+ * the scheme in the name.
+ * <p>
+ * The {@link AccessCheckingInitialContextFactoryBuilder} wraps the context returned
+ * by the factory in an instance of this class and thus is restoring the original
+ * intended behavior of the {@link InitialContext}. It looks at the name being looked
+ * up (bound or whatever) and prefers to use the URL context factories if the name
+ * contains the scheme (as does the {@link InitialContext} if no builder is installed).
+ * If the name doesn't contain a scheme, the provided default context factory is used to
+ * look up the name.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecorator implements Context, ContextDecorator, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private Context original;
+
+ public URLPreferringContextDecorator() {
+
+ }
+
+ public URLPreferringContextDecorator(Context ctx) {
+ original = ctx;
+ }
+
+ public void init(Context context) {
+ original = context;
+ }
+
+ protected Context getOriginal() throws NamingException {
+ return original;
+ }
+
+ protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
+ @SuppressWarnings("unchecked")
+ Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
+ return urlContext == null ? getOriginal() : urlContext;
+ }
+
+ protected Context getURLOrDefaultInitCtx(String name) throws NamingException {
+ @SuppressWarnings("unchecked")
+ Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
+ return urlContext == null ? getOriginal() : urlContext;
+ }
+
+ public Object lookup(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookup(name);
+ }
+
+ public void bind(Name name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ getURLOrDefaultInitCtx(name).unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ getURLOrDefaultInitCtx(name).unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
+ }
+
+ public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).list(name);
+ }
+
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).list(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).listBindings(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ getURLOrDefaultInitCtx(name).destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ getURLOrDefaultInitCtx(name).destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ return getOriginal().composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix) throws NamingException {
+ return getOriginal().composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+ return getOriginal().addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ return getOriginal().removeFromEnvironment(propName);
+ }
+
+ public Hashtable<?, ?> getEnvironment() throws NamingException {
+ return getOriginal().getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ if (getOriginal() != null) {
+ getOriginal().close();
+ original = null;
+ }
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ return getOriginal().getNameInNamespace();
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
new file mode 100644
index 0000000..6e7debc
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
@@ -0,0 +1,76 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.spi.NamingManager;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecoratorHelper {
+
+ private URLPreferringContextDecoratorHelper() {
+
+ }
+
+ public static Context getURLContext(String name, Hashtable<Object, Object> env) throws NamingException {
+ String scheme = getURLScheme(name);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, env);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+
+ return null;
+ }
+
+ public static Context getURLContext(Name name, Hashtable<Object, Object> env) throws NamingException {
+ if (name.size() > 0) {
+ String first = name.get(0);
+ String scheme = getURLScheme(first);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, env);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
new file mode 100644
index 0000000..828cd74
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
@@ -0,0 +1,71 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
+
+ private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
+ static {
+ HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
+ tmp.add(URLPreferringContextDecorator.class);
+ tmp.add(URLPreferringDirContextDecorator.class);
+ tmp.add(URLPreferringEventContextDecorator.class);
+ tmp.add(URLPreferringEventDirContextDecorator.class);
+ tmp.add(URLPreferringLdapContextDecorator.class);
+
+ DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
+ }
+
+ private Set<Class<? extends Context>> supportedInterfaces;
+
+ public URLPreferringContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces) {
+ this.supportedInterfaces = supportedInterfaces;
+ }
+
+ public Set<Class<? extends Context>> getSupportedInterfaces() {
+ return supportedInterfaces;
+ }
+
+ public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
+ return DECORATOR_CLASSES;
+ }
+
+ public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
+ return decoratorClass.newInstance();
+ }
+
+ public void init(ContextDecorator decorator, Context object) throws Exception {
+ decorator.init(object);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
new file mode 100644
index 0000000..6a49942
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
@@ -0,0 +1,185 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+/**
+ * Akin to {@link URLPreferringContextDecorator} this class implements the similar logic
+ * for {@link DirContext}s.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringDirContextDecorator extends URLPreferringContextDecorator implements DirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringDirContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringDirContextDecorator(DirContext ctx) {
+ super(ctx);
+ }
+
+ protected DirContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof DirContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of DirContext");
+ }
+ }
+
+ return (DirContext) ctx;
+ }
+
+ @Override
+ protected DirContext getURLOrDefaultInitCtx(Name name) throws NamingException {
+ Context ctx = super.getURLOrDefaultInitCtx(name);
+ return checkAndCast(ctx);
+ }
+
+ @Override
+ protected DirContext getURLOrDefaultInitCtx(String name) throws NamingException {
+ Context ctx = super.getURLOrDefaultInitCtx(name);
+ return checkAndCast(ctx);
+ }
+
+ public Attributes getAttributes(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name);
+ }
+
+ public Attributes getAttributes(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name);
+ }
+
+ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
+ }
+
+ public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
+ }
+
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
+ }
+
+ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
+ }
+
+ public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
+ }
+
+ public void bind(String name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
+ }
+
+ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
+ }
+
+ public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
+ }
+
+ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
+ }
+
+ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
+ }
+
+ public DirContext getSchema(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchema(name);
+ }
+
+ public DirContext getSchema(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchema(name);
+ }
+
+ public DirContext getSchemaClassDefinition(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
+ }
+
+ public DirContext getSchemaClassDefinition(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
+ throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
+ SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
new file mode 100644
index 0000000..e3298a0
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
@@ -0,0 +1,81 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringEventContextDecorator extends URLPreferringContextDecorator implements EventContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringEventContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringEventContextDecorator(EventContext ctx) {
+ super(ctx);
+ }
+
+ protected EventContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof EventContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of EventContext");
+ }
+ }
+
+ return (EventContext) ctx;
+ }
+
+ @Override
+ protected EventContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return getOriginal().targetMustExist();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
new file mode 100644
index 0000000..4925297
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
@@ -0,0 +1,104 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.directory.SearchControls;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringEventDirContextDecorator extends URLPreferringDirContextDecorator implements EventDirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringEventDirContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringEventDirContextDecorator(EventDirContext ctx) {
+ super(ctx);
+ }
+
+ @Override
+ protected EventDirContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof EventDirContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of EventDirContext");
+ }
+ }
+
+ return (EventDirContext) ctx;
+ }
+
+ @Override
+ protected EventDirContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return getOriginal().targetMustExist();
+ }
+
+ public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void
+ addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
+ NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
new file mode 100644
index 0000000..c74df39
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
@@ -0,0 +1,94 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringLdapContextDecorator extends URLPreferringDirContextDecorator implements LdapContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringLdapContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringLdapContextDecorator(LdapContext original) {
+ super(original);
+ }
+
+ @Override
+ protected LdapContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof LdapContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException("Not an instance of LdapContext");
+ }
+ }
+
+ return (LdapContext) ctx;
+ }
+
+ @Override
+ protected LdapContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
+ return getOriginal().extendedOperation(request);
+ }
+
+ public LdapContext newInstance(Control[] requestControls) throws NamingException {
+ return new URLPreferringLdapContextDecorator(getOriginal().newInstance(requestControls));
+ }
+
+ public void reconnect(Control[] connCtls) throws NamingException {
+ getOriginal().reconnect(connCtls);
+ }
+
+ public Control[] getConnectControls() throws NamingException {
+ return getOriginal().getConnectControls();
+ }
+
+ public void setRequestControls(Control[] requestControls) throws NamingException {
+ getOriginal().setRequestControls(requestControls);
+ }
+
+ public Control[] getRequestControls() throws NamingException {
+ return getOriginal().getRequestControls();
+ }
+
+ public Control[] getResponseControls() throws NamingException {
+ return getOriginal().getResponseControls();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
new file mode 100644
index 0000000..d938c50
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
@@ -0,0 +1,45 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.mbean;
+
+import javax.naming.spi.NamingManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingInitialContextFactoryBuilderInstaller implements AccessCheckingInitialContextFactoryBuilderInstallerMBean {
+ private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
+
+ public void start() throws Exception {
+ LOG.info("Installing RHQ's access permission checking initial context factory builder");
+
+ NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
+ }
+
+ public void stop() throws Exception {
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
new file mode 100644
index 0000000..87d19ab
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
@@ -0,0 +1,32 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.mbean;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public interface AccessCheckingInitialContextFactoryBuilderInstallerMBean {
+
+ void start() throws Exception;
+
+ void stop() throws Exception;
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
new file mode 100644
index 0000000..356a6e9
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
@@ -0,0 +1,46 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public class DecoratingInvocationHandler<Type, Decorator extends Type> implements InvocationHandler {
+
+ private final List<DecoratorPicker<Type, Decorator>> pickers;
+ private Type object;
+
+ public DecoratingInvocationHandler(List<DecoratorPicker<Type, Decorator>> pickers, Type object) {
+ this.pickers = pickers;
+ this.object = object;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Type target = object;
+ Class<?> methodClass = method.getDeclaringClass();
+
+ for(DecoratorPicker<Type, Decorator> picker : pickers) {
+ target = picker.decorate(target, methodClass);
+ }
+
+ return method.invoke(target, args);
+ }
+}
\ No newline at end of file
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
new file mode 100644
index 0000000..017d29f
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
@@ -0,0 +1,195 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Given as set of decorators extending given type, this class can pick
+ * the most appropriate set of decorators for a class or a method call.
+ * <p>
+ * To configure the decorator, one has to provide a {@link DecoratorSetContext} that
+ * is then used to obtain the list of
+ * {@link DecoratorSetContext#getSupportedInterfaces() supported interfaces}, which are
+ * all the interfaces that should be used for decorator resolution (i.e. all other interfaces
+ * that a class might implement are ignored during decorator resolution), the list of
+ * {@link DecoratorSetContext#getDecoratorClasses() decorator classes}, which is a list
+ * of decorators the picker can choose from and is also used to instantiate and initialize
+ * the decorators.
+ *
+ * @author Lukas Krejci
+ */
+public class DecoratorPicker<Type, Decorator extends Type> {
+
+ private DecoratorSetContext<Type, Decorator> context;
+
+ public DecoratorSetContext<Type, Decorator> getContext() {
+ return context;
+ }
+
+ public void setContext(DecoratorSetContext<Type, Decorator> decoratorSetContext) {
+ this.context = decoratorSetContext;
+ }
+
+ /**
+ * Returns a set of decorators applicable for given method. The set is established based
+ * on the declaring class of the method.
+ *
+ * @param method the method to inspect
+ * @return the set of decorators that can be used to wrap a method call
+ * @throws Exception
+ */
+ public Set<Decorator> getDecoratorsForMethod(Method method) throws Exception {
+ return getDecoratorsForClass_Private(method.getDeclaringClass());
+ }
+
+ /**
+ * Returns a set of decorators that can be used on instances of given class.
+ * @param cls the class to inspect
+ * @return
+ * @throws Exception
+ */
+ public Set<Decorator> getDecoratorsForClass(Class<? extends Type> cls) throws Exception {
+ return getDecoratorsForClass_Private(cls);
+ }
+
+ /**
+ * This method first establishes the set of decorators to use based on the class of the supplied
+ * object and then chains the decorators (in arbitrary order) with the supplied object at the
+ * "root" of the chain.
+ * <p>
+ * If a method is then called on the returned object, the methods of all the decorators are called
+ * in chain (each supposedly calling the next) and finally, at the end of the chain, the method on
+ * the original object (the one supplied to this method) is called.
+ * <p>
+ * Note that the above is only an intended behavior and actually depends on the implementation of
+ * the decorators that are resposinble for the chaining. Each decorator is initialized
+ * (@{link {@link DecoratorSetContext#init(Object, Object)} which should set it up for such chaining.
+ *
+ * @param object
+ * @return
+ * @throws Exception
+ */
+ public Type decorate(Type object) throws Exception {
+ Set<Decorator> decs = getDecoratorsForClass_Private(object.getClass());
+ Type ret = object;
+ for(Decorator d : decs) {
+ context.init(d, ret);
+ ret = d;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Similar to {@link #decorate(Object)} but instead of the class of the object itself,
+ * uses the significantSuperClass as the basis for the decorator resolution.
+ * <p>
+ * This is important, because if the object implements two mutually incompatible sub-interfaces of <code>Type</code>,
+ * the chained decorators might fail to execute a method later on if the decorator depends on the upper part
+ * of the chain to implement certain sub-interface of <code>Type</code>.
+ *
+ * @param object the object to wrap in decorators
+ * @param significantSuperClass the class to base the decorator resolution on
+ * @return
+ * @throws Exception
+ */
+ public Type decorate(Type object, Class<?> significantSuperClass) throws Exception {
+ Set<Decorator> decs = getDecoratorsForClass_Private(significantSuperClass);
+ Type ret = object;
+ for(Decorator d : decs) {
+ context.init(d, ret);
+ ret = d;
+ }
+
+ return ret;
+ }
+
+ private Set<Decorator> getDecoratorsForClass_Private(Class<?> cls) throws Exception {
+ Set<Class<? extends Type>> ifaces = getNearestApplicableInterfaces(cls);
+
+ HashSet<Decorator> ret = new HashSet<Decorator>();
+
+ for (Class<? extends Type> iface : ifaces) {
+ for (Class<? extends Decorator> decClass : getMatch(iface)) {
+ ret.add(context.instantiate(decClass));
+ }
+ }
+
+ return ret;
+ }
+
+ private Set<Class<? extends Type>> getNearestApplicableInterfaces(Class<?> cls) {
+ List<Class<? extends Type>> ifaces = new ArrayList<Class<? extends Type>>(getAllApplicableInterfaces(cls));
+
+ //now compact the set to only contain the most concrete interfaces
+
+ Iterator<Class<? extends Type>> it = ifaces.iterator();
+ while (it.hasNext()) {
+ Class<? extends Type> c = it.next();
+
+ for (int i = 0; i < ifaces.size(); ++i) {
+ Class<? extends Type> nextC = ifaces.get(i);
+ if (!c.equals(nextC) && c.isAssignableFrom(nextC)) {
+ it.remove();
+ break;
+ }
+ }
+ }
+
+ return new HashSet<Class<? extends Type>>(ifaces);
+ }
+
+ private Set<Class<? extends Type>> getAllApplicableInterfaces(Class<?> cls) {
+ Set<Class<? extends Type>> ifaces = new HashSet<Class<? extends Type>>();
+
+ for (Class<? extends Type> iface : context.getSupportedInterfaces()) {
+ if (iface.isAssignableFrom(cls)) {
+ ifaces.add(iface);
+ }
+ }
+
+ if (ifaces.isEmpty()) {
+ throw new IllegalArgumentException("Class " + cls
+ + " doesn't implement any of the applicable interfaces. Cannot find decorators for it.");
+ }
+
+ return ifaces;
+ }
+
+ private Set<Class<? extends Decorator>> getMatch(Class<?> targetIface) {
+
+ Set<Class<? extends Decorator>> ret = new HashSet<Class<? extends Decorator>>();
+
+ for (Class<? extends Decorator> cls : context.getDecoratorClasses()) {
+ if (Arrays.asList(cls.getInterfaces()).contains(targetIface)) {
+ ret.add(cls);
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
new file mode 100644
index 0000000..d7b1676
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
@@ -0,0 +1,59 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.util.Set;
+
+/**
+ * Implementations of this interface provide a context to the {@link DecoratorPicker}.
+ *
+ * @author Lukas Krejci
+ */
+public interface DecoratorSetContext<Type, Decorator> {
+
+ /**
+ * @return the set of interfaces that the decorators are able support.
+ * Usually this should be just a union of all interfaces the decorators implement
+ * but can be trimmed down.
+ */
+ Set<Class<? extends Type>> getSupportedInterfaces();
+
+ /**
+ * @return the set of all decorator classes in this set
+ */
+ Set<Class<? extends Decorator>> getDecoratorClasses();
+
+ /**
+ * Instantiates a new decorator of given class.
+ * @param decoratorClass
+ * @return
+ * @throws Exception
+ */
+ Decorator instantiate(Class<? extends Decorator> decoratorClass) throws Exception;
+
+ /**
+ * Initializes the decorator to decorate given object.
+ *
+ * @param decorator
+ * @param object
+ * @throws Exception on error
+ */
+ void init(Decorator decorator, Type object) throws Exception;
+}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
new file mode 100644
index 0000000..45ba114
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
@@ -0,0 +1,145 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.NamingManager;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class DecoratingInvocationHandlerTest {
+ private static final Set<String> INVOKED_METHODS = new HashSet<String>();
+
+ private static final InvocationHandler NOTE_TAKING_HANDLER = new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ INVOKED_METHODS.add(method.getName());
+
+ if ("hashCode".equals(method.getName())) {
+ return 0;
+ } else if ("equals".equals(method.getName())) {
+ return false;
+ }
+
+ return null;
+ }
+ };
+
+ private static Class<?>[] CONTEXT_INTERFACES;
+
+ public static class Factory implements InitialContextFactory {
+ public Context getInitialContext(Hashtable<?, ?> environment)
+ throws NamingException {
+
+ return (Context) Proxy.newProxyInstance(DecoratingInvocationHandlerTest.class.getClassLoader(), CONTEXT_INTERFACES, NOTE_TAKING_HANDLER);
+ }
+ }
+
+ private static class DummyInitialEventContext extends InitialContext implements EventContext {
+
+ /**
+ * @param environment
+ * @throws NamingException
+ */
+ public DummyInitialEventContext(Hashtable<?, ?> environment) throws NamingException {
+ super(environment);
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ ((EventContext)getDefaultInitCtx()).removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return ((EventContext)getDefaultInitCtx()).targetMustExist();
+ }
+
+
+ }
+
+ @BeforeClass
+ public void setBuilder() throws Exception {
+ NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
+ }
+
+ public void testSimpleDispatch() throws Exception {
+ INVOKED_METHODS.clear();
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
+
+ CONTEXT_INTERFACES = new Class<?>[] { Context.class };
+
+ InitialContext ctx = new InitialContext(env);
+
+ ctx.lookup("asdf");
+
+ assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
+ }
+
+ public void testMultiInterfaceDispatch() throws Exception {
+ INVOKED_METHODS.clear();
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
+
+ CONTEXT_INTERFACES = new Class<?>[] { EventContext.class, DirContext.class };
+
+ InitialContext ctx = new InitialContext(env);
+
+ ctx.lookup("asdf");
+
+ DummyInitialEventContext ectx = new DummyInitialEventContext(env);
+
+ ectx.addNamingListener("hodiny", 0, null);
+
+ assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
+ assert INVOKED_METHODS.contains("addNamingListener") : "The addNamingListener doesn't seem to have propagated to the actual context to be used.";
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
new file mode 100644
index 0000000..e2d7429
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
@@ -0,0 +1,180 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.ldap.LdapContext;
+
+import org.testng.annotations.Test;
+
+import org.rhq.jndi.util.DecoratorPicker;
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ * @author Lukas Krejci
+ */
+@Test
+public class DecoratorPickerTest {
+
+ private static final InvocationHandler DUMMY_HANDLER = new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("hashCode".equals(method.getName())) {
+ return 0;
+ } else if ("equals".equals(method.getName())) {
+ return false;
+ }
+
+ return null;
+ }
+ };
+
+ private static final Class<?> TEST_OBJECT_CLASS1 = createProxyClass(Context.class);
+ private static final Class<?> TEST_OBJECT_CLASS2 = createProxyClass(DirContext.class);
+ private static final Class<?> TEST_OBJECT_CLASS3 = createProxyClass(LdapContext.class);
+ private static final Class<?> TEST_OBJECT_CLASS4 = createProxyClass(LdapContext.class, EventContext.class);
+ private static final Class<?> DECORATOR_CLASS1 = createProxyClass(Context.class);
+ private static final Class<?> DECORATOR_CLASS2 = createProxyClass(EventContext.class);
+ private static final Class<?> DECORATOR_CLASS3 = createProxyClass(LdapContext.class);
+ private static final Class<?> DECORATOR_CLASS4 = createProxyClass(DirContext.class);
+
+ public void testSimpleDecoratorIdentifiedByClass() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS1);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for Context class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], Context.class);
+ }
+
+ public void testSuperClassDecoratorHasPrecedenceOverSubClassDecorator() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ //this tests that the LdapContext isn't returned even though it subclasses the DirContext
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS2);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for DirContext class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], DirContext.class);
+ }
+
+ public void testSubClassDecoratorCorrectlyIdentified() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS3);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for LdapContext class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ public void testMultipleDecoratorsDetectable() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> decorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS4);
+ assertEquals(decorators.size(), 2,
+ "Exactly 2 decorators should have been found for a class implementing 2 interfaces.");
+
+ boolean ldapContextDecoratorFound = false;
+ boolean eventContextDecoratorFound = false;
+
+ for (Object d : decorators) {
+ if (LdapContext.class.isAssignableFrom(d.getClass())) {
+ ldapContextDecoratorFound = true;
+ continue; //just to make sure that somehow the decorator doesn't implement both
+ }
+ if (EventContext.class.isAssignableFrom(d.getClass())) {
+ eventContextDecoratorFound = true;
+ }
+ }
+
+ assertTrue(ldapContextDecoratorFound && eventContextDecoratorFound,
+ "The found decorators don't implement the desired interfaces.");
+ }
+
+ public void testDecoratorsIdentifiedByMethod() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> decorators =
+ picker.getDecoratorsForMethod(LdapContext.class.getMethod("getConnectControls", (Class<?>[]) null));
+ assertEquals(decorators.size(), 1,
+ "Expected exactly one decorator for method 'getConnectControls()' from LdapContext class");
+ assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ public void testMethodFromSubclassMatchesSubclassDecorator() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ //this is a method from the DirContext but we're asking for it from a class
+ //that implements also an LdapContext
+ //The LdapContext decorator also inherits from the DirContext decorator
+ //(by the virtue of LdapContext interface inheriting from the DirContext)
+ //The picker should therefore match the LdapContext decorator because its
+ //the "closest" one to the actual class.
+ Set<Object> decorators =
+ picker.getDecoratorsForMethod(TEST_OBJECT_CLASS3.getMethod("getSchemaClassDefinition",
+ new Class<?>[] { String.class }));
+ assertEquals(decorators.size(), 1,
+ "Expected exactly one decorator for method 'getSchemaClassDefinition(String)' from LdapContext class");
+ assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ private static Class<?> createProxyClass(Class<?>... ifaces) {
+ return Proxy.getProxyClass(DecoratorPickerTest.class.getClassLoader(), ifaces);
+ }
+
+ private static DecoratorPicker<Object, Object> createTestPicker() {
+ DecoratorPicker<Object, Object> picker = new DecoratorPicker<Object, Object>();
+
+ DecoratorSetContext<Object, Object> decSet = new DecoratorSetContext<Object, Object>() {
+
+ public Object instantiate(Class<? extends Object> decoratorClass) throws Exception {
+ Constructor<? extends Object> ctor = decoratorClass.getConstructor(InvocationHandler.class);
+ return ctor.newInstance(DUMMY_HANDLER);
+ }
+
+ public void init(Object decorator, Object object) throws Exception {
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<Class<? extends Object>> getSupportedInterfaces() {
+ return new HashSet<Class<? extends Object>>(Arrays.asList(Context.class, EventContext.class,
+ LdapContext.class, DirContext.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<Class<? extends Object>> getDecoratorClasses() {
+ return new HashSet<Class<? extends Object>>(Arrays.asList(DECORATOR_CLASS1, DECORATOR_CLASS2, DECORATOR_CLASS3, DECORATOR_CLASS4));
+ }
+ };
+
+ picker.setContext(decSet);
+
+ return picker;
+ }
+}
diff --git a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
index 859b552..f231f15 100644
--- a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
+++ b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
@@ -225,6 +225,13 @@
<!-- JNDI -->
<!-- ==================================================================== -->
+ <!-- This installs a custom initial context factory builder into the JVM
+ that will ensure that all the default InitialContexts are going to check
+ for the permission to access the RHQ internals. -->
+ <mbean code="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
+ name="org.rhq:service=AccessCheckingInitialContextFactoryBuilderInstaller">
+ </mbean>
+
<!-- A simple mbean wrapper around the jndi Naming object. This
only handles an in memory instance. The NamingService uses this
as the JNDI store and exposes it remotely.
diff --git a/modules/enterprise/server/itests/pom.xml b/modules/enterprise/server/itests/pom.xml
index 8753e6f..6898621 100644
--- a/modules/enterprise/server/itests/pom.xml
+++ b/modules/enterprise/server/itests/pom.xml
@@ -56,6 +56,12 @@
<dependency>
<groupId>org.rhq</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
<artifactId>rhq-enterprise-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
diff --git a/modules/enterprise/server/jar/pom.xml b/modules/enterprise/server/jar/pom.xml
index 6eaf304..92f4cf1 100644
--- a/modules/enterprise/server/jar/pom.xml
+++ b/modules/enterprise/server/jar/pom.xml
@@ -78,6 +78,13 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<groupId>com.googlecode.java-diff-utils</groupId>
<artifactId>diffutils</artifactId>
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
index 39b6076..ecf2f6f 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
@@ -26,29 +26,41 @@ import java.util.Random;
import org.rhq.core.domain.auth.Subject;
import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
/**
* This is the JON Server's own session ID generator. It is outside any container-provided session mechanism. Its sole
* purpose is to provide session IDs to logged in {@link Subject}s. It will timeout those sessions regardless of any
* container-provided session-timeout mechanism.
- *
+ * <p>
+ * Because this is a very security-sensitive class, any public method requires the caller to
+ * have the {@link AllowEjbAccessPermission} as any other calls to the EJB layer. This is so that the
+ * malicious users can't trick the EJB layer into thinking that some users are logged in or log out other
+ * users.
+ * <p>
+ * Also, for security reasons, this class is final so that malicious code can't subclass it and modify its
+ * behavior.
+ *
* <p>This object is a {@link #getInstance() singleton}.</p>
*/
-public class SessionManager {
+public final class SessionManager {
+
+ private static final AllowRhqServerInternalsAccessPermission ACCESS_PERMISSION = new AllowRhqServerInternalsAccessPermission();
+
/**
* Our source for random session IDs.
*/
- private static Random _random = new Random();
+ private static final Random _random = new Random();
/**
* Our session cache that is keyed on the session ID.
*/
- private static Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
+ private static final Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
/**
* The singleton instance
*/
- private static SessionManager _manager = new SessionManager();
+ private static final SessionManager _manager = new SessionManager();
/**
* The timeout for all user sessions.
@@ -78,7 +90,7 @@ public class SessionManager {
/**
* Return the singleton object.
- *
+ *
* @return the {@link SessionManager}
*/
public static SessionManager getInstance() {
@@ -95,6 +107,7 @@ public class SessionManager {
* sessionId will be assigned.
*/
public Subject put(Subject subject) {
+ checkPermission();
return put(subject, DEFAULT_TIMEOUT);
}
@@ -108,6 +121,7 @@ public class SessionManager {
* that Subject is overlord). The sessionId will be assigned.
*/
public synchronized Subject put(Subject subject, long timeout) {
+ checkPermission();
Integer key;
do {
@@ -141,6 +155,7 @@ public class SessionManager {
* @throws SessionTimeoutException
*/
public synchronized Subject getSubject(int sessionId) throws SessionNotFoundException, SessionTimeoutException {
+ checkPermission();
Integer id = new Integer(sessionId);
AuthSession session = _cache.get(id);
@@ -162,6 +177,7 @@ public class SessionManager {
* @param sessionId session id to invalidate
*/
public synchronized void invalidate(int sessionId) {
+ checkPermission();
_cache.remove(new Integer(sessionId));
// while we are here, let's go through the entire session cache and remove expired sessions
@@ -187,6 +203,7 @@ public class SessionManager {
* @param username username for the sessions to be invalidated
*/
public synchronized void invalidate(String username) {
+ checkPermission();
List<Integer> doomedSessionIds = new ArrayList<Integer>(_cache.size());
for (AuthSession s : _cache.values()) {
if (username.equals(s.getSubject(false).getName())) {
@@ -201,6 +218,7 @@ public class SessionManager {
}
public long getlastAccess(int sessionId) {
+ checkPermission();
AuthSession session = _cache.get(sessionId);
if (session == null) {
return -1;
@@ -209,6 +227,7 @@ public class SessionManager {
}
public Subject getOverlord() {
+ checkPermission();
if (overlordSubject == null) {
overlordSubject = LookupUtil.getSubjectManager().getSubjectById(OVERLORD_SUBJECT_ID);
@@ -256,4 +275,9 @@ public class SessionManager {
return copy;
}
+
+ private static void checkPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+ }
}
\ No newline at end of file
diff --git a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
index 05edefa..85e2fb3 100644
--- a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
+++ b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
@@ -4,6 +4,14 @@
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
+ <!-- This installs a custom initial context factory builder into the JVM
+ that will ensure that all the default InitialContexts are going to check
+ for the permission to access the RHQ internals. -->
+ <bean class="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
+ name="AccessCheckingInitialContextFactoryBuilderInstaller">
+ </bean>
+
+
<bean name="Naming" class="org.jnp.server.SingletonNamingServer"/>
<bean name="InitialContextProperties" class="java.util.Hashtable">
@@ -20,7 +28,7 @@
</entry>
</map>
</parameter>
- </constructor>
+ </constructor>
</bean>
<bean name="java:comp/Initializer" class="org.jboss.ejb3.embedded.JavaCompInitializer">
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
new file mode 100644
index 0000000..1991e0e
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
@@ -0,0 +1,315 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-test</artifactId>
+ <packaging>jar</packaging>
+
+ <name>JNDI access integration test</name>
+ <description>Tests for local and remote JNDI access from within serverside scripts.</description>
+
+ <properties>
+ <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
+ <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
+ <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
+ <jnp.port>54987</jnp.port>
+ <jnp.rmiPort>54988</jnp.rmiPort>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <!--================ Test Deps ================ -->
+
+ <!-- Note, the test deps are intentionally placed above the other
+ scoped deps because of classpath reasons. Maven orders the [test] classpath
+ in the order listed in the pom. We specifically need the embeddable-ejb3
+ jar above the standard ejb3 jars because we need the embeddble packages loaded
+ when testing. -->
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-core-domain</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-core-client-api</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-server-client-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-remote-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss.jboss-embeddable-ejb3</groupId>
+ <artifactId>jboss-ejb3-all</artifactId>
+ <version>${jboss-embeddable-ejb3.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- NOTE: The remaining test deps correspond to the classes contained
+ in hibernate-all.jar and thirdparty-all.jar. -->
+
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- needed by embedded ejb container -->
+ <dependency>
+ <groupId>trove</groupId>
+ <artifactId>trove</artifactId>
+ <version>1.0.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- needed by embedded ejb container -->
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- 3rd Party Deps -->
+
+ <!-- required by RHQ server classes, as well as EJB3 Embedded -->
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1-jboss</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate</groupId>
+ <artifactId>hibernate3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-annotations</groupId>
+ <artifactId>hibernate-annotations</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-entitymanager</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-annotations-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed
+ by the PoolClass annotation used on some of our SLSB's -->
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <!-- for the transaction interrupt EJB3 interceptor -->
+ <dependency>
+ <groupId>org.jboss.transaction</groupId>
+ <artifactId>jboss-jta</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz-oracle</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
+ </dependency>
+
+ <!-- This is needed cglib which is in turn needed by hibernate -->
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.18</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <!-- in order to get JMS to work properly in embedded
+ test container, extract jms-rs.rar classes -->
+ <execution>
+ <id>Extract JMS classes from RAR needed for JMS tests</id>
+ <phase>process-classes</phase>
+ <configuration>
+ <tasks>
+ <unzip src="src/test/resources/jms-ra.rar"
+ dest="target">
+ <patternset>
+ <include name="jms-ra.jar" />
+ </patternset>
+ </unzip>
+ <unzip src="target/jms-ra.jar"
+ dest="target/test-classes">
+ <patternset>
+ <include name="org/**" />
+ </patternset>
+ </unzip>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <!-- Everything but the web service tests, this is the standard
+ test execution -->
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <groups>${rhq.testng.includedGroups}</groups>
+ <systemPropertyVariables>
+ <embeddedDeployment>true</embeddedDeployment>
+ <deploymentDirectory>target/test-classes</deploymentDirectory>
+ <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
+ <clean.db>${clean.db}</clean.db>
+ <test.server.jar.path>${settings.localRepository}/org/rhq/jndi-access-remote-server/${project.version}/jndi-access-remote-server-${project.version}.jar</test.server.jar.path>
+ <jnp.port>${jnp.port}</jnp.port>
+ <jnp.rmiPort>${jnp.rmiPort}</jnp.rmiPort>
+ </systemPropertyVariables>
+ <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
+ <additionalClasspathElements>
+ <!-- The below is required for tests to run against
+ Oracle. -->
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
new file mode 100644
index 0000000..f20d4f1
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
@@ -0,0 +1,193 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.SerializablePermission;
+import java.security.PermissionCollection;
+import java.util.Collections;
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Parameters;
+import org.testng.annotations.Test;
+
+import org.rhq.bindings.SandboxedScriptEngine;
+import org.rhq.bindings.ScriptEngineFactory;
+import org.rhq.bindings.StandardBindings;
+import org.rhq.bindings.StandardScriptPermissions;
+import org.rhq.bindings.util.PackageFinder;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class JndiAccessTest extends AbstractEJB3Test {
+ private static final Log JNP_SERVER_LOG = LogFactory.getLog("Test JNP Server");
+
+ private Process testServerProcess;
+ private Thread testServerStdErrReader;
+ private Thread testServerStdOutReader;
+
+ @BeforeClass
+ @Parameters({"test.server.jar.path", "jnp.port", "jnp.rmiPort"})
+ public void startTestJnpServer(String testServerJar, int jnpPort, int rmiPort) throws Exception {
+ ProcessBuilder bld = new ProcessBuilder("java", "-Djnp.port=" + jnpPort, "-Djnp.rmiPort=" + rmiPort, "-jar", testServerJar);
+
+ testServerProcess = bld.start();
+
+ testServerStdErrReader = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getErrorStream()));
+ try {
+ String line;
+ while((line = rdr.readLine()) != null) {
+ JNP_SERVER_LOG.warn(line);
+ }
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Reading test JNP server error output failed.", e);
+ } finally {
+ try {
+ rdr.close();
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Failed to close the test server error stream.", e);
+ }
+ }
+ }
+ });
+ testServerStdErrReader.start();
+
+ testServerStdOutReader = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getInputStream()));
+ try {
+ String line;
+ while((line = rdr.readLine()) != null) {
+ JNP_SERVER_LOG.debug(line);
+ }
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Reading test JNP server standard output failed.", e);
+ } finally {
+ try {
+ rdr.close();
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Failed to close the test server standard output stream.", e);
+ }
+ }
+ }
+ });
+ testServerStdOutReader.start();
+
+ //give the JNP server some time to start up
+ Thread.sleep(5000);
+ }
+
+ @AfterClass
+ public void stopTestJnpServer() throws Exception {
+ testServerProcess.destroy();
+ testServerStdErrReader.join();
+ testServerStdOutReader.join();
+ }
+
+ @Parameters("jnp.port")
+ public void testRemoteConnectionWorkingFromJava(int jnpPort) throws Exception {
+ Properties env = new Properties();
+ env.put("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory");
+ env.put("java.naming.provider.url", "jnp://localhost:" + jnpPort);
+ InitialContext ctx = new InitialContext(env);
+ Object kachny = ctx.lookup("kachny");
+
+ assert kachny != null;
+ }
+
+ public void testLocalJNDILookupFailsFromScripts() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ @Parameters("jnp.port")
+ public void testRemoteJNDILookupWorksFromScripts(int jnpPort) throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "env = new java.util.Hashtable();"
+ + "env.put('java.naming.factory.initial', 'org.jboss.naming.NamingContextFactory');"
+ + "env.put('java.naming.provider.url', 'jnp://localhost:" + jnpPort + "');"
+ + "context = new javax.naming.InitialContext(env);\n"
+ + "kachny = context.lookup('kachny');\n"
+ + "assertNotNull(kachny);\n");
+ } catch (ScriptException e) {
+ Assert.fail("The script should have been able to access a remote JNDI server.", e);
+ }
+ }
+
+ private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
+ StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
+ ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
+
+ PermissionCollection perms = new StandardScriptPermissions();
+
+ return new SandboxedScriptEngine(engine, perms);
+ }
+
+ private static void checkIsDesiredSecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
+ }
+}
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
new file mode 100644
index 0000000..1951b84
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
@@ -0,0 +1,26 @@
+# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
+# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
+# WORK IN THIS MODULE.
+
+hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
+#hibernate.connection.release_mode=after_statement
+#hibernate.transaction.flush_before_completion=false
+#hibernate.transaction.auto_close_session=false
+#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
+#hibernate.hbm2ddl.auto=create-drop
+#hibernate.hbm2ddl.auto=create
+hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
+# Clustered cache with TreeCache
+#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
+#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
+#hibernate.dialect=org.hibernate.dialect.HSQLDialect
+hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+hibernate.bytecode.use_reflection_optimizer=false
+# I don't think this is honored, but EJB3Deployer uses it
+hibernate.bytecode.provider=javassist
+hibernate.jdbc.use_streams_for_binary=true
+hibernate.show_sql=false
+hibernate.format_sql=true
+hibernate.default_batch_fetch_size=16
+hibernate.jdbc.batch_size=20
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
new file mode 100644
index 0000000..ec09ed7
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<!-- $Id: log4j.xml 39945 2006-01-12 02:44:07Z bill $ -->
+
+<!--
+ | For more configuration infromation and examples see the Jakarta Log4j
+ | owebsite: http://jakarta.apache.org/log4j
+ -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
+ <param name="Target" value="System.out"/>
+ <param name="Threshold" value="WARN"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <!-- The default pattern: Date Priority [Category] Messagen -->
+ <!--
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+ -->
+ <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
+ <param name="File" value="target/server-jar-test.log"/>
+ <param name="Threshold" value="WARN"/>
+ <param name="Append" value="false"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <!-- The default pattern: Date Priority [Category] Messagen -->
+ <!--
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+ -->
+ <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
+ </layout>
+ </appender>
+
+ <category name="Test JNP Server">
+ <priority value="DEBUG"/>
+ </category>
+
+ <!-- Hibernate logs WARNINGS frequent from this class, in test envs. -->
+ <category name="org.hibernate.hql.ast.QueryTranslatorImpl">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- hides the TIMER SERVICE IS NOT INSTALLED warning - we know embedded EJB3 container doesn't support timers -->
+ <category name="org.jboss.ejb3.timerservice.jboss.JBossTimerServiceFactory">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- hides the shutdown warnings - for some reason, the container spits out some warnings when shutting down -->
+ <category name="org.jboss.kernel.plugins.dependency.StartStopLifecycleAction">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- Hibernate SQL logs -->
+ <!--
+ <category name="org.hibernate.SQL">
+ <priority value="DEBUG"/>
+ </category>
+ -->
+
+ <root>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ </root>
+
+</log4j:configuration>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
new file mode 100644
index 0000000..8860b47
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
@@ -0,0 +1,10 @@
+// We need the SecurityManager installed to enable sandboxing of CLI scripts
+// but we don't define any other security measures on the RHQ server itself.
+//
+// Granting all permissions allows us to run the RHQ server as if no security
+// manager was in place (which is assumed by default by JBoss AS) but be able
+// to use it when we need it for our own purposes.
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/modules/integration-tests/jndi-access/pom.xml b/modules/integration-tests/jndi-access/pom.xml
new file mode 100644
index 0000000..6e9c673
--- /dev/null
+++ b/modules/integration-tests/jndi-access/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>rhq-integration-tests</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <name>JNDI access tests</name>
+ <description>Tests for the secured JNDI access tests</description>
+
+ <modules>
+ <module>remote-server</module>
+ <module>jndi-access-test</module>
+ </modules>
+</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/pom.xml b/modules/integration-tests/jndi-access/remote-server/pom.xml
new file mode 100644
index 0000000..9046e6f
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/pom.xml
@@ -0,0 +1,72 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-remote-server</artifactId>
+ <packaging>jar</packaging>
+
+ <name>Test JNDI-enabled remote server</name>
+ <description>
+ A testing JNDI-enabled server to test the ability to connect to remote servers without security
+ checks from within the scripts running inside the RHQ server.
+ </description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jnpserver</artifactId>
+ <version>4.2.2.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-common</artifactId>
+ <version>4.2.2.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>oswego-concurrent</groupId>
+ <artifactId>concurrent</artifactId>
+ <version>1.3.4-jboss</version>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package</id>
+ <phase>package</phase>
+ <goals><goal>single</goal></goals>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>org.rhq.jndi.test.Server</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java b/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
new file mode 100644
index 0000000..7bfb8e8
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
@@ -0,0 +1,79 @@
+package org.rhq.jndi.test;
+import java.util.Properties;
+
+import javax.naming.CompoundName;
+
+import org.jnp.server.Main;
+import org.jnp.server.NamingBeanImpl;
+
+import org.jboss.logging.Logger;
+
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class Server {
+ private static final Logger LOG = Logger.getLogger(Server.class);
+
+ private static Server INSTANCE;
+
+ private Main jnpServer;
+
+ public static void main(String[] args) throws Exception {
+ LOG.debug("System properties: " + System.getProperties());
+ Server.start();
+ }
+
+ private Server() {
+ jnpServer = new Main("org.rhq.jndi.access.test.server");
+ }
+
+ public static synchronized Server getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new Server();
+ }
+
+ return INSTANCE;
+ }
+
+ public static void start() throws Exception {
+ LOG.debug("Initializing the JNP server");
+
+ NamingBeanImpl nbi = new NamingBeanImpl();
+ getInstance().jnpServer.setNamingInfo(nbi);
+ nbi.start();
+
+ LOG.debug("Binding kachny");
+
+ nbi.getNamingInstance().bind(new CompoundName("kachny", new Properties()), "KACHNY!", String.class.getName());
+
+ LOG.debug("Starting the JNP server");
+
+ getInstance().jnpServer.start();
+ }
+
+ public static void stop() {
+ LOG.debug("Stopping the JNP server");
+ getInstance().jnpServer.stop();
+ }
+}
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
new file mode 100644
index 0000000..a45f2ce
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jboss.naming.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
new file mode 100644
index 0000000..2d41f83
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootCategory=TRACE, CONSOLE
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c] %m%n
diff --git a/modules/integration-tests/pom.xml b/modules/integration-tests/pom.xml
index 0290729..969b94a 100644
--- a/modules/integration-tests/pom.xml
+++ b/modules/integration-tests/pom.xml
@@ -62,6 +62,7 @@
<id>integration-tests</id>
<modules>
<module>apache-plugin-test</module>
+ <module>jndi-access</module>
<!--<module>mod_cluster-plugin-test</module>-->
</modules>
</profile>
commit 1174064a0372d31199d75939b64d36eaa2232d02
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 12 16:51:18 2012 -0500
[BZ 672947] add favorite groups portlet
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/PortletFactory.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/PortletFactory.java
index b2aa035..67937b0 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/PortletFactory.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/PortletFactory.java
@@ -30,6 +30,7 @@ import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.dashboard.DashboardPortlet;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.ImageManager;
+import org.rhq.enterprise.gui.coregui.client.dashboard.portlets.groups.FavoriteGroupsPortlet;
import org.rhq.enterprise.gui.coregui.client.dashboard.portlets.groups.GroupAlertsPortlet;
import org.rhq.enterprise.gui.coregui.client.dashboard.portlets.groups.GroupBundleDeploymentsPortlet;
import org.rhq.enterprise.gui.coregui.client.dashboard.portlets.groups.GroupConfigurationUpdatesPortlet;
@@ -105,6 +106,7 @@ public class PortletFactory {
globalPortletFactoryMap.put(TagCloudPortlet.KEY, TagCloudPortlet.Factory.INSTANCE);
}
globalPortletFactoryMap.put(FavoriteResourcesPortlet.KEY, FavoriteResourcesPortlet.Factory.INSTANCE);
+ globalPortletFactoryMap.put(FavoriteGroupsPortlet.KEY, FavoriteGroupsPortlet.Factory.INSTANCE);
globalPortletFactoryMap.put(MashupPortlet.KEY, MashupPortlet.Factory.INSTANCE);
globalPortletFactoryMap.put(MessagePortlet.KEY, MessagePortlet.Factory.INSTANCE);
globalPortletFactoryMap.put(ProblemResourcesPortlet.KEY, ProblemResourcesPortlet.Factory.INSTANCE);
@@ -125,6 +127,7 @@ public class PortletFactory {
globalPortletNameMap.put(TagCloudPortlet.NAME, TagCloudPortlet.KEY);
}
globalPortletNameMap.put(FavoriteResourcesPortlet.NAME, FavoriteResourcesPortlet.KEY);
+ globalPortletNameMap.put(FavoriteGroupsPortlet.NAME, FavoriteGroupsPortlet.KEY);
globalPortletNameMap.put(MashupPortlet.NAME, MashupPortlet.KEY);
globalPortletNameMap.put(MessagePortlet.NAME, MessagePortlet.KEY);
globalPortletNameMap.put(ProblemResourcesPortlet.NAME, ProblemResourcesPortlet.KEY);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/groups/FavoriteGroupsPortlet.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/groups/FavoriteGroupsPortlet.java
new file mode 100644
index 0000000..b438071
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/groups/FavoriteGroupsPortlet.java
@@ -0,0 +1,151 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2010 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.dashboard.portlets.groups;
+
+import java.util.Set;
+
+import com.google.gwt.user.client.Timer;
+import com.smartgwt.client.data.Criteria;
+import com.smartgwt.client.types.Overflow;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.HTMLFlow;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.events.FieldStateChangedEvent;
+import com.smartgwt.client.widgets.grid.events.FieldStateChangedHandler;
+
+import org.rhq.core.domain.common.EntityContext;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.dashboard.DashboardPortlet;
+import org.rhq.enterprise.gui.coregui.client.UserSessionManager;
+import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshPortlet;
+import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshPortletUtil;
+import org.rhq.enterprise.gui.coregui.client.dashboard.Portlet;
+import org.rhq.enterprise.gui.coregui.client.dashboard.PortletViewFactory;
+import org.rhq.enterprise.gui.coregui.client.dashboard.PortletWindow;
+import org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupCompositeDataSource;
+import org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupListView;
+
+public class FavoriteGroupsPortlet extends ResourceGroupListView implements AutoRefreshPortlet {
+
+ // A non-displayed, persisted identifier for the portlet
+ public static final String KEY = "FavoriteGroups";
+ // A default displayed, persisted name for the portlet
+ public static final String NAME = MSG.favorites_groups();
+
+ public static final String CFG_TABLE_PREFS = "tablePreferences";
+
+ // set on initial configuration, the window for this portlet view.
+ private PortletWindow portletWindow;
+
+ private Timer refreshTimer;
+
+ public FavoriteGroupsPortlet(String locatorId) {
+ super(locatorId, createInitialCriteria(), NAME);
+ setOverflow(Overflow.VISIBLE);
+
+ setShowHeader(false);
+ setShowFooter(false);
+ }
+
+ private static Criteria createInitialCriteria() {
+ Set<Integer> favoriteIds = UserSessionManager.getUserPreferences().getFavoriteResourceGroups();
+
+ Integer[] favArray = favoriteIds.toArray(new Integer[favoriteIds.size()]);
+
+ Criteria criteria = new Criteria();
+ if (favoriteIds.isEmpty()) {
+ criteria.addCriteria("id", -1);
+ } else {
+ criteria.addCriteria(ResourceGroupCompositeDataSource.FILTER_GROUP_IDS, favArray);
+ }
+
+ return criteria;
+ }
+
+ @Override
+ protected void configureTable() {
+ super.configureTable();
+
+ getListGrid().addFieldStateChangedHandler(new FieldStateChangedHandler() {
+ public void onFieldStateChanged(FieldStateChangedEvent fieldStateChangedEvent) {
+ String state = getListGrid().getViewState();
+
+ portletWindow.getStoredPortlet().getConfiguration().put(new PropertySimple(CFG_TABLE_PREFS, state));
+ portletWindow.save();
+ }
+ });
+
+ DashboardPortlet storedPortlet = portletWindow.getStoredPortlet();
+ if ((null != storedPortlet && null != storedPortlet.getConfiguration())) {
+
+ PropertySimple tablePrefs = storedPortlet.getConfiguration().getSimple(CFG_TABLE_PREFS);
+ ListGrid listGrid = getListGrid();
+ if (null != tablePrefs && null != listGrid) {
+ String state = tablePrefs.getStringValue();
+ listGrid.setViewState(state);
+ }
+ }
+ }
+
+ public void configure(PortletWindow portletWindow, DashboardPortlet storedPortlet) {
+ if (null == this.portletWindow && null != portletWindow) {
+ this.portletWindow = portletWindow;
+ }
+ }
+
+ public Canvas getHelpCanvas() {
+ return new HTMLFlow(MSG.view_portlet_help_favoriteResources());
+ }
+
+ public static final class Factory implements PortletViewFactory {
+ public static PortletViewFactory INSTANCE = new Factory();
+
+ public final Portlet getInstance(String locatorId, EntityContext context) {
+
+ return new FavoriteGroupsPortlet(locatorId);
+ }
+ }
+
+ public void startRefreshCycle() {
+ refreshTimer = AutoRefreshPortletUtil.startRefreshCycle(this, this, refreshTimer);
+ }
+
+ @Override
+ protected void onDestroy() {
+ AutoRefreshPortletUtil.onDestroy(this, refreshTimer);
+
+ super.onDestroy();
+ }
+
+ public boolean isRefreshing() {
+ return false;
+ }
+
+ @Override
+ public void refresh() {
+ if (!isRefreshing()) {
+ super.refresh();
+ }
+ }
+
+}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/inventory/resource/FavoriteResourcesPortlet.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/inventory/resource/FavoriteResourcesPortlet.java
index b9f7e31..7d94624 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/inventory/resource/FavoriteResourcesPortlet.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/inventory/resource/FavoriteResourcesPortlet.java
@@ -42,6 +42,7 @@ import org.rhq.enterprise.gui.coregui.client.dashboard.AutoRefreshPortletUtil;
import org.rhq.enterprise.gui.coregui.client.dashboard.Portlet;
import org.rhq.enterprise.gui.coregui.client.dashboard.PortletViewFactory;
import org.rhq.enterprise.gui.coregui.client.dashboard.PortletWindow;
+import org.rhq.enterprise.gui.coregui.client.inventory.resource.ResourceDatasource;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.ResourceSearchView;
/**
@@ -78,7 +79,7 @@ public class FavoriteResourcesPortlet extends ResourceSearchView implements Auto
if (favoriteIds.isEmpty()) {
criteria.addCriteria("id", -1);
} else {
- criteria.addCriteria("resourceIds", favArray);
+ criteria.addCriteria(ResourceDatasource.FILTER_RESOURCE_IDS, favArray);
}
return criteria;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupCompositeDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupCompositeDataSource.java
index 17b2b56..4a87378 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupCompositeDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupCompositeDataSource.java
@@ -18,6 +18,14 @@
*/
package org.rhq.enterprise.gui.coregui.client.inventory.groups;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.AVAIL_CHILDREN;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.AVAIL_DESCENDANTS;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.CATEGORY;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.DESCRIPTION;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.NAME;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.PLUGIN;
+import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.TYPE;
+
import java.util.List;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -43,13 +51,13 @@ import org.rhq.enterprise.gui.coregui.client.gwt.ResourceGroupGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
-import static org.rhq.enterprise.gui.coregui.client.inventory.groups.ResourceGroupDataSourceField.*;
-
/**
* @author Joseph Marques
*/
public class ResourceGroupCompositeDataSource extends RPCDataSource<ResourceGroupComposite, ResourceGroupCriteria> {
+ public static final String FILTER_GROUP_IDS = "resourceGroupIds";
+
ResourceGroupGWTServiceAsync groupService = GWTServiceLookup.getResourceGroupService();
private static ResourceGroupCompositeDataSource INSTANCE;
@@ -80,8 +88,8 @@ public class ResourceGroupCompositeDataSource extends RPCDataSource<ResourceGrou
nameDataField.setCanEdit(false);
fields.add(nameDataField);
- DataSourceTextField descriptionDataField = new DataSourceTextField(DESCRIPTION.propertyName(), DESCRIPTION
- .title());
+ DataSourceTextField descriptionDataField = new DataSourceTextField(DESCRIPTION.propertyName(),
+ DESCRIPTION.title());
descriptionDataField.setCanEdit(false);
fields.add(descriptionDataField);
@@ -125,12 +133,14 @@ public class ResourceGroupCompositeDataSource extends RPCDataSource<ResourceGrou
ResourceGroupCriteria criteria = new ResourceGroupCriteria();
criteria.setPageControl(getPageControl(request));
+ criteria.addFilterId(getFilter(request, "id", Integer.class));
criteria.addFilterName(getFilter(request, NAME.propertyName(), String.class));
criteria.addFilterGroupCategory(getFilter(request, CATEGORY.propertyName(), GroupCategory.class));
criteria.addFilterDownMemberCount(getFilter(request, "downMemberCount", Long.class));
criteria.addFilterExplicitResourceIds(getFilter(request, "explicitResourceId", Integer.class));
criteria.addFilterGroupDefinitionId(getFilter(request, "groupDefinitionId", Integer.class));
criteria.setSearchExpression(getFilter(request, "search", String.class));
+ criteria.addFilterIds(getArrayFilter(request, FILTER_GROUP_IDS, Integer.class));
return criteria;
}
@@ -202,14 +212,15 @@ public class ResourceGroupCompositeDataSource extends RPCDataSource<ResourceGrou
StringBuilder results = new StringBuilder();
results.append("<table width=\"120px\"><tr>");
if (up == 0 && down == 0) {
- results.append(getColumn(false, "<img src=\""
- + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(null)) + "\" /> 0"));
+ results.append(getColumn(false,
+ "<img src=\"" + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(null)) + "\" /> 0"));
results.append(getColumn(true));
results.append(getColumn(false));
} else {
if (up > 0) {
- results.append(getColumn(false, " <img src=\""
- + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(Boolean.TRUE)) + "\" />", up));
+ results.append(getColumn(false,
+ " <img src=\"" + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(Boolean.TRUE))
+ + "\" />", up));
}
if (up > 0 && down > 0) {
@@ -217,8 +228,9 @@ public class ResourceGroupCompositeDataSource extends RPCDataSource<ResourceGrou
}
if (down > 0) {
- results.append(getColumn(false, " <img src=\""
- + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(Boolean.FALSE)) + "\" />", down));
+ results.append(getColumn(false,
+ " <img src=\"" + ImageManager.getFullImagePath(ImageManager.getAvailabilityIcon(Boolean.FALSE))
+ + "\" />", down));
} else {
results.append(getColumn(false,
" <img src=\"/images/blank.png\" width=\"16px\" height=\"16px\" />"));
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupsDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupsDataSource.java
index 83c356f..9f2cd03 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupsDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/ResourceGroupsDataSource.java
@@ -51,6 +51,8 @@ import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
*/
public class ResourceGroupsDataSource extends RPCDataSource<ResourceGroup, ResourceGroupCriteria> {
+ public static final String FILTER_GROUP_IDS = "resourceGroupIds";
+
private ResourceGroupGWTServiceAsync groupService = GWTServiceLookup.getResourceGroupService();
private static ResourceGroupsDataSource INSTANCE;
@@ -79,8 +81,8 @@ public class ResourceGroupsDataSource extends RPCDataSource<ResourceGroup, Resou
DataSourceTextField nameDataField = new DataSourceTextField(NAME.propertyName(), NAME.title(), 200);
fields.add(nameDataField);
- DataSourceTextField descriptionDataField = new DataSourceTextField(DESCRIPTION.propertyName(), DESCRIPTION
- .title());
+ DataSourceTextField descriptionDataField = new DataSourceTextField(DESCRIPTION.propertyName(),
+ DESCRIPTION.title());
fields.add(descriptionDataField);
DataSourceTextField typeNameDataField = new DataSourceTextField(TYPE.propertyName(), TYPE.title());
@@ -117,12 +119,14 @@ public class ResourceGroupsDataSource extends RPCDataSource<ResourceGroup, Resou
ResourceGroupCriteria criteria = new ResourceGroupCriteria();
criteria.setPageControl(getPageControl(request));
+ criteria.addFilterId(getFilter(request, "id", Integer.class));
criteria.addFilterName(getFilter(request, NAME.propertyName(), String.class));
criteria.addFilterGroupCategory(getFilter(request, CATEGORY.propertyName(), GroupCategory.class));
criteria.addFilterDownMemberCount(getFilter(request, "downMemberCount", Long.class));
criteria.addFilterExplicitResourceIds(getFilter(request, "explicitResourceId", Integer.class));
criteria.addFilterGroupDefinitionId(getFilter(request, "groupDefinitionId", Integer.class));
criteria.setSearchExpression(getFilter(request, "search", String.class));
+ criteria.addFilterIds(getArrayFilter(request, FILTER_GROUP_IDS, Integer.class));
return criteria;
}
commit f9a99a4e1f83f3bc74b4fae5a8515914f69b15a5
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Jan 12 13:46:23 2012 -0500
[Bug 535725 - (RHQ-2391) Logfile parser ignores lines where severity is not surrounded by spaces]
I've updated our logEntry pattern handling to allow for bracket or paren
delimiters, with optional spacing, around the severity. So, the
following should all now match, for example:
2012-01-05 11:42:13,607 INFO [org.foo.Baz] my message
2012-01-05 11:42:13,607 [INFO] [org.foo.Baz] my message
2012-01-05 11:42:13,607 ( INFO ) [org.foo.Baz] my message
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessor.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessor.java
index 8b5caa0..9eb4f09 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessor.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessor.java
@@ -35,15 +35,23 @@ import org.rhq.core.domain.event.EventSeverity;
/**
* A {@link org.rhq.core.pluginapi.event.log.LogEntryProcessor} for Log4J log files.
- *
+ * <pre>
+ * By default we support log entries of the format: date [delimiter]severity[delimiter] message
+ * Where:
+ * - the optional delimiters are either square brackets ort parens, with or without spaces
+ * - the date format is one of the built-ins below, or a user-specified date format for the logfile source
+ * - the message portion may contain multiple lines.
+ * For example:
+ * 2007-12-21 15:32:49,514 DEBUG [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000
+ * 2007/12/21 15:32:49,514 (DEBUG) [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000
+ * 2007-Dec-21 15:32:49 [ DEBUG ] [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000
+ * </pre>
* @author Ian Springer
*/
public class Log4JLogEntryProcessor extends MultiLineLogEntryProcessor {
- // For now, we only support the default pattern: date priority '['category']' message
- // e.g.: 2007-12-09 15:32:49,514 DEBUG [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000
- // NOTE: The message portion may contain multiple lines.
- private static final String REGEX = "(.*?) (TRACE|DEBUG|INFO|WARN|ERROR|FATAL) (.*)";
- private static final Pattern PATTERN = Pattern.compile(REGEX);
+
+ private static final String REGEX;
+ private static final Pattern PATTERN;
private static final String ISO8601_DATE_PATTERN = "yyyy-MM-dd kk:mm:ss,SSS";
private static final DateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat(ISO8601_DATE_PATTERN);
@@ -55,6 +63,12 @@ public class Log4JLogEntryProcessor extends MultiLineLogEntryProcessor {
private static final Map<Priority, EventSeverity> PRIORITY_TO_SEVERITY_MAP = new LinkedHashMap<Priority, EventSeverity>();
static {
+ // just in case there is something unanticipated that our default pattern doesn't like, allow
+ // a backdoor prop to set the REGEX pattern.
+ String regex = System.getProperty("rhq.agent.event.log4j.regex");
+ REGEX = (null != regex) ? regex : "(.*?) [\\[\\(]??\\s*(TRACE|DEBUG|INFO|WARN|ERROR|FATAL)\\s*[\\]\\)]?? (.*)";
+ PATTERN = Pattern.compile(REGEX);
+
PRIORITY_TO_SEVERITY_MAP.put(Priority.TRACE, EventSeverity.DEBUG);
PRIORITY_TO_SEVERITY_MAP.put(Priority.DEBUG, EventSeverity.DEBUG);
PRIORITY_TO_SEVERITY_MAP.put(Priority.INFO, EventSeverity.INFO);
diff --git a/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessorTest.java b/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessorTest.java
index e38e1be..78d98ce 100644
--- a/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessorTest.java
+++ b/modules/core/plugin-api/src/test/java/org/rhq/core/pluginapi/event/log/Log4JLogEntryProcessorTest.java
@@ -1,92 +1,159 @@
- /*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.rhq.core.pluginapi.event.log;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.StringReader;
-import java.util.Calendar;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.testng.annotations.Test;
-
-import org.rhq.core.domain.event.Event;
-import org.rhq.core.domain.event.EventSeverity;
-
-/**
- * @author Ian Springer
- */
-@Test
-public class Log4JLogEntryProcessorTest {
- private static final String LINE_SEPARATOR = System.getProperty("line.separator");
- private static final StringBuilder TEST_LOG = new StringBuilder();
- static {
- TEST_LOG.append(
- "2007-12-09 15:32:49,909 DEBUG [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000")
- .append(LINE_SEPARATOR);
- TEST_LOG.append("2008-02-09 02:10:11,909 INFO [com.example.FooBar] a multi-line entry").append(LINE_SEPARATOR);
- TEST_LOG.append("\tyada yada yada").append(LINE_SEPARATOR);
- TEST_LOG.append("\twocka wocka").append(LINE_SEPARATOR);
- }
-
- public void testProcessLine() throws Exception {
- String eventType = "logEntry";
- File logFile = new File("C:/test.log");
- System.out.println("Testing with no includes pattern...");
- Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(eventType, logFile);
- BufferedReader bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
- Set<Event> events = processor.processLines(bufferedReader);
- assert events != null && events.size() == 2;
- Iterator<Event> eventIterator = events.iterator();
- Event event1 = eventIterator.next();
- assert eventType.equals(event1.getType());
- assert new File(event1.getSourceLocation()).equals(logFile);
- Calendar calendar = Calendar.getInstance();
- calendar.set(2007, 11, 9, 15, 32, 49);
- calendar.set(Calendar.MILLISECOND, 909);
- long expectedTimestamp = calendar.getTimeInMillis();
- assert event1.getTimestamp() == expectedTimestamp;
- assert event1.getSeverity().equals(EventSeverity.DEBUG);
- assert event1.getDetail().equals("[com.example.FooBar] run: IdleRemover notifying pools, interval: 450000");
- Event event2 = eventIterator.next();
- assert event2.getDetail().startsWith("[com.example.FooBar] a multi-line entry\n");
- assert event2.getDetail().endsWith("\twocka wocka");
- System.out.println("SUCCESS!");
- System.out.println("Testing with matching includes pattern...");
- processor.setIncludesPattern(Pattern.compile("wocka wocka"));
- bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
- events = processor.processLines(bufferedReader);
- assert events != null && events.size() == 1;
- event1 = events.iterator().next();
- assert event1.getDetail().endsWith("\twocka wocka");
- System.out.println("SUCCESS!");
- System.out.println("Testing with non-matching includes pattern...");
- processor.setIncludesPattern(Pattern.compile("hubba bubba"));
- bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
- events = processor.processLines(bufferedReader);
- assert events != null && events.size() == 0;
- System.out.println("SUCCESS!");
- }
-}
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.pluginapi.event.log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.StringReader;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.testng.annotations.Test;
+
+import org.rhq.core.domain.event.Event;
+import org.rhq.core.domain.event.EventSeverity;
+
+/**
+ * @author Ian Springer
+ */
+@Test
+public class Log4JLogEntryProcessorTest {
+ private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+ private static final StringBuilder TEST_LOG = new StringBuilder();
+ static {
+ TEST_LOG.append(
+ "2007-12-09 15:32:49,909 DEBUG [com.example.FooBar] run: IdleRemover notifying pools, interval: 450000")
+ .append(LINE_SEPARATOR);
+ TEST_LOG.append("2008-02-09 02:10:11,909 INFO [com.example.FooBar] a multi-line entry").append(LINE_SEPARATOR);
+ TEST_LOG.append("\tyada yada yada").append(LINE_SEPARATOR);
+ TEST_LOG.append("\twocka wocka").append(LINE_SEPARATOR);
+ }
+
+ public void testProcessLine() throws Exception {
+ String eventType = "logEntry";
+ File logFile = new File("C:/test.log");
+ System.out.println("Testing with no includes pattern...");
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(eventType, logFile);
+ BufferedReader bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
+ Set<Event> events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 2;
+ Iterator<Event> eventIterator = events.iterator();
+ Event event1 = eventIterator.next();
+ assert eventType.equals(event1.getType());
+ assert new File(event1.getSourceLocation()).equals(logFile);
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2007, 11, 9, 15, 32, 49);
+ calendar.set(Calendar.MILLISECOND, 909);
+ long expectedTimestamp = calendar.getTimeInMillis();
+ assert event1.getTimestamp() == expectedTimestamp;
+ assert event1.getSeverity().equals(EventSeverity.DEBUG);
+ assert event1.getDetail().equals("[com.example.FooBar] run: IdleRemover notifying pools, interval: 450000");
+ Event event2 = eventIterator.next();
+ assert event2.getDetail().startsWith("[com.example.FooBar] a multi-line entry\n");
+ assert event2.getDetail().endsWith("\twocka wocka");
+ System.out.println("SUCCESS!");
+ System.out.println("Testing with matching includes pattern...");
+ processor.setIncludesPattern(Pattern.compile("wocka wocka"));
+ bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
+ events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 1;
+ event1 = events.iterator().next();
+ assert event1.getDetail().endsWith("\twocka wocka");
+ System.out.println("SUCCESS!");
+ System.out.println("Testing with non-matching includes pattern...");
+ processor.setIncludesPattern(Pattern.compile("hubba bubba"));
+ bufferedReader = new BufferedReader(new StringReader(TEST_LOG.toString()));
+ events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 0;
+ System.out.println("SUCCESS!");
+ }
+
+ public void testProcessLineBracketDelimitedSeverity() throws Exception {
+ String eventType = "logEntry";
+ File logFile = new File("C:/test.log");
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(eventType, logFile);
+
+ String logEntry = "2007-12-09 15:32:49,909 [DEBUG] [com.example.FooBar] test message";
+ BufferedReader bufferedReader = new BufferedReader(new StringReader(logEntry));
+ Set<Event> events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 1;
+ Iterator<Event> eventIterator = events.iterator();
+ Event event1 = eventIterator.next();
+ assert eventType.equals(event1.getType());
+ assert new File(event1.getSourceLocation()).equals(logFile);
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2007, 11, 9, 15, 32, 49);
+ calendar.set(Calendar.MILLISECOND, 909);
+ long expectedTimestamp = calendar.getTimeInMillis();
+ assert event1.getTimestamp() == expectedTimestamp;
+ assert event1.getSeverity().equals(EventSeverity.DEBUG);
+ assert event1.getDetail().equals("[com.example.FooBar] test message");
+ }
+
+ public void testProcessLineParenDelimitedSeverity() throws Exception {
+ String eventType = "logEntry";
+ File logFile = new File("C:/test.log");
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(eventType, logFile);
+
+ String logEntry = "2007-12-09 15:32:49,909 (DEBUG) [com.example.FooBar] test message";
+ BufferedReader bufferedReader = new BufferedReader(new StringReader(logEntry));
+ Set<Event> events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 1;
+ Iterator<Event> eventIterator = events.iterator();
+ Event event1 = eventIterator.next();
+ assert eventType.equals(event1.getType());
+ assert new File(event1.getSourceLocation()).equals(logFile);
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2007, 11, 9, 15, 32, 49);
+ calendar.set(Calendar.MILLISECOND, 909);
+ long expectedTimestamp = calendar.getTimeInMillis();
+ assert event1.getTimestamp() == expectedTimestamp;
+ assert event1.getSeverity().equals(EventSeverity.DEBUG);
+ assert event1.getDetail().equals("[com.example.FooBar] test message");
+ }
+
+ public void testProcessLineSpacedDelimitedSeverity() throws Exception {
+ String eventType = "logEntry";
+ File logFile = new File("C:/test.log");
+ Log4JLogEntryProcessor processor = new Log4JLogEntryProcessor(eventType, logFile);
+
+ String logEntry = "2007-12-09 15:32:49,909 [ DEBUG ) [com.example.FooBar] test message";
+ BufferedReader bufferedReader = new BufferedReader(new StringReader(logEntry));
+ Set<Event> events = processor.processLines(bufferedReader);
+ assert events != null && events.size() == 1;
+ Iterator<Event> eventIterator = events.iterator();
+ Event event1 = eventIterator.next();
+ assert eventType.equals(event1.getType());
+ assert new File(event1.getSourceLocation()).equals(logFile);
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(2007, 11, 9, 15, 32, 49);
+ calendar.set(Calendar.MILLISECOND, 909);
+ long expectedTimestamp = calendar.getTimeInMillis();
+ assert event1.getTimestamp() == expectedTimestamp;
+ assert event1.getSeverity().equals(EventSeverity.DEBUG);
+ assert event1.getDetail().equals("[com.example.FooBar] test message");
+ }
+
+}
commit 7d14f7484ad758be037694e3599654e4fcb11a88
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Jan 12 16:45:50 2012 +0100
Increasing the log level back to WARN now that the tests are working again.
diff --git a/modules/enterprise/server/itests/src/test/resources/log4j.xml b/modules/enterprise/server/itests/src/test/resources/log4j.xml
index 1e37497..bc65329 100644
--- a/modules/enterprise/server/itests/src/test/resources/log4j.xml
+++ b/modules/enterprise/server/itests/src/test/resources/log4j.xml
@@ -19,7 +19,7 @@
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
<param name="Target" value="System.out"/>
- <param name="Threshold" value="INFO"/>
+ <param name="Threshold" value="WARN"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Messagen -->
@@ -32,7 +32,7 @@
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="target/server-jar-test.log"/>
- <param name="Threshold" value="INFO"/>
+ <param name="Threshold" value="WARN"/>
<param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
commit 759b64ee6b76525650ebece39459bf9abe5c7dd4
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Jan 12 16:45:20 2012 +0100
Making the script security work with Java 6u27 and up.
Due to CVE-2011-3544 the Rhino script engine changed the way it applies
security permissions which broke our original sandboxing approach.
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/SandboxedScriptEngine.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/SandboxedScriptEngine.java
index 7b34c6d..f994f09 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/SandboxedScriptEngine.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/SandboxedScriptEngine.java
@@ -40,6 +40,9 @@ import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
/**
+ * <b>DO NOT USE THIS CLASS DIRECTLY!!!!</b> Use {@link org.rhq.bindings.ScriptEngineFactory#getSecuredScriptEngine(String, org.rhq.bindings.util.PackageFinder, StandardBindings, PermissionCollection)}
+ * method instead for a reliably secured script engine.
+ * <p>
* This is a decorator class for any other {@link ScriptEngine} implementation
* that runs any of the eval methods with the defined set of {@link Permission}s.
* <p>
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/ScriptEngineFactory.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/ScriptEngineFactory.java
index 168d2fb..5834922 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/ScriptEngineFactory.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/ScriptEngineFactory.java
@@ -25,6 +25,15 @@ import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -79,7 +88,7 @@ public class ScriptEngineFactory {
public static ScriptEngine getScriptEngine(String language, PackageFinder packageFinder, StandardBindings bindings)
throws ScriptException, IOException {
ScriptEngineInitializer initializer = getInitializer(language);
-
+
if (initializer == null) {
return null;
}
@@ -92,6 +101,55 @@ public class ScriptEngineFactory {
return engine;
}
+
+ /**
+ * This method is similar to the {@link #getScriptEngine(String, PackageFinder, StandardBindings)} method
+ * but additionally applies a security wrapper on the returned script engine so that the scripts execute
+ * with the provided java permissions.
+ *
+ * @see #getScriptEngine(String, PackageFinder, StandardBindings)
+ */
+ public static ScriptEngine getSecuredScriptEngine(final String language, final PackageFinder packageFinder, final StandardBindings bindings, final PermissionCollection permissions) throws ScriptException, IOException {
+ CodeSource src = new CodeSource(new URL("http://rhq-project.org/scripting"), (Certificate[]) null);
+ ProtectionDomain scriptDomain = new ProtectionDomain(src, permissions);
+ AccessControlContext ctx = new AccessControlContext(new ProtectionDomain[] { scriptDomain });
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<ScriptEngine>() {
+ @Override
+ public ScriptEngine run() throws Exception {
+ //This might seem a bit excessive but is necessary due to the
+ //change in security handling in the rhino script engine
+ //that occured in Java6u27 (due to a CVE desribed here:
+ //https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2011-3544)
+
+ //In Java 6u26 and earlier, it was enough to wrap a script engine
+ //in the sandbox and everything would work.
+
+ //Java 6u27 introduced new behavior where the rhino script engine
+ //remembers the access control context with which it has been
+ //constructed and combines that with the callers protection domain
+ //when a script is executed. Because this class has all perms and
+ //all the code in RHQ that called ScriptEngine.eval* also
+ //had all perms, the scripts would never be sandboxed even if the call
+ //was pushed through the SandboxedScriptEngine.
+
+ //This means that the below wrapping is necessary for the security
+ //to work in java6 pre u27 while the surrounding privileged block
+ //is necessary for the security to be applied in java6 u27 and later.
+ return new SandboxedScriptEngine(getScriptEngine(language, packageFinder, bindings), permissions);
+ }
+ }, ctx);
+ } catch (PrivilegedActionException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof IOException) {
+ throw (IOException) cause;
+ } else if (cause instanceof ScriptException) {
+ throw (ScriptException) cause;
+ } else {
+ throw new ScriptException(e);
+ }
+ }
+ }
/**
* Injects the values provided in the bindings into the {@link ScriptContext#ENGINE_SCOPE engine scope}
diff --git a/modules/enterprise/binding/src/test/java/org/rhq/bindings/ScriptEngineTest.java b/modules/enterprise/binding/src/test/java/org/rhq/bindings/ScriptEngineTest.java
index 69874e4..15184c1 100644
--- a/modules/enterprise/binding/src/test/java/org/rhq/bindings/ScriptEngineTest.java
+++ b/modules/enterprise/binding/src/test/java/org/rhq/bindings/ScriptEngineTest.java
@@ -40,6 +40,7 @@ import org.rhq.bindings.util.PackageFinder;
*
* @author Lukas Krejci
*/
+@Test
public class ScriptEngineTest {
private static StandardBindings EMPTY_BINDINGS = new StandardBindings(new PrintWriter(System.out), new FakeRhqFacade());
@@ -52,9 +53,7 @@ public class ScriptEngineTest {
@Test
public void testSandbox() throws ScriptException, IOException {
- ScriptEngine engine = getScriptEngine();
-
- SandboxedScriptEngine sandbox = new SandboxedScriptEngine(engine, new StandardScriptPermissions());
+ ScriptEngine sandbox = getSecuredScriptEngine();
try {
sandbox.eval("java.lang.System.exit(1);");
@@ -90,6 +89,10 @@ public class ScriptEngineTest {
return ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), EMPTY_BINDINGS);
}
+ private ScriptEngine getSecuredScriptEngine() throws ScriptException, IOException {
+ return ScriptEngineFactory.getSecuredScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), EMPTY_BINDINGS, new StandardScriptPermissions());
+ }
+
private void assertSecurityExceptionPresent(Throwable t) {
boolean ok = false;
while (t != null) {
diff --git a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
index ae848a8..de0d912 100644
--- a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
+++ b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
@@ -181,12 +181,10 @@ public class JndiAccessTest extends AbstractEJB3Test {
private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
- ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
PermissionCollection perms = new StandardScriptPermissions();
- perms.add(new SerializablePermission("enableSubclassImplementation"));
- return new SandboxedScriptEngine(engine, perms);
+ return ScriptEngineFactory.getSecuredScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings, perms);
}
private static void checkIsDesiredSecurityException(ScriptException e) {
diff --git a/modules/enterprise/server/plugins/alert-cli/src/main/java/org/rhq/enterprise/server/plugins/alertCli/CliSender.java b/modules/enterprise/server/plugins/alert-cli/src/main/java/org/rhq/enterprise/server/plugins/alertCli/CliSender.java
index 3aab6a2..43090c7 100644
--- a/modules/enterprise/server/plugins/alert-cli/src/main/java/org/rhq/enterprise/server/plugins/alertCli/CliSender.java
+++ b/modules/enterprise/server/plugins/alert-cli/src/main/java/org/rhq/enterprise/server/plugins/alertCli/CliSender.java
@@ -127,8 +127,6 @@ public class CliSender extends AlertSender<CliComponent> {
engine = getScriptEngine(alert, scriptOut, config);
- final SandboxedScriptEngine sandbox = new SandboxedScriptEngine(engine, new StandardScriptPermissions());
-
InputStream packageBits = getPackageBits(config.packageId, config.repoId);
reader = new BufferedReader(new InputStreamReader(packageBits));
@@ -137,10 +135,11 @@ public class CliSender extends AlertSender<CliComponent> {
final ExceptionHolder exceptionHolder = new ExceptionHolder();
+ final ScriptEngine e = engine;
Thread scriptRunner = new Thread(new Runnable() {
public void run() {
try {
- sandbox.eval(rdr);
+ e.eval(rdr);
} catch (ScriptException e) {
exceptionHolder.scriptException = e;
}
@@ -414,8 +413,8 @@ public class CliSender extends AlertSender<CliComponent> {
ScriptEngine engine = SCRIPT_ENGINES.poll();
if (engine == null) {
- engine = ScriptEngineFactory.getScriptEngine(ENGINE_NAME, new PackageFinder(Collections
- .<File> emptyList()), bindings);
+ engine = ScriptEngineFactory.getSecuredScriptEngine(ENGINE_NAME, new PackageFinder(Collections
+ .<File> emptyList()), bindings, new StandardScriptPermissions());
} else {
ScriptEngineFactory.injectStandardBindings(engine, bindings, true);
}
commit 40247b6c476b0a68476480fe5bca118c4db93489
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Jan 12 16:28:10 2012 +0100
making sure that the tests that try to exit the jvm won't make the test
suite appear to have succeeded.
diff --git a/modules/enterprise/binding/pom.xml b/modules/enterprise/binding/pom.xml
index 0a9dd46..52def8e 100644
--- a/modules/enterprise/binding/pom.xml
+++ b/modules/enterprise/binding/pom.xml
@@ -209,6 +209,8 @@
<!-- <argLine>-Xdebug -Xnoagent -Djava.compiler=NONE
-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> -->
<argLine>-Djava.security.manager -Djava.security.policy==${project.build.testOutputDirectory}/allow-all.policy</argLine>
+ <!-- This is important, because some of the tests try to exit the JVM. -->
+ <failIfNoTests>true</failIfNoTests>
</configuration>
</plugin>
commit 3af946684338eecfced03356dfbebdf1f308eec3
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Wed Jan 11 17:05:52 2012 -0500
[BZ 773090] fix the attachment form item so it doesn't cause the info to go off the screen
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleResourceDeploymentHistoryListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleResourceDeploymentHistoryListView.java
index 63a10d7..db5d363 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleResourceDeploymentHistoryListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleResourceDeploymentHistoryListView.java
@@ -38,8 +38,10 @@ import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.DoubleClickEvent;
import com.smartgwt.client.widgets.events.DoubleClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
-import com.smartgwt.client.widgets.form.fields.AutoFitTextAreaItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
+import com.smartgwt.client.widgets.form.fields.TextAreaItem;
+import com.smartgwt.client.widgets.form.fields.events.ChangeEvent;
+import com.smartgwt.client.widgets.form.fields.events.ChangeHandler;
import com.smartgwt.client.widgets.grid.CellFormatter;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
@@ -172,9 +174,17 @@ public class BundleResourceDeploymentHistoryListView extends LocatableVLayout {
StaticTextItem message = new StaticTextItem("message", MSG.common_title_message());
message.setTitleVAlign(VerticalAlignment.TOP);
- AutoFitTextAreaItem detail = new AutoFitTextAreaItem("attachment", MSG.common_title_details());
+ TextAreaItem detail = new TextAreaItem("attachment", MSG.common_title_details());
detail.setTitleVAlign(VerticalAlignment.TOP);
+ detail.setMinHeight(100);
+ detail.setHeight("100%");
detail.setWidth("100%");
+ detail.addChangeHandler(new ChangeHandler() {
+ @Override
+ public void onChange(ChangeEvent event) {
+ event.cancel(); // we want the user to interact with the text to copy it, but not to edit it
+ }
+ });
form.setItems(timestamp, action, category, user, status, info, message, detail);
form.editRecord(record);
commit 3a40aefab45f851facda766e766bb312675d1e63
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jan 11 16:05:01 2012 -0500
[Bug 773031 - Component start() called more than once without an intervening stop()]
A variety of auto-formatting changes took place, actual changes are in:
InventoryManager.prepareResourceForActivation
InventoryManager.activateResource
The resource component state could be STOPPED or STARTED. There was a
large window while a component was actually starting that a call
to prepareResourceForActivation would happily allow the component to
again be activated. So, added an actual STARTING state that can block
redundant activation.
Additionally, if forcing reactivation ensure a STARTED component is
stopped before being restarted.
Also:
- remove unnecessary and bad lazy state check
- comment out some unused/debug code
- remove warnings
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
index 2a5bd2f..2afe7f0 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/InventoryManager.java
@@ -130,6 +130,7 @@ import org.rhq.core.util.exception.WrappedRemotingException;
* @author Ian Springer
* @author Jay Shaughnessy
*/
+@SuppressWarnings({ "rawtypes", "unchecked" })
public class InventoryManager extends AgentService implements ContainerService, DiscoveryAgentService {
private static final String INVENTORY_THREAD_POOL_NAME = "InventoryManager.discovery";
private static final String AVAIL_THREAD_POOL_NAME = "InventoryManager.availability";
@@ -245,16 +246,19 @@ public class InventoryManager extends AgentService implements ContainerService,
// inside EmbJopr).
if (configuration.isInsideAgent()) {
// After an initial delay (5s by default), periodically run an availability check (every 1m by default).
- availabilityThreadPoolExecutor.scheduleWithFixedDelay(availabilityExecutor, configuration
- .getAvailabilityScanInitialDelay(), configuration.getAvailabilityScanPeriod(), TimeUnit.SECONDS);
+ availabilityThreadPoolExecutor.scheduleWithFixedDelay(availabilityExecutor,
+ configuration.getAvailabilityScanInitialDelay(), configuration.getAvailabilityScanPeriod(),
+ TimeUnit.SECONDS);
// After an initial delay (10s by default), periodically run a server discovery scan (every 15m by default).
- inventoryThreadPoolExecutor.scheduleWithFixedDelay(serverScanExecutor, configuration
- .getServerDiscoveryInitialDelay(), configuration.getServerDiscoveryPeriod(), TimeUnit.SECONDS);
+ inventoryThreadPoolExecutor.scheduleWithFixedDelay(serverScanExecutor,
+ configuration.getServerDiscoveryInitialDelay(), configuration.getServerDiscoveryPeriod(),
+ TimeUnit.SECONDS);
// After an initial delay (20s by default), periodically run a service discovery scan (every 1d by default).
- inventoryThreadPoolExecutor.scheduleWithFixedDelay(serviceScanExecutor, configuration
- .getServiceDiscoveryInitialDelay(), configuration.getServiceDiscoveryPeriod(), TimeUnit.SECONDS);
+ inventoryThreadPoolExecutor.scheduleWithFixedDelay(serviceScanExecutor,
+ configuration.getServiceDiscoveryInitialDelay(), configuration.getServiceDiscoveryPeriod(),
+ TimeUnit.SECONDS);
}
} finally {
inventoryLock.writeLock().unlock();
@@ -311,8 +315,8 @@ public class InventoryManager extends AgentService implements ContainerService,
long timeout = getDiscoveryComponentTimeout(context.getResourceType());
try {
- ResourceDiscoveryComponent proxy = this.discoveryComponentProxyFactory.getDiscoveryComponentProxy(context
- .getResourceType(), component, timeout, parentResourceContainer);
+ ResourceDiscoveryComponent proxy = this.discoveryComponentProxyFactory.getDiscoveryComponentProxy(
+ context.getResourceType(), component, timeout, parentResourceContainer);
Set<DiscoveredResourceDetails> results = proxy.discoverResources(context);
return results;
} catch (TimeoutException te) {
@@ -347,8 +351,8 @@ public class InventoryManager extends AgentService implements ContainerService,
long timeout = getDiscoveryComponentTimeout(context.getResourceType());
try {
- ManualAddFacet proxy = this.discoveryComponentProxyFactory.getDiscoveryComponentProxy(context
- .getResourceType(), component, timeout, ManualAddFacet.class, parentResourceContainer);
+ ManualAddFacet proxy = this.discoveryComponentProxyFactory.getDiscoveryComponentProxy(
+ context.getResourceType(), component, timeout, ManualAddFacet.class, parentResourceContainer);
DiscoveredResourceDetails result = proxy.discoverResource(pluginConfig, context);
return result;
} catch (TimeoutException te) {
@@ -387,8 +391,8 @@ public class InventoryManager extends AgentService implements ContainerService,
component, timeout, ClassLoaderFacet.class, parentContainer);
ResourceDiscoveryContext discoveryContext = new ResourceDiscoveryContext(resourceType, parentComponent,
- parentResourceContext, SystemInfoFactory.createSystemInfo(), null, null, this.configuration
- .getContainerName(), this.configuration.getPluginContainerDeployment());
+ parentResourceContext, SystemInfoFactory.createSystemInfo(), null, null,
+ this.configuration.getContainerName(), this.configuration.getPluginContainerDeployment());
// Configurations are not immutable, so clone the plugin config, so the plugin will not be able to change the
// actual PC-managed plugin config.
@@ -409,7 +413,6 @@ public class InventoryManager extends AgentService implements ContainerService,
long timeout = getDiscoveryComponentTimeout(resourceType);
try {
- @SuppressWarnings("unchecked")
ResourceUpgradeFacet<T> proxy = this.discoveryComponentProxyFactory.getDiscoveryComponentProxy(
resourceType, component, timeout, ResourceUpgradeFacet.class, parentResourceContainer);
@@ -641,7 +644,6 @@ public class InventoryManager extends AgentService implements ContainerService,
return new Availability(resource, new Date(), availType);
}
- @SuppressWarnings("unchecked")
public MergeResourceResponse manuallyAddResource(ResourceType resourceType, int parentResourceId,
Configuration pluginConfiguration, int ownerSubjectId) throws InvalidPluginConfigurationClientException,
PluginContainerException {
@@ -676,8 +678,8 @@ public class InventoryManager extends AgentService implements ContainerService,
ResourceDiscoveryContext<ResourceComponent<?>> discoveryContext = new ResourceDiscoveryContext<ResourceComponent<?>>(
resourceType, parentResourceComponent, parentResourceContainer.getResourceContext(),
SystemInfoFactory.createSystemInfo(), new ArrayList<ProcessScanResult>(0),
- new ArrayList<Configuration>(0), this.configuration.getContainerName(), this.configuration
- .getPluginContainerDeployment());
+ new ArrayList<Configuration>(0), this.configuration.getContainerName(),
+ this.configuration.getPluginContainerDeployment());
// Ask the plugin's discovery component to find the new resource, throwing exceptions if it cannot be
// found at all.
@@ -879,8 +881,7 @@ public class InventoryManager extends AgentService implements ContainerService,
if ((this.platform != null) && (this.platform.getInventoryStatus() == InventoryStatus.NEW)
&& newPlatformWasDeletedRecently) {
// let's make sure we are registered; its probable that our platform was deleted and we need to re-register
- log
- .info("No committed resources to send in our availability report - the platform/agent was deleted, let's re-register again");
+ log.info("No committed resources to send in our availability report - the platform/agent was deleted, let's re-register again");
registerWithServer();
newPlatformWasDeletedRecently = false; // we've tried to recover from our platform being deleted, let's not do it again
}
@@ -923,8 +924,8 @@ public class InventoryManager extends AgentService implements ContainerService,
log.debug("Availability report content: " + report.toString(log.isTraceEnabled()));
}
- boolean ok = configuration.getServerServices().getDiscoveryServerService().mergeAvailabilityReport(
- report);
+ boolean ok = configuration.getServerServices().getDiscoveryServerService()
+ .mergeAvailabilityReport(report);
if (!ok) {
// I guess I could immediately call executeAvailabilityScanImmediately and pass its results to
// mergeAvailabilityReport again right now, but what happens if we've queued up a bunch of
@@ -970,10 +971,9 @@ public class InventoryManager extends AgentService implements ContainerService,
(System.currentTimeMillis() - startTime)));
}
} catch (StaleTypeException e) {
- log
- .error("Failed to merge inventory report with server. The report contains one or more resource types "
- + "that have been marked for deletion. Notifying the plugin container that a reboot is needed to purge "
- + "stale types.");
+ log.error("Failed to merge inventory report with server. The report contains one or more resource types "
+ + "that have been marked for deletion. Notifying the plugin container that a reboot is needed to purge "
+ + "stale types.");
PluginContainer.getInstance().notifyRebootRequestListener();
return false;
} catch (InvalidInventoryReportException e) {
@@ -981,8 +981,7 @@ public class InventoryManager extends AgentService implements ContainerService,
if ((this.platform != null) && (this.platform.getInventoryStatus() == InventoryStatus.NEW)
&& newPlatformWasDeletedRecently) {
// let's make sure we are registered; its probable that our platform was deleted and we need to re-register
- log
- .info("The inventory report was invalid probably because the platform/Agent was deleted; let's re-register...");
+ log.info("The inventory report was invalid probably because the platform/Agent was deleted; let's re-register...");
registerWithServer();
newPlatformWasDeletedRecently = false; // we've tried to recover from our platform being deleted, let's not do it again
}
@@ -1178,8 +1177,8 @@ public class InventoryManager extends AgentService implements ContainerService,
parent.removeChildResource(resource);
}
- PluginContainer.getInstance().getMeasurementManager().unscheduleCollection(
- Collections.singleton(resource.getId()));
+ PluginContainer.getInstance().getMeasurementManager()
+ .unscheduleCollection(Collections.singleton(resource.getId()));
if (this.resourceContainers.remove(resource.getUuid()) == null) {
if (log.isDebugEnabled()) {
@@ -1285,8 +1284,8 @@ public class InventoryManager extends AgentService implements ContainerService,
logMessage.append("description, ");
}
- logMessage.replace(logMessage.length() - 1, logMessage.length(), "to become [").append(
- existingResource.toString()).append("]");
+ logMessage.replace(logMessage.length() - 1, logMessage.length(), "to become [")
+ .append(existingResource.toString()).append("]");
log.info(logMessage.toString());
} else {
@@ -1449,25 +1448,48 @@ public class InventoryManager extends AgentService implements ContainerService,
*/
private boolean prepareResourceForActivation(Resource resource, @NotNull ResourceContainer container,
boolean forceReinitialization) throws InvalidPluginConfigurationException, PluginContainerException {
+
if (resourceUpgradeDelegate.hasUpgradeFailed(resource)) {
if (log.isTraceEnabled()) {
log.trace("Skipping activation of " + resource + " - it has failed to upgrade.");
}
+
return false;
}
ResourceComponent component = container.getResourceComponent();
+ ResourceComponentState state = container.getResourceComponentState();
- // if the component already exists and is started, and the resource's plugin config has not changed, there is
- // nothing to do, so return immediately
- if ((component != null)
- && (container.getResourceComponentState() == ResourceComponentState.STARTED && !forceReinitialization)) {
- if (log.isTraceEnabled()) {
- log.trace("No need to prepare the activation of resource " + resource
- + " - its component is already started and its plugin "
- + "config has not been updated since it was last started.");
+ // state is a transient field, so reinitialize it just in case this is invoked just after loadFromDisk()
+ if (state == null) {
+ container.setResourceComponentState(ResourceComponentState.STOPPED);
+ }
+
+ // if the component exists and is not stopped then we may not have to do anything
+ if ((component != null) && (state != ResourceComponentState.STOPPED)) {
+
+ // if STARTED and we are forced to restart (e.g. plugin config change), then stop the component
+ // and continue. If STARTING just let it continue to start as interruption could put us in a bad state.
+ if (forceReinitialization) {
+ switch (state) {
+ case STARTED:
+ component.stop();
+ break;
+ case STARTING:
+ log.warn("Could not force initialization of component for resource [" + resource.getId()
+ + "] as it is already in the process of starting.");
+
+ return false;
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ log.trace("No need to prepare the activation of resource " + resource
+ + " - its component is already started and its plugin "
+ + "config has not been updated since it was last started.");
+ }
+
+ return false;
}
- return false;
}
if (log.isDebugEnabled()) {
@@ -1483,16 +1505,13 @@ public class InventoryManager extends AgentService implements ContainerService,
}
try {
component = PluginContainer.getInstance().getPluginComponentFactory().buildResourceComponent(resource);
+
} catch (Throwable e) {
throw new PluginContainerException("Could not build component for Resource [" + resource + "]", e);
}
container.setResourceComponent(component);
}
- //this is a transient field, so reinitialize it just in case this is invoked just after
- //loadFromDisk()
- container.setResourceComponentState(ResourceComponentState.STOPPED);
-
// start the resource, but only if its parent component is running. If the parent is null, that means
// the resource is, itself, the root platform and we always activate that.
ResourceContainer parentResourceContainer;
@@ -1522,8 +1541,8 @@ public class InventoryManager extends AgentService implements ContainerService,
log.warn("Cannot give activated resource its discovery component. Cause: " + e);
}
- ConfigurationUtility.normalizeConfiguration(resource.getPluginConfiguration(), type
- .getPluginConfigurationDefinition());
+ ConfigurationUtility.normalizeConfiguration(resource.getPluginConfiguration(),
+ type.getPluginConfigurationDefinition());
ResourceComponent<?> parentComponent = null;
if (resource.getParentResource() != null) {
@@ -1531,10 +1550,9 @@ public class InventoryManager extends AgentService implements ContainerService,
}
ResourceContext context = createResourceContext(resource, parentComponent, discoveryComponent);
-
container.setResourceContext(context);
-
return true;
+
} else {
if (log.isDebugEnabled()) {
log.debug("Resource [" + resource + "] not being prepared for activation; parent isn't started: "
@@ -1558,9 +1576,9 @@ public class InventoryManager extends AgentService implements ContainerService,
* plugin configuration
* @throws PluginContainerException for all other errors
*/
- @SuppressWarnings("unchecked")
public void activateResource(Resource resource, @NotNull ResourceContainer container, boolean updatedPluginConfig)
throws InvalidPluginConfigurationException, PluginContainerException {
+
if (resourceUpgradeDelegate.hasUpgradeFailed(resource)) {
if (log.isTraceEnabled()) {
log.trace("Skipping activation of " + resource + " - it has failed to upgrade.");
@@ -1569,6 +1587,7 @@ public class InventoryManager extends AgentService implements ContainerService,
}
if (prepareResourceForActivation(resource, container, updatedPluginConfig)) {
+ container.setResourceComponentState(ResourceComponentState.STARTING);
ResourceContext context = container.getResourceContext();
@@ -1577,27 +1596,26 @@ public class InventoryManager extends AgentService implements ContainerService,
FacetLockType.READ, COMPONENT_START_TIMEOUT, true, false);
try {
- // One last check to make sure another thread didn't beat us to the punch.
- // TODO: Add some real synchronization to this method. (ips, 07/09/07)
- if (container.getResourceComponentState() == ResourceComponentState.STARTED) {
- if (log.isTraceEnabled()) {
- log.trace("Skipping activation of " + resource + " - its component is already started.");
- }
- return;
- }
component.start(context);
container.setResourceComponentState(ResourceComponentState.STARTED);
resource.setConnected(true); // This tells the server-side that the resource has connected successfully.
+
} catch (Throwable t) {
+ // Don't leave in a STARTING state. Don't actually call component.stop(),
+ // because we're not actually STARTED
+ container.setResourceComponentState(ResourceComponentState.STOPPED);
+
if (updatedPluginConfig || (t instanceof InvalidPluginConfigurationException)) {
if (log.isDebugEnabled()) {
log.debug("Resource has a bad config, waiting for this to go away: " + resource);
}
InventoryEventListener iel = new ResourceGotActivatedListener();
addInventoryEventListener(iel);
+
throw new InvalidPluginConfigurationException("Failed to start component for resource " + resource
+ ".", t);
}
+
throw new PluginContainerException("Failed to start component for resource " + resource + ".", t);
}
@@ -1661,8 +1679,8 @@ public class InventoryManager extends AgentService implements ContainerService,
resource.setConnected(false); // invalid plugin configuration infers the resource component is disconnected
// Give the server-side an error message describing the connection failure that can be
// displayed on the resource's Inventory page.
- ResourceError resourceError = new ResourceError(resource, ResourceErrorType.INVALID_PLUGIN_CONFIGURATION, t
- .getLocalizedMessage(), ThrowableUtil.getStackAsString(t), System.currentTimeMillis());
+ ResourceError resourceError = new ResourceError(resource, ResourceErrorType.INVALID_PLUGIN_CONFIGURATION,
+ t.getLocalizedMessage(), ThrowableUtil.getStackAsString(t), System.currentTimeMillis());
return sendResourceErrorToServer(resourceError);
}
@@ -1750,37 +1768,39 @@ public class InventoryManager extends AgentService implements ContainerService,
return servers;
}
- private void activateFromDisk(Resource resource) throws PluginContainerException {
- if (resource.getId() == 0) {
- return; // This is for the case of a resource that hadn't been synced to the server (there are probably better places to handle this)
- }
-
- resource.setAgent(this.agent);
- ResourceContainer container = getResourceContainer(resource.getId());
- if (container == null) {
- if (log.isDebugEnabled()) {
- log.debug("Could not find a container for resource: " + resource);
- }
- return;
- }
- if (container.getSynchronizationState() != ResourceContainer.SynchronizationState.SYNCHRONIZED) {
- if (log.isDebugEnabled()) {
- log.debug("Stopped activating resources at unsynchronized resource [" + resource + "]");
- }
- return;
- }
-
- try {
- activateResource(resource, container, false);
- } catch (Exception e) {
- log.debug("Failed to activate from disk [" + resource + "]");
- }
-
- for (Resource child : resource.getChildResources()) {
- initResourceContainer(child);
- activateFromDisk(child);
- }
- }
+ // commenting out dead code, leaving for reference -jshaughn
+ //
+ // private void activateFromDisk(Resource resource) throws PluginContainerException {
+ // if (resource.getId() == 0) {
+ // return; // This is for the case of a resource that hadn't been synced to the server (there are probably better places to handle this)
+ // }
+ //
+ // resource.setAgent(this.agent);
+ // ResourceContainer container = getResourceContainer(resource.getId());
+ // if (container == null) {
+ // if (log.isDebugEnabled()) {
+ // log.debug("Could not find a container for resource: " + resource);
+ // }
+ // return;
+ // }
+ // if (container.getSynchronizationState() != ResourceContainer.SynchronizationState.SYNCHRONIZED) {
+ // if (log.isDebugEnabled()) {
+ // log.debug("Stopped activating resources at unsynchronized resource [" + resource + "]");
+ // }
+ // return;
+ // }
+ //
+ // try {
+ // activateResource(resource, container, false);
+ // } catch (Exception e) {
+ // log.debug("Failed to activate from disk [" + resource + "]");
+ // }
+ //
+ // for (Resource child : resource.getChildResources()) {
+ // initResourceContainer(child);
+ // activateFromDisk(child);
+ // }
+ // }
/**
* Tries to load an existing inventory from the file data/inventory.dat
@@ -1875,7 +1895,6 @@ public class InventoryManager extends AgentService implements ContainerService,
* TODO GH: Move this to another class (this one is getting too big)
* @return The discovered platform (which might be a dummy in case of testing)
*/
- @SuppressWarnings("unchecked")
private Resource discoverPlatform() {
PluginManager pluginManager = PluginContainer.getInstance().getPluginManager();
PluginComponentFactory componentFactory = PluginContainer.getInstance().getPluginComponentFactory();
@@ -1921,8 +1940,7 @@ public class InventoryManager extends AgentService implements ContainerService,
}
} else {
// This is very strange - there are no platform types - we should never be missing the built-in platform plugin.
- log
- .error("Missing platform plugin(s) - falling back to dummy platform impl; this should only occur in tests!");
+ log.error("Missing platform plugin(s) - falling back to dummy platform impl; this should only occur in tests!");
// TODO: Set sysprop (e.g. rhq.test.mode=true) in integration tests,
// and throw a runtime exception here if that sysprop is not set.
return getTestPlatform();
@@ -2307,8 +2325,8 @@ public class InventoryManager extends AgentService implements ContainerService,
try {
ResourceDiscoveryContext context = new ResourceDiscoveryContext(resourceType, parentComponent,
parentResourceContext, SystemInfoFactory.createSystemInfo(), processScanResults,
- Collections.EMPTY_LIST, this.configuration.getContainerName(), this.configuration
- .getPluginContainerDeployment());
+ Collections.EMPTY_LIST, this.configuration.getContainerName(),
+ this.configuration.getPluginContainerDeployment());
newResources = new HashSet<Resource>();
try {
Set<DiscoveredResourceDetails> discoveredResources = invokeDiscoveryComponent(parentContainer,
@@ -2419,19 +2437,19 @@ public class InventoryManager extends AgentService implements ContainerService,
return contentContext;
}
- private ResourceComponent<?> createTestPlatformComponent() {
- return new ResourceComponent() {
- public AvailabilityType getAvailability() {
- return AvailabilityType.UP;
- }
-
- public void start(ResourceContext context) {
- }
-
- public void stop() {
- }
- };
- }
+ // private ResourceComponent<?> createTestPlatformComponent() {
+ // return new ResourceComponent() {
+ // public AvailabilityType getAvailability() {
+ // return AvailabilityType.UP;
+ // }
+ //
+ // public void start(ResourceContext context) {
+ // }
+ //
+ // public void stop() {
+ // }
+ // };
+ // }
private void updateResourceVersion(Resource resource, String version) {
String existingVersion = resource.getVersion();
@@ -2547,8 +2565,8 @@ public class InventoryManager extends AgentService implements ContainerService,
if (log.isDebugEnabled()) {
log.debug("Merging [" + modifiedResourceIds.size() + "] modified Resources into local inventory...");
}
- Set<Resource> modifiedResources = configuration.getServerServices().getDiscoveryServerService().getResources(
- modifiedResourceIds, false);
+ Set<Resource> modifiedResources = configuration.getServerServices().getDiscoveryServerService()
+ .getResources(modifiedResourceIds, false);
syncSchedules(modifiedResources); // RHQ-792, mtime is the indicator that schedules should be sync'ed too
syncDriftDefinitions(modifiedResources);
for (Resource modifiedResource : modifiedResources) {
@@ -2590,16 +2608,16 @@ public class InventoryManager extends AgentService implements ContainerService,
return;
}
- private void print(Resource resourceTreeNode, int level) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < level; i++) {
- builder.append(" ");
- }
- log.info(builder.toString() + resourceTreeNode.getId() + " " + resourceTreeNode.getUuid());
- for (Resource child : resourceTreeNode.getChildResources()) {
- print(child, level + 1);
- }
- }
+ // private void print(Resource resourceTreeNode, int level) {
+ // StringBuilder builder = new StringBuilder();
+ // for (int i = 0; i < level; i++) {
+ // builder.append(" ");
+ // }
+ // log.info(builder.toString() + resourceTreeNode.getId() + " " + resourceTreeNode.getUuid());
+ // for (Resource child : resourceTreeNode.getChildResources()) {
+ // print(child, level + 1);
+ // }
+ // }
private void mergeResource(Resource resource) {
if (log.isDebugEnabled()) {
@@ -2797,10 +2815,9 @@ public class InventoryManager extends AgentService implements ContainerService,
log.info("Resource activation and upgrade finished.");
} catch (Throwable t) {
- log
- .error(
- "Resource activation or upgrade failed with an exception. An attempt to merely activate the resources will be made now.",
- t);
+ log.error(
+ "Resource activation or upgrade failed with an exception. An attempt to merely activate the resources will be made now.",
+ t);
//make sure to at least activate the resources
activateAndUpgradeResourceRecursively(getPlatform(), false);
@@ -2831,6 +2848,7 @@ public class InventoryManager extends AgentService implements ContainerService,
}
} catch (InvalidPluginConfigurationException e) {
log.debug("Failed to activate resource [" + resource + "] due to invalid plugin configuration.", e);
+
} catch (Throwable t) {
log.error("Exception thrown while activating [" + resource + "].", t);
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/ResourceContainer.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/ResourceContainer.java
index 854e624..c348a57 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/ResourceContainer.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/inventory/ResourceContainer.java
@@ -67,7 +67,7 @@ import org.rhq.core.pluginapi.inventory.ResourceContext;
* @author John Mazzitelli
* @author Ian Springer
*/
-@SuppressWarnings("unchecked")
+@SuppressWarnings({ "rawtypes", "unchecked" })
public class ResourceContainer implements Serializable {
private static final long serialVersionUID = 1L;
@@ -76,7 +76,7 @@ public class ResourceContainer implements Serializable {
}
public enum ResourceComponentState {
- STARTED, STOPPED
+ STARTED, STOPPED, STARTING
}
// thread pools used to invoke methods on container's components
commit d1a4410a78bfbed7baa8b65b71abea0315a3fea0
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jan 11 15:25:51 2012 -0500
[Bug 773435 - Enabled event sources cause initial resource component start to time out]
lazily access sigar on the first polling, which happens after container
initialization.
diff --git a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
index d936522..6fcb6d1 100644
--- a/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
+++ b/modules/core/plugin-api/src/main/java/org/rhq/core/pluginapi/event/log/LogFileEventPoller.java
@@ -1,25 +1,25 @@
- /*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
package org.rhq.core.pluginapi.event.log;
import java.io.BufferedReader;
@@ -46,24 +46,21 @@ import org.rhq.core.pluginapi.event.EventPoller;
*
* @author Ian Springer
*/
-public class LogFileEventPoller implements EventPoller {
+public class LogFileEventPoller implements EventPoller {
private final Log log = LogFactory.getLog(this.getClass());
private String eventType;
private File logFile;
private FileInfo logFileInfo;
private LogEntryProcessor entryProcessor;
+ private EventContext eventContext;
- public LogFileEventPoller(EventContext eventContext, String eventType, File logFile, LogEntryProcessor entryProcessor) {
+ public LogFileEventPoller(EventContext eventContext, String eventType, File logFile,
+ LogEntryProcessor entryProcessor) {
this.eventType = eventType;
this.logFile = logFile;
- SigarProxy sigar = eventContext.getSigar();
- try {
- this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
- } catch (SigarException e) {
- throw new RuntimeException(e);
- }
this.entryProcessor = entryProcessor;
+ this.eventContext = eventContext;
}
@NotNull
@@ -76,8 +73,27 @@ public class LogFileEventPoller implements EventPoller {
return this.logFile.getPath();
}
+ // we can't get the FileInfo in the constructor because pollers are constructed during pc initialization, and
+ // at that time the eventManager is not available (and so we can't get sigar).
+ private FileInfo getFileInfo() {
+ if (null == this.logFileInfo) {
+ try {
+ SigarProxy sigar = eventContext.getSigar();
+ this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
+ // once we have the file info we can let go of the event context, just in case that's useful
+ this.eventContext = null;
+
+ } catch (SigarException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ return this.logFileInfo;
+ }
+
@Nullable
public Set<Event> poll() {
+
if (!this.logFile.exists()) {
log.warn("Log file [" + this.logFile + "' being polled does not exist.");
return null;
@@ -86,23 +102,25 @@ public class LogFileEventPoller implements EventPoller {
log.error("Log file [" + this.logFile + "' being polled is a directory, not a regular file.");
return null;
}
+ FileInfo fileInfo;
try {
- if (!this.logFileInfo.changed()) {
+ fileInfo = getFileInfo();
+ if (!fileInfo.changed()) {
return null;
}
} catch (SigarException e) {
throw new RuntimeException(e);
}
- return processNewLines();
+ return processNewLines(fileInfo);
}
- private Set<Event> processNewLines() {
+ private Set<Event> processNewLines(FileInfo fileInfo) {
Set<Event> events = null;
Reader reader = null;
try {
reader = new FileReader(this.logFile);
- long offset = getOffset();
+ long offset = getOffset(fileInfo);
if (offset > 0) {
reader.skip(offset);
@@ -123,24 +141,24 @@ public class LogFileEventPoller implements EventPoller {
return events;
}
- private long getOffset() {
- FileInfo previousFileInfo = this.logFileInfo.getPreviousInfo();
+ private long getOffset(FileInfo fileInfo) {
+ FileInfo previousFileInfo = fileInfo.getPreviousInfo();
if (previousFileInfo == null) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": first stat");
}
- return this.logFileInfo.getSize();
+ return fileInfo.getSize();
}
- if (this.logFileInfo.getInode() != previousFileInfo.getInode()) {
+ if (fileInfo.getInode() != previousFileInfo.getInode()) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": file inode changed");
}
return -1;
}
- if (this.logFileInfo.getSize() < previousFileInfo.getSize()) {
+ if (fileInfo.getSize() < previousFileInfo.getSize()) {
if (log.isDebugEnabled()) {
log.debug(this.logFile + ": file truncated");
}
@@ -148,7 +166,7 @@ public class LogFileEventPoller implements EventPoller {
}
if (log.isDebugEnabled()) {
- long diff = this.logFileInfo.getSize() - previousFileInfo.getSize();
+ long diff = fileInfo.getSize() - previousFileInfo.getSize();
log.debug(this.logFile + ": " + diff + " new bytes");
}
commit 4a4e0dcbc60faef7e25e1801fd7aeffb5a74521b
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Jan 11 15:15:44 2012 +0100
BZ 771940 - Increase timeout when waiting for process start.
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 3a3fa03..99c8cee 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
@@ -110,7 +110,7 @@ public class BaseServerComponent extends BaseComponent {
}
processExecution.setWorkingDirectory(baseDir);
processExecution.setCaptureOutput(true);
- processExecution.setWaitForCompletion(2000L); // 2 seconds // TODO: Should we wait longer than two seconds?
+ processExecution.setWaitForCompletion(15000L); // 15 seconds // TODO: Should we wait longer than 15 seconds?
processExecution.setKillOnTimeout(false);
commit e314d32549140d221af587c7c794b8856a87b4d0
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Jan 11 09:55:55 2012 +0100
Fix the computation of the correct start and end times, so that each color represents a full day.
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
index 62b2ec5..0f38577 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
@@ -36,7 +36,7 @@ path {
stroke-width: 2;
fill: none;
}
-
+
line {
stroke: black;
}
@@ -70,8 +70,8 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
var schId = json2[0].scheduleId;
$("#header").text("Schedule " + schId + " (" + json2[0].scheduleName + "), base unit: " + json2[0].unit);
-
-// '/rest/1/metric/data/' + schId + '/raw.json?duration=604800',
+ var now = new Date().getTime();
+ var startTime = now - (7 * 86400*1000);
d3.json(
'/rest/1/metric/data/' + schId + '/raw.json?duration=604800',
function (jsondata) {
@@ -81,14 +81,14 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
var w = 960,
h = 600;
// compute min/max values for x and y a
- var minVal = d3.min(jsondata,function(d) { return d.value;});
- var maxVal = d3.max(jsondata,function(d) { return d.value;});
- var minTsD = 0;
- var maxTsD = 86400*1000;
+ var minVal = d3.min(jsondata,function(d) { return d.value;});
+ var maxVal = d3.max(jsondata,function(d) { return d.value;});
+ var minTsD = 0;
+ var maxTsD = 86400*1000;
- var minTimestamp = d3.min(jsondata,function(d) { return d.timeStamp;});
+ var minTimestamp = d3.min(jsondata,function(d) { return d.timeStamp;});
- var avg = d3.sum(jsondata,function(d) { return d.value;}) / jsondata.length;
+ var avg = d3.sum(jsondata,function(d) { return d.value;}) / jsondata.length;
@@ -119,12 +119,12 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
.tickFormat(d3.format("0e"))
.tickSubdivide(true); // display ticks between text labels
-// create the SVG
+ // create the SVG
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h);
-// Create axes
+ // Create axes
svg.append("svg:g")
.attr("class","x axis")
.call(xAxis);
@@ -134,51 +134,51 @@ $.getJSON('/rest/1/resource/platforms.json', function (json) {
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
- svg.append("svg:line")
- .attr("x1","50")
- .attr("x2","950")
- .attr("y1",y(avg))
- .attr("y2",y(avg))
- .style("stroke","red")
- .attr("style","stroke-dasharray:2 2; stroke:red")
- ;
+ svg.append("svg:line")
+ .attr("x1","50")
+ .attr("x2","950")
+ .attr("y1",y(avg))
+ .attr("y2",y(avg))
+ .style("stroke","red")
+ .attr("style","stroke-dasharray:2 2; stroke:red")
+ ;
-// split the data into 7 data sets (1 per day)
+ var colors = ["black","blue","green","cyan","red","orange","yellow"];
-//var dat = d3.split(jsondata,function(d) { return (d.timeStamp-minTimestamp % 86400*1000) < 3*60*0000; });
-var colors = ["black","blue","green","cyan","red","orange","yellow"];
-var dat = putToBuckets(jsondata,7);
+ // split the data into 7 data sets (1 per day)
+ var dat = putToBuckets(jsondata,7,now);
-for (day = 0 ; day < 7 ; day ++ ) {
- var daydat = dat[day];
- // Now lets "loop" over the data and show the dots
- var lines = svg.append("svg:g").attr("class","linechart")
- .attr("opacity","0");
-;
- var dayMinTs = d3.min(daydat,function(d) { return d.timeStamp;});
+ // loop over the buckets and create the graph
+ for (day = 0 ; day < 7 ; day ++ ) {
+ var daydat = dat[day];
+ // Now lets "loop" over the data of a bucket and show the lines and dots
+ var lines = svg.append("svg:g").attr("class","linechart")
+ .attr("opacity","1");
-var line = d3.svg.line()
- .x(function(d,i) { return x(d.timeStamp-dayMinTs); })
- .y(function(d) { return y(d.value); })
+ var dayMinTs = startTime + day * (86400*1000);
-lines.append("svg:path").attr("d", line(daydat)).style("stroke",colors[day]);
+ var line = d3.svg.line()
+ .x(function(d,i) { return x(d.timeStamp-dayMinTs); })
+ .y(function(d) { return y(d.value); })
+ lines.append("svg:path").attr("d", line(daydat)).style("stroke",colors[day]);
- var dot = svg.append("svg:g").attr("class","dotschart")
- .selectAll("dot").data(jsondata)
+ var dot = svg.append("svg:g").attr("class","dotschart")
+ .selectAll("dot").data(jsondata)
- dot.enter().append("svg:circle")
- .attr("cx", function (d) {
- return x(d.timeStamp-dayMinTs);
- })
- .attr("cy", function (d) {
- return y(d.value);
- })
- .style("stroke", colors[day])
- .attr("r", 1)
+ dot.enter().append("svg:circle")
+ .attr("cx", function (d) {
+ return x(d.timeStamp-dayMinTs);
+ })
+ .attr("cy", function (d) {
+ return y(d.value);
+ })
+ .style("stroke", colors[day])
+ .attr("r", 1)
+ .attr("opacity","0")
-}
+ }
});
})
})
@@ -198,29 +198,25 @@ function transitionBoth() {
}
// put the data in d into n buckets
-function putToBuckets(data,n) {
+function putToBuckets(data,n,now) {
- var band = d3.extent(data,function(d){ return d.timeStamp;});
- var bs = band[1] - band[0];
-// var bs = bs / n;
- var bs = 86400*1000;
+ var band = d3.extent(data,function(d){ return d.timeStamp;});
+ var bs = 86400*1000;
+ var start = now - n * bs;
-console.log("bs : " + bs );
-console.log("min ts : " + band[0]);
-
-var dat = new Array(n);
-for (i = 0; i < n ; i++ ) {
- dat[i]=new Array();
-}
+ var dat = new Array(n);
+ for (i = 0; i < n ; i++ ) {
+ dat[i]=new Array();
+ }
-data.forEach(function (d) {
- var diff = d.timeStamp-band[0];
- var bucket = parseInt(diff / bs);
-console.log(d.timeStamp + ", " + diff + " buck : " + bucket);
- dat[bucket].push(d);
-});
+ data.forEach(function (d) {
+ var diff = d.timeStamp-start;
+ var bucket = parseInt(diff / bs);
+// console.log(d.timeStamp + ", " + diff + " buck : " + bucket);
+ dat[bucket].push(d);
+ });
-return dat;
+ return dat;
}
</script>
commit 6483f4edcf08478af30763af05df004b5840e350
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Jan 11 15:03:38 2012 +0100
Explicitly list the container-lib in the list of submodules of
the enterprise/server module with hope of resolving the mysterious Jenkins
build failures. Also slightly increase the logging verbosity in the itests
to see what might be going wrong.
diff --git a/modules/enterprise/server/itests/src/test/resources/log4j.xml b/modules/enterprise/server/itests/src/test/resources/log4j.xml
index bc65329..1e37497 100644
--- a/modules/enterprise/server/itests/src/test/resources/log4j.xml
+++ b/modules/enterprise/server/itests/src/test/resources/log4j.xml
@@ -19,7 +19,7 @@
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
<param name="Target" value="System.out"/>
- <param name="Threshold" value="WARN"/>
+ <param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Messagen -->
@@ -32,7 +32,7 @@
<appender name="FILE" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="target/server-jar-test.log"/>
- <param name="Threshold" value="WARN"/>
+ <param name="Threshold" value="INFO"/>
<param name="Append" value="false"/>
<layout class="org.apache.log4j.PatternLayout">
diff --git a/modules/enterprise/server/pom.xml b/modules/enterprise/server/pom.xml
index 42d5c4b..8cf8acc 100644
--- a/modules/enterprise/server/pom.xml
+++ b/modules/enterprise/server/pom.xml
@@ -25,6 +25,7 @@
</activation>
<modules>
<module>xml-schemas</module>
+ <module>container-lib</module>
<module>jar</module>
<module>sars</module>
<module>plugins</module>
@@ -44,6 +45,7 @@
</activation>
<modules>
<module>xml-schemas</module>
+ <module>container-lib</module>
<module>jar</module>
<module>safe-invoker</module>
</modules>
commit 9ffda9543216f1176b3fd5ba87d08df5f1bbec87
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Jan 11 15:02:04 2012 +0100
Adding some logging to AccessCheckingInitialContextFactoryBuilder.
Use the correct logger in
the AccessCheckingInitialContextFactoryBuilderInstaller MBean.
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
index 3046af7..9abe13c 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -147,14 +147,17 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
* @throws NamingException If an error occurs loading the factory class.
*/
public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
- final String factoryClassName = (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
+ final String factoryClassName = (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
if (factoryClassName == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No " + Context.INITIAL_CONTEXT_FACTORY + " set. Using the default factory.");
+ }
return DEFAULT_FACTORY;
}
final ClassLoader classLoader = getContextClassLoader();
try {
final Class<?> factoryClass = Class.forName(factoryClassName, true, classLoader);
- InitialContextFactory configuredFactory = (InitialContextFactory) factoryClass.newInstance();
+ InitialContextFactory configuredFactory = (InitialContextFactory) factoryClass.newInstance();
return createSecureWrapper(configuredFactory, environment);
} catch (Exception e) {
throw new NamingException("Failed instantiate InitialContextFactory " + factoryClassName
@@ -175,6 +178,9 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
String providerUrl = (String) environment.get(Context.PROVIDER_URL);
if (providerUrl == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Wrapping " + factory + " of class " + factory.getClass() + " in an access checking wrapper. No provider URL detected.");
+ }
return getAccessCheckingFactory(factory);
} else {
try {
@@ -184,16 +190,32 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
//check if we are accessing the RHQ server through some remoting
//interface.
if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Wrapping " + factory + " of class " + factory.getClass() + " in an access checking wrapper. The provider URL points to this server.");
+ }
return getAccessCheckingFactory(factory);
} else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Wrapping " + factory + " of class " + factory.getClass() + " in an URL preferring wrapper to enable remote connections.");
+ }
return getURLPreferringFactory(factory);
}
} catch (URISyntaxException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("The " + Context.PROVIDER_URL
+ + " is not a valid URI. Falling back to using the access checking wrapper for the factory "
+ + factory + " of class " + factory.getClass() + ".", e);
+ }
return getAccessCheckingFactory(factory);
} catch (UnknownHostException e) {
//let the factory deal with the unknown host...
//this most probably shouldn't be secured because localhost addresses
//should be resolvable.
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("The " + Context.PROVIDER_URL
+ + " is not resolvable. Falling back to using the URL preferring wrapper for the factory "
+ + factory + " of class " + factory.getClass() + ".", e);
+ }
return getURLPreferringFactory(factory);
}
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
index d938c50..a1ccb4f 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
@@ -32,7 +32,7 @@ import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
* @author Lukas Krejci
*/
public class AccessCheckingInitialContextFactoryBuilderInstaller implements AccessCheckingInitialContextFactoryBuilderInstallerMBean {
- private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
+ private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilderInstaller.class);
public void start() throws Exception {
LOG.info("Installing RHQ's access permission checking initial context factory builder");
commit 8eaf6da4148d2eeea265f5deb633ce7a295731ff
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Tue Jan 10 12:35:51 2012 -0500
[Bug 772771 - Agent not syncing updated plugin config at startup]
The resource mtime was not being properly updated when completing the
plugin config sync. If the agent was down at update time it would not
know to sync the resource on startup, or at any point until perhaps
the resource was modified in some other way, or the plugin config was
changed when the agent was up.
Also, in general Resource.setAgentSynchronizationNeeded() should be called
by any code performing an update that requires agent sync. The
Resource.setMtime() method should not be called for this purpose, but
rather only when manual mtime manipulation is required.
- fixed plugin config update
- converted setMtime calls to be setAgentSynchronizationNeeded() where appropriate
- added a missing call to setAgentSynchronizationNeeded() in DiscoveryBossBean
- trivial
-- fixed a method name typo
-- fixed some compiler warnings
-- removed some dead code
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
index dd5da1b..c90ed4e 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/Resource.java
@@ -83,7 +83,7 @@ import org.rhq.core.domain.util.Summary;
* Represents an RHQ managed resource (i.e. a platform, server, or service).
*/
@Entity
-@NamedQueries( {
+@NamedQueries({
@NamedQuery(name = Resource.QUERY_FIND_PROBLEM_RESOURCES_ALERT_ADMIN, query = "" //
+ " SELECT DISTINCT new org.rhq.core.domain.resource.composite.ProblemResourceComposite"
+ " ( "
@@ -1302,6 +1302,12 @@ public class Resource implements Comparable<Resource>, Serializable {
return this.mtime;
}
+ /**
+ * Call this directly only when needing manual manipulation of the mtime. Otherwise, you probably want to
+ * call {@link #setAgentSynchronizationNeeded()}.
+ *
+ * @param mtime
+ */
public void setMtime(long mtime) {
this.mtime = mtime;
}
@@ -1336,8 +1342,6 @@ public class Resource implements Comparable<Resource>, Serializable {
*
* For a list of changes that the agent cares about, see InventoryManager.mergeResource(Resource, Resource)
*/
-
- // @PreUpdate
public void setAgentSynchronizationNeeded() {
this.mtime = System.currentTimeMillis();
}
@@ -1434,7 +1438,7 @@ public class Resource implements Comparable<Resource>, Serializable {
return schedules;
}
- public void setSchendules(Set<MeasurementSchedule> schedules) {
+ public void setSchedules(Set<MeasurementSchedule> schedules) {
this.schedules = schedules;
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
index 5b88fe5..60550be 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/configuration/ConfigurationManagerBean.java
@@ -136,7 +136,6 @@ import org.rhq.enterprise.server.util.QuartzUtil;
* @author John Mazzitelli
* @author Ian Springer
*/
-@SuppressWarnings({ "UnnecessaryLocalVariable", "UnnecessaryReturnStatement" })
@Stateless
@XmlType(namespace = ServerVersion.namespace)
public class ConfigurationManagerBean implements ConfigurationManagerLocal, ConfigurationManagerRemote {
@@ -220,6 +219,7 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
Resource resource = update.getResource();
// link to the newer, persisted configuration object -- regardless of errors
+ resource.setAgentSynchronizationNeeded();
resource.setPluginConfiguration(update.getConfiguration());
if (response.getStatus() == ConfigurationUpdateStatus.SUCCESS) {
@@ -1242,17 +1242,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return configService.validate(configuration, resourceId, isStructured);
}
- private boolean isRawSupported(int resourceId) {
- Resource resource = entityManager.find(Resource.class, resourceId);
- ConfigurationDefinition configDef = resource.getResourceType().getResourceConfigurationDefinition();
- if (configDef == null) {
- return false;
- }
-
- return (ConfigurationFormat.STRUCTURED_AND_RAW == configDef.getConfigurationFormat() || (ConfigurationFormat.RAW == configDef
- .getConfigurationFormat()));
- }
-
private boolean isStructuredAndRawSupported(int resourceId) {
Resource resource = entityManager.find(Resource.class, resourceId);
ConfigurationDefinition configDef = resource.getResourceType().getResourceConfigurationDefinition();
@@ -1691,7 +1680,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
}
public Configuration getConfiguration(Subject subject, int configurationId) {
- @SuppressWarnings({ "UnnecessaryLocalVariable" })
Configuration configuration = getConfigurationById(configurationId);
return configuration;
}
@@ -2337,7 +2325,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return out;
}
- @SuppressWarnings("unchecked")
public PageList<ResourceConfigurationUpdate> findResourceConfigurationUpdatesByCriteria(Subject subject,
ResourceConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2346,8 +2333,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
"resource", subject.getId());
}
- CriteriaQueryRunner<ResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<ResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner<ResourceConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<ResourceConfigurationUpdate> updates = queryRunner.execute();
@@ -2371,7 +2358,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<PluginConfigurationUpdate> findPluginConfigurationUpdatesByCriteria(Subject subject,
PluginConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2380,8 +2366,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
"resource", subject.getId());
}
- CriteriaQueryRunner<PluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<PluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner<PluginConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<PluginConfigurationUpdate> updates = queryRunner.execute();
@@ -2405,7 +2391,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<GroupResourceConfigurationUpdate> findGroupResourceConfigurationUpdatesByCriteria(Subject subject,
GroupResourceConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2414,8 +2399,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
subject.getId());
}
- CriteriaQueryRunner<GroupResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria,
- generator, entityManager);
+ CriteriaQueryRunner<GroupResourceConfigurationUpdate> queryRunner = new CriteriaQueryRunner<GroupResourceConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<GroupResourceConfigurationUpdate> updates = queryRunner.execute();
@@ -2438,7 +2423,6 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
return updates;
}
- @SuppressWarnings("unchecked")
public PageList<GroupPluginConfigurationUpdate> findGroupPluginConfigurationUpdatesByCriteria(Subject subject,
GroupPluginConfigurationUpdateCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2447,8 +2431,8 @@ public class ConfigurationManagerBean implements ConfigurationManagerLocal, Conf
subject.getId());
}
- CriteriaQueryRunner<GroupPluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<GroupPluginConfigurationUpdate> queryRunner = new CriteriaQueryRunner<GroupPluginConfigurationUpdate>(
+ criteria, generator, entityManager);
PageList<GroupPluginConfigurationUpdate> updates = queryRunner.execute();
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index 2ea6234..7609492 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -21,6 +21,7 @@ package org.rhq.enterprise.server.discovery;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -29,7 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.Date;
import javax.ejb.EJB;
import javax.ejb.Stateless;
@@ -44,12 +44,12 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
+
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.discovery.InvalidPluginConfigurationClientException;
import org.rhq.core.clientapi.agent.upgrade.ResourceUpgradeRequest;
@@ -314,16 +314,15 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
final String randomSuffix = UUID.randomUUID().toString();
final String triggerName = TRIGGER_PREFIX + " - " + randomSuffix;
- SimpleTrigger trigger = new SimpleTrigger(triggerName, DEFAULT_JOB_GROUP,
- new Date());
+ SimpleTrigger trigger = new SimpleTrigger(triggerName, DEFAULT_JOB_GROUP, new Date());
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(AgentInventoryStatusUpdateJob.KEY_TRIGGER_NAME, triggerName);
jobDataMap.put(AgentInventoryStatusUpdateJob.KEY_TRIGGER_GROUP_NAME, DEFAULT_JOB_GROUP);
AgentInventoryStatusUpdateJob.externalizeJobValues(jobDataMap,
- AgentInventoryStatusUpdateJob.PLATFORMS_COMMA_LIST, platforms);
+ AgentInventoryStatusUpdateJob.PLATFORMS_COMMA_LIST, platforms);
AgentInventoryStatusUpdateJob.externalizeJobValues(jobDataMap,
- AgentInventoryStatusUpdateJob.SERVERS_COMMA_LIST, servers);
+ AgentInventoryStatusUpdateJob.SERVERS_COMMA_LIST, servers);
trigger.setJobName(DEFAULT_JOB_NAME);
trigger.setJobGroup(DEFAULT_JOB_GROUP);
@@ -333,7 +332,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
scheduler.scheduleJob(trigger);
} else {
JobDetail jobDetail = new JobDetail(DEFAULT_JOB_NAME, DEFAULT_JOB_GROUP,
- AgentInventoryStatusUpdateJob.class);
+ AgentInventoryStatusUpdateJob.class);
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (SchedulerException e) {
@@ -357,10 +356,10 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
AgentClient agentClient = agentManager.getAgentClient(platform.getAgent());
try {
agentClient.getDiscoveryAgentService().synchronizeInventory(
- entityManager.find(ResourceSyncInfo.class, platform.getId()));
+ entityManager.find(ResourceSyncInfo.class, platform.getId()));
} catch (Exception e) {
log.warn("Could not perform commit synchronization with agent for platform [" + platform.getName()
- + "]", e);
+ + "]", e);
}
}
for (Resource server : servers) {
@@ -369,10 +368,10 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
AgentClient agentClient = agentManager.getAgentClient(server.getAgent());
try {
agentClient.getDiscoveryAgentService().synchronizeInventory(
- entityManager.find(ResourceSyncInfo.class, server.getId()));
+ entityManager.find(ResourceSyncInfo.class, server.getId()));
} catch (Exception e) {
log.warn("Could not perform commit synchronization with agent for server [" + server.getName()
- + "]", e);
+ + "]", e);
}
}
}
@@ -511,6 +510,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
}
}
+ @SuppressWarnings("deprecation")
public Set<ResourceUpgradeResponse> upgradeResources(Set<ResourceUpgradeRequest> upgradeRequests) {
Set<ResourceUpgradeResponse> result = new HashSet<ResourceUpgradeResponse>();
@@ -588,8 +588,9 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
private ResourceUpgradeResponse upgradeResource(@NotNull Resource resource, ResourceUpgradeRequest upgradeRequest,
boolean allowGenericPropertiesUpgrade) {
if (upgradeRequest.getUpgradeErrorMessage() != null) {
- ResourceError error = new ResourceError(resource, ResourceErrorType.UPGRADE, upgradeRequest
- .getUpgradeErrorMessage(), upgradeRequest.getUpgradeErrorStackTrace(), upgradeRequest.getTimestamp());
+ ResourceError error = new ResourceError(resource, ResourceErrorType.UPGRADE,
+ upgradeRequest.getUpgradeErrorMessage(), upgradeRequest.getUpgradeErrorStackTrace(),
+ upgradeRequest.getTimestamp());
resourceManager.addResourceError(error);
return null;
}
@@ -767,8 +768,8 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
continue;
}
}
- existingResource = resourceManager.getResourceByParentAndKey(overlord, existingParent, resource
- .getResourceKey(), resourceType.getPlugin(), resourceType.getName());
+ existingResource = resourceManager.getResourceByParentAndKey(overlord, existingParent,
+ resource.getResourceKey(), resourceType.getPlugin(), resourceType.getName());
}
if (existingResource != null) {
@@ -871,6 +872,7 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
if (existingResource.getInventoryStatus() == InventoryStatus.DELETED) {
existingResource.setInventoryStatus(InventoryStatus.COMMITTED);
existingResource.setPluginConfiguration(updatedResource.getPluginConfiguration());
+ existingResource.setAgentSynchronizationNeeded();
}
for (Resource childResource : updatedResource.getChildResources()) {
@@ -1021,14 +1023,14 @@ public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemot
// Do one query per 1000 Resource id's to prevent Oracle from failing because of an IN clause with more
// than 1000 items.
- List<Resource> resources = new ArrayList(resourceIds.length);
+ List<Resource> resources = new ArrayList<Resource>(resourceIds.length);
fromIndex = 0;
while (fromIndex < resourceIds.length) {
int toIndex = (resourceIds.length < (fromIndex + 1000)) ? resourceIds.length : (fromIndex + 1000);
int[] resourceIdSubArray = Arrays.copyOfRange(resourceIds, fromIndex, toIndex);
PageList<Resource> batchResources = resourceManager.findResourceByIds(subject, resourceIdSubArray, false,
- PageControl.getUnlimitedInstance());
+ PageControl.getUnlimitedInstance());
resources.addAll(batchResources);
fromIndex = toIndex;
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
index c899487..964d84c 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/ResourceListAdapter.java
@@ -160,7 +160,7 @@ class WsResourceListWrapper extends Resource {
destination.setProductVersion(source.getProductVersion());
destination.setResourceConfiguration(source.getResourceConfiguration());
destination.setResourceConfigurationUpdates(source.getResourceConfigurationUpdates());
- destination.setSchendules(source.getSchedules());
+ destination.setSchedules(source.getSchedules());
destination.setUuid(source.getUuid());
//handle the problematic references that would cause cycles if used by storing only ids.
if (source.getParentResource() != null) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
index 20d1c95..3c74f06 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/jaxb/adapter/WsResource.java
@@ -116,7 +116,7 @@ class WsResource extends Resource {
destination.setProductVersion(source.getProductVersion());
destination.setResourceConfiguration(source.getResourceConfiguration());
destination.setResourceConfigurationUpdates(source.getResourceConfigurationUpdates());
- destination.setSchendules(source.getSchedules());
+ destination.setSchedules(source.getSchedules());
destination.setUuid(source.getUuid());
//handle the problematic references that would cause cycles if used by storing only ids.
if (source.getParentResource() != null) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
index 8a21886..fba8a68 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDefinitionManagerBean.java
@@ -74,8 +74,6 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
* @param def the MeasuremendDefinition to delete
*/
public void removeMeasurementDefinition(MeasurementDefinition def) {
- long now = System.currentTimeMillis();
-
// First remove the schedules and associated OOBs.
List<MeasurementSchedule> schedules = def.getSchedules();
Iterator<MeasurementSchedule> schedIter = schedules.iterator();
@@ -86,8 +84,7 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
sched.setBaseline(null);
}
oobManager.removeOOBsForSchedule(subjectManager.getOverlord(), sched);
- // IMPORTANT: Update the mtime to tell the Agent this Resource needs to be synced.
- sched.getResource().setMtime(now);
+ sched.getResource().setAgentSynchronizationNeeded();
entityManager.remove(sched);
schedIter.remove();
}
@@ -134,14 +131,13 @@ public class MeasurementDefinitionManagerBean implements MeasurementDefinitionMa
return results;
}
- @SuppressWarnings("unchecked")
public PageList<MeasurementDefinition> findMeasurementDefinitionsByCriteria(Subject subject,
MeasurementDefinitionCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
;
- CriteriaQueryRunner<MeasurementDefinition> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager);
+ CriteriaQueryRunner<MeasurementDefinition> queryRunner = new CriteriaQueryRunner<MeasurementDefinition>(
+ criteria, generator, entityManager);
return queryRunner.execute();
}
}
\ No newline at end of file
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 5b6b048..69a22db 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
@@ -24,21 +24,14 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.Date;
import java.util.UUID;
-import org.quartz.Trigger;
-import org.quartz.Scheduler;
-import org.quartz.JobDetail;
-import org.quartz.JobDataMap;
-import org.quartz.SimpleTrigger;
-import org.quartz.SchedulerException;
-
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
@@ -52,6 +45,12 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.SimpleTrigger;
+import org.quartz.Trigger;
import org.jboss.annotation.IgnoreDependency;
@@ -318,13 +317,13 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
return;
}
- @RequiredPermissions( { @RequiredPermission(Permission.MANAGE_INVENTORY),
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_INVENTORY),
@RequiredPermission(Permission.MANAGE_SETTINGS) })
public void disableAllDefaultCollections(Subject subject) {
entityManager.createNamedQuery(MeasurementDefinition.DISABLE_ALL).executeUpdate();
}
- @RequiredPermissions( { @RequiredPermission(Permission.MANAGE_INVENTORY),
+ @RequiredPermissions({ @RequiredPermission(Permission.MANAGE_INVENTORY),
@RequiredPermission(Permission.MANAGE_SETTINGS) })
public void disableAllSchedules(Subject subject) {
entityManager.createNamedQuery(MeasurementSchedule.DISABLE_ALL).executeUpdate();
@@ -332,11 +331,10 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
}
public void createSchedulesForExistingResources(ResourceType type, MeasurementDefinition newDefinition) {
- long now = System.currentTimeMillis();
List<Resource> resources = type.getResources();
if (resources != null) {
for (Resource res : resources) {
- res.setMtime(now); // changing MTime tells the agent this resource needs to be synced
+ res.setAgentSynchronizationNeeded();
MeasurementSchedule sched = new MeasurementSchedule(newDefinition, res);
sched.setInterval(newDefinition.getDefaultInterval());
entityManager.persist(sched);
@@ -649,16 +647,10 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
final String randomSuffix = UUID.randomUUID().toString();
final String jobName = DEFAULT_AGENT_JOB + " - " + randomSuffix;
- JobDetail jobDetail = new JobDetail(
- jobName,
- DEFAULT_AGENT_GROUP,
- NotifyAgentsOfScheduleUpdatesJob.class);
+ JobDetail jobDetail = new JobDetail(jobName, DEFAULT_AGENT_GROUP, NotifyAgentsOfScheduleUpdatesJob.class);
final String triggerName = DEFAULT_AGENT_TRIGGER + " - " + randomSuffix;
- SimpleTrigger simpleTrigger = new SimpleTrigger(
- triggerName,
- DEFAULT_AGENT_GROUP,
- new Date());
+ SimpleTrigger simpleTrigger = new SimpleTrigger(triggerName, DEFAULT_AGENT_GROUP, new Date());
JobDataMap jobDataMap = simpleTrigger.getJobDataMap();
jobDataMap.put(TRIGGER_NAME, triggerName);
@@ -1236,8 +1228,8 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// first get all the resources, which is needed to get the agent mappings
Subject overlord = subjectManager.getOverlord();
- PageList<Resource> resources = resourceManager.findResourceByIds(overlord, resourceIds, false, PageControl
- .getUnlimitedInstance());
+ PageList<Resource> resources = resourceManager.findResourceByIds(overlord, resourceIds, false,
+ PageControl.getUnlimitedInstance());
// then get all the requests
Set<ResourceMeasurementScheduleRequest> requests = findSchedulesForResourceAndItsDescendants(resourceIds, false);
@@ -1483,8 +1475,8 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
;
if (authorizationManager.isInventoryManager(subject) == false) {
- generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.RESOURCE, subject
- .getId());
+ generator.setAuthorizationResourceFragment(CriteriaQueryGenerator.AuthorizationTokenType.RESOURCE,
+ subject.getId());
}
CriteriaQueryRunner<MeasurementSchedule> queryRunner = new CriteriaQueryRunner(criteria, generator,
@@ -1523,4 +1515,3 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
// }
}
-
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
index f2d05c5..14479ba 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceManagerBean.java
@@ -238,8 +238,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
persistedResource.setLocation(resource.getLocation());
persistedResource.setDescription(resource.getDescription());
- // NOTE: Updating the mtime will tell the Agent it needs to sync this Resource.
- persistedResource.setMtime(System.currentTimeMillis());
+ persistedResource.setAgentSynchronizationNeeded();
persistedResource.setModifiedBy(user.getName());
return entityManager.merge(persistedResource);
@@ -614,7 +613,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
private void updateInventoryStatus(Resource resource, InventoryStatus newStatus, long now) {
resource.setInventoryStatus(newStatus);
resource.setItime(now);
- resource.setMtime(now);
+ resource.setAgentSynchronizationNeeded();
}
@SuppressWarnings("unchecked")
@@ -757,8 +756,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
// Build up a list of composite Resources for the ancestry that includes which ancestors, if any, should be
// locked from view.
boolean isInventoryManager = authorizationManager.isInventoryManager(subject);
- List<ResourceLineageComposite> resourceLineage = new ArrayList<ResourceLineageComposite>(rawResourceLineage
- .size());
+ List<ResourceLineageComposite> resourceLineage = new ArrayList<ResourceLineageComposite>(
+ rawResourceLineage.size());
for (Resource resource : rawResourceLineage) {
boolean isLocked = !(isInventoryManager || authorizationManager.canViewResource(subject, resource.getId()));
ResourceLineageComposite composite = new ResourceLineageComposite(resource, isLocked);
@@ -776,8 +775,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
// If the ancestor is not locked, include viewable children.
if (!ancestor.isLocked() || ancestor.getResource() == parent) {
// Get all viewable committed children.
- PageList<Resource> children = findChildResourcesByCategoryAndInventoryStatus(subject, ancestor
- .getResource(), null, InventoryStatus.COMMITTED, PageControl.getUnlimitedInstance());
+ PageList<Resource> children = findChildResourcesByCategoryAndInventoryStatus(subject,
+ ancestor.getResource(), null, InventoryStatus.COMMITTED, PageControl.getUnlimitedInstance());
// Remove any that are in the lineage to avoid repeated handling.
children.removeAll(rawResourceLineage);
for (Resource child : children) {
@@ -1384,7 +1383,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return result;
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public List<AutoGroupComposite> findResourcesAutoGroups(Subject subject, int[] resourceIds) {
List<AutoGroupComposite> results = new ArrayList<AutoGroupComposite>();
List<Integer> ids = ArrayUtils.wrapInList(resourceIds);
@@ -1484,6 +1483,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
query.setParameter("inventoryStatus", InventoryStatus.COMMITTED);
List<Object[]> objs = query.getResultList();
+ @SuppressWarnings("rawtypes")
List results = new ArrayList<ResourceWithAvailability>(objs.size());
for (Object[] ob : objs) {
Resource r = (Resource) ob[0];
@@ -1814,7 +1814,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -1847,7 +1847,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -1890,7 +1890,7 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
List<Resource> resources = query.getResultList();
- return new PageList(resources, (int) count, pageControl);
+ return new PageList<Resource>(resources, (int) count, pageControl);
}
@SuppressWarnings("unchecked")
@@ -2396,7 +2396,6 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return results;
}
- @SuppressWarnings("unchecked")
public PageList<ResourceComposite> findResourceCompositesByCriteria(Subject subject, ResourceCriteria criteria) {
boolean isInventoryManager = authorizationManager.isInventoryManager(subject);
@@ -2440,8 +2439,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
subject.getId());
}
- CriteriaQueryRunner<ResourceComposite> queryRunner = new CriteriaQueryRunner(criteria, generator,
- entityManager, false); // don't auto-init bags, we're returning composites not entities
+ CriteriaQueryRunner<ResourceComposite> queryRunner = new CriteriaQueryRunner<ResourceComposite>(criteria,
+ generator, entityManager, false); // don't auto-init bags, we're returning composites not entities
PageList<ResourceComposite> results = queryRunner.execute();
for (ResourceComposite nextComposite : results) {
@@ -2456,7 +2455,6 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
return results;
}
- @SuppressWarnings("unchecked")
public PageList<Resource> findResourcesByCriteria(Subject subject, ResourceCriteria criteria) {
CriteriaQueryGenerator generator = new CriteriaQueryGenerator(subject, criteria);
@@ -2470,7 +2468,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
subject.getId());
}
- CriteriaQueryRunner<Resource> queryRunner = new CriteriaQueryRunner(criteria, generator, entityManager);
+ CriteriaQueryRunner<Resource> queryRunner = new CriteriaQueryRunner<Resource>(criteria, generator,
+ entityManager);
PageList<Resource> results = queryRunner.execute();
return results;
}
@@ -2521,8 +2520,8 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
public <T> List<DisambiguationReport<T>> disambiguate(List<T> results, IntExtractor<? super T> extractor,
DisambiguationUpdateStrategy updateStrategy) {
- return Disambiguator.disambiguate(results, updateStrategy, extractor, entityManager, typeManager
- .getDuplicateTypeNames());
+ return Disambiguator.disambiguate(results, updateStrategy, extractor, entityManager,
+ typeManager.getDuplicateTypeNames());
}
public void updateAncestry(Subject subject, int resourceId) {
@@ -2545,13 +2544,13 @@ public class ResourceManagerBean implements ResourceManagerLocal, ResourceManage
@SuppressWarnings("unchecked")
public List<Integer> findIdsByTypeIds(List<Integer> resourceTypeIds) {
- return entityManager.createNamedQuery(Resource.QUERY_FIND_IDS_BY_TYPE_IDS).setParameter("resourceTypeIds",
- resourceTypeIds).getResultList();
+ return entityManager.createNamedQuery(Resource.QUERY_FIND_IDS_BY_TYPE_IDS)
+ .setParameter("resourceTypeIds", resourceTypeIds).getResultList();
}
@Override
public Integer getResourceCount(List<Integer> resourceTypeIds) {
- return (Integer) entityManager.createNamedQuery(Resource.QUERY_FIND_COUNT_BY_TYPES).setParameter(
- "resourceTypeIds", resourceTypeIds).getSingleResult();
+ return (Integer) entityManager.createNamedQuery(Resource.QUERY_FIND_COUNT_BY_TYPES)
+ .setParameter("resourceTypeIds", resourceTypeIds).getSingleResult();
}
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
index 3963f9d..841fe03 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/metadata/PluginConfigurationMetadataManagerBean.java
@@ -1,6 +1,5 @@
package org.rhq.enterprise.server.resource.metadata;
-import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
@@ -58,8 +57,8 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
// all new
if (existingConfigurationDefinition == null) {
if (log.isDebugEnabled()) {
- log.debug(existingType + " currently does not have a plugin configuration definition. Adding " +
- "new plugin configuration.");
+ log.debug(existingType + " currently does not have a plugin configuration definition. Adding "
+ + "new plugin configuration.");
}
entityMgr.persist(newType.getPluginConfigurationDefinition());
existingType.setPluginConfigurationDefinition(newType.getPluginConfigurationDefinition());
@@ -72,8 +71,8 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
.updateConfigurationDefinition(newType.getPluginConfigurationDefinition(),
existingConfigurationDefinition);
- if (updateReport.getNewPropertyDefinitions().size() > 0 ||
- updateReport.getUpdatedPropertyDefinitions().size() > 0) {
+ if (updateReport.getNewPropertyDefinitions().size() > 0
+ || updateReport.getUpdatedPropertyDefinitions().size() > 0) {
Subject overlord = subjectMgr.getOverlord();
ResourceCriteria criteria = new ResourceCriteria();
criteria.addFilterResourceTypeId(existingType.getId());
@@ -99,6 +98,7 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
private void updateResourcePluginConfiguration(Resource resource, ConfigurationDefinitionUpdateReport updateReport) {
Configuration pluginConfiguration = resource.getPluginConfiguration();
boolean modified = false;
+ @SuppressWarnings("unused")
int numberOfProperties = pluginConfiguration.getProperties().size();
ConfigurationTemplate template = updateReport.getConfigurationDefinition().getDefaultTemplate();
Configuration templateConfiguration = template.getConfiguration();
@@ -106,10 +106,10 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
for (PropertyDefinition propertyDef : updateReport.getNewPropertyDefinitions()) {
if (propertyDef.isRequired()) {
Property templateProperty = templateConfiguration.get(propertyDef.getName());
- if (templateProperty==null) {
+ if (templateProperty == null) {
throw new IllegalArgumentException("The property [" + propertyDef.getName()
- + "] marked as required in the configuration definition of [" + propertyDef.getConfigurationDefinition().getName()
- + "] has no attribute 'default'");
+ + "] marked as required in the configuration definition of ["
+ + propertyDef.getConfigurationDefinition().getName() + "] has no attribute 'default'");
} else {
pluginConfiguration.put(templateProperty.deepCopy(false));
modified = true;
@@ -129,7 +129,7 @@ public class PluginConfigurationMetadataManagerBean implements PluginConfigurati
}
if (modified) {
- resource.setMtime(new Date().getTime());
+ resource.setAgentSynchronizationNeeded();
}
}
}
commit ca98fa5acf8c59902ff3dac98215605a4a455237
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 10 14:25:11 2012 +0100
Moving the JNDI access tests from rhq-server-client-api to
rhq-server-itests to reduce the number of tests suites that set up
the whole RHQ container.
Made sure to avoid multiple inclusion of the server jar classes on
the test classpath (by explicitly excluding the module from the deps of
rhq-script-bindings and rhq-server-client-api that the itests module is
now dependent on). This caused some weird problems during the embedded
container startup.
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index 4dfd109..29ac29a 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -15,380 +15,32 @@
<name>RHQ Enterprise Server Client API</name>
<description>The implementation of the client API when accessing the server locally</description>
- <properties>
- <persistence-api.version>1.0</persistence-api.version>
- <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
- <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
-
- <!-- dependency versions -->
- <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
-
- <clean.db>true</clean.db>
- </properties>
-
- <dependencies>
-
- <!-- Note, the test deps are intentionally placed above the other scoped deps because of classpath
- reasons. Maven orders the [test] classpath in the order listed in the pom. We specifically
- need the embeddable-ejb3 jar above the standard ejb3 jars because we need the embeddble packages
- loaded when testing. -->
- <dependency>
- <groupId>jboss.jboss-embeddable-ejb3</groupId>
- <artifactId>jboss-ejb3-all</artifactId>
- <version>${jboss-embeddable-ejb3.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>rhq-script-bindings</artifactId>
- <version>${project.version}</version>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.persistence</groupId>
- <artifactId>persistence-api</artifactId>
- <version>${persistence-api.version}</version>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate-annotations</groupId>
- <artifactId>hibernate-annotations</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-ejb3x</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <!-- Test deps - this insane list of deps is needed to get the embedded JBoss server with RHQ server deployed running -->
-
+ <dependencies>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>test-utils</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-container-lib</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate</groupId>
- <artifactId>hibernate3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate-entitymanager</groupId>
- <artifactId>hibernate-entitymanager</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-javamail_1.3.1_spec</artifactId>
- <!-- The Sun javamail jar isn't available from a public repo due to licensing issues,
- so use the Geronimo one instead. -->
- <version>1.3</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.4</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>jsp-api</artifactId>
- <version>2.0</version>
- <scope>test</scope>
- </dependency>
-
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz-oracle</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-annotations-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-cache</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-common</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed by the PoolClass annotation used on some
- of our SLSB's -->
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-j2ee</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-jmx</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-system</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jbosssx</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jbpm</artifactId>
- <version>3.1.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>antlr</groupId>
- <artifactId>antlr</artifactId>
- <version>2.7.7</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javassist</groupId>
- <artifactId>javassist</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>trove</groupId>
- <artifactId>trove</artifactId>
- <version>1.0.2</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.8.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>net.sf.opencsv</groupId>
- <artifactId>opencsv</artifactId>
- <version>1.8</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>commons-jxpath</groupId>
- <artifactId>commons-jxpath</artifactId>
- <version>1.3</version>
- <scope>test</scope>
- </dependency>
-
- <!-- for the transaction interrupt EJB3 interceptor -->
- <dependency>
- <groupId>org.jboss.transaction</groupId>
- <artifactId>jboss-jta</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-script-bindings</artifactId>
+ <version>${project.version}</version>
</dependency>
<dependency>
- <groupId>tomcat</groupId>
- <artifactId>catalina</artifactId>
- <version>5.5.20</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>tomcat</groupId>
- <artifactId>tomcat-jk</artifactId>
- <version>4.1.31</version>
- <scope>test</scope>
- </dependency>
-
- <!-- Needed by com.jboss.jbossnetwork.apl.actions.xml.XPathProcessor; TODO: Remove once APL has been excised. -->
- <dependency>
- <groupId>xalan</groupId>
- <artifactId>xalan</artifactId>
- <version>2.5.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>com.jcraft</groupId>
- <artifactId>jsch</artifactId>
- <version>0.1.29</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-jaxrs</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-jettison-provider</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-links</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.el</groupId>
- <artifactId>jboss-el</artifactId>
- <version>2.0.1.GA</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- <version>2.3.18</version>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <testResources>
- <testResource>
- <directory>src/test/resources</directory>
- <filtering>true</filtering>
- </testResource>
- </testResources>
-
- <plugins>
-
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <!-- Everything but the web service tests, this is the standard test execution -->
- <configuration>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <groups>${rhq.testng.includedGroups}</groups>
- <systemPropertyVariables>
- <embeddedDeployment>true</embeddedDeployment>
- <deploymentDirectory>target/test-classes</deploymentDirectory>
- <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
- <clean.db>${clean.db}</clean.db>
- </systemPropertyVariables>
- <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
- <additionalClasspathElements>
- <!-- The below is required for tests to run against Oracle. -->
- <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
- </additionalClasspathElements>
- </configuration>
- </plugin>
-
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
-
- <!-- in order to get JMS to work properly in embedded test container, extract jms-rs.rar classes -->
- <execution>
- <id>Extract JMS classes from RAR needed for JMS tests</id>
- <phase>process-classes</phase>
- <configuration>
- <tasks>
- <unzip src="src/test/resources/jms-ra.rar" dest="target">
- <patternset>
- <include name="jms-ra.jar"/>
- </patternset>
- </unzip>
- <unzip src="target/jms-ra.jar" dest="target/test-classes">
- <patternset>
- <include name="org/**"/>
- </patternset>
- </unzip>
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
-
- </executions>
- </plugin>
- </plugins>
- </build>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
<profiles>
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
deleted file mode 100644
index dc1fc83..0000000
--- a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package org.rhq.enterprise.client.security.test;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.SerializablePermission;
-import java.security.PermissionCollection;
-import java.util.Collections;
-
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import org.rhq.bindings.SandboxedScriptEngine;
-import org.rhq.bindings.ScriptEngineFactory;
-import org.rhq.bindings.StandardBindings;
-import org.rhq.bindings.StandardScriptPermissions;
-import org.rhq.bindings.util.PackageFinder;
-import org.rhq.core.domain.auth.Subject;
-import org.rhq.enterprise.client.LocalClient;
-import org.rhq.enterprise.server.test.AbstractEJB3Test;
-import org.rhq.enterprise.server.util.LookupUtil;
-import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-@Test
-public class EjbAccessTest extends AbstractEJB3Test {
-
- public void testEjbsAccessibleThroughPrivilegedCode() {
- LookupUtil.getSubjectManager().getOverlord();
- }
-
- public void testEjbsAccessibleThroughLocalClient() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- engine.eval("SubjectManager.getSubjectByName('rhqadmin');");
- }
-
- public void testLocalEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "subjectManager = context.lookup('SubjectManagerBean/local');\n"
- + "subjectManager.getOverlord();");
-
- Assert.fail("The script shouldn't have been able to call local SLSB method.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testRemoteEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "subjectManager = context.lookup('SubjectManagerBean/remote');\n"
- + "subjectManager.getSubjectByName('rhqadmin');");
-
- Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testScriptCantUseSessionManagerMethods() throws Exception {
-
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- final ScriptEngine engine = getEngine(overlord);
-
- class G {
- private String sessionManager = ""
- + "org.rhq.enterprise.server.auth.SessionManager.getInstance().";
-
- public void testInvoke(String methodCall) throws ScriptException {
- String code = sessionManager + methodCall;
-
- try {
- engine.eval(code);
- Assert.fail("The script shouldn't have been able to call a method on a SessionManager: " + methodCall);
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
- };
- G manager = new G();
-
- manager.testInvoke("getlastAccess(0);");
- manager.testInvoke("getOverlord()");
- manager.testInvoke("getSubject(2);");
- manager.testInvoke("invalidate(0);");
- manager.testInvoke("invalidate(\"\");");
- manager.testInvoke("put(new org.rhq.core.domain.auth.Subject());");
- manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
- }
-
- public void testScriptCantObtainRawJDBCConnectionsWithoutCredentials() throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "datasource = context.lookup('java:/RHQDS');\n"
- + "con = datasource.getConnection();");
-
- Assert.fail("The script shouldn't have been able to obtain the datasource from the JNDI.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testScriptCantUseEntityManager() throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
- + "entityManager = entityManagerFactory.createEntityManager();\n"
- + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
-
- Assert.fail("The script shouldn't have been able to use the EntityManager.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
-
- //try harder with manually specifying the initial context factory
- try {
- engine.eval(""
- + "env = new java.util.Hashtable();"
- + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.LocalOnlyContextFactory');"
- + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');"
- + "context = new javax.naming.InitialContext(env);\n"
- + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
- + "entityManager = entityManagerFactory.createEntityManager();\n"
- + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
-
- Assert.fail("The script shouldn't have been able to use the EntityManager even using custom initial context factory.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
- StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
- ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
-
- PermissionCollection perms = new StandardScriptPermissions();
- perms.add(new SerializablePermission("enableSubclassImplementation"));
-
- return new SandboxedScriptEngine(engine, perms);
- }
-
- private static void checkIsDesiredSecurityException(ScriptException e) {
- String message = e.getMessage();
- String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
-
- Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
- }
-}
diff --git a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
deleted file mode 100644
index 1951b84..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
-# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
-# WORK IN THIS MODULE.
-
-hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
-#hibernate.connection.release_mode=after_statement
-#hibernate.transaction.flush_before_completion=false
-#hibernate.transaction.auto_close_session=false
-#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
-#hibernate.hbm2ddl.auto=create-drop
-#hibernate.hbm2ddl.auto=create
-hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
-# Clustered cache with TreeCache
-#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
-#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
-#hibernate.dialect=org.hibernate.dialect.HSQLDialect
-hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
-hibernate.bytecode.use_reflection_optimizer=false
-# I don't think this is honored, but EJB3Deployer uses it
-hibernate.bytecode.provider=javassist
-hibernate.jdbc.use_streams_for_binary=true
-hibernate.show_sql=false
-hibernate.format_sql=true
-hibernate.default_batch_fetch_size=16
-hibernate.jdbc.batch_size=20
diff --git a/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar b/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar
deleted file mode 100644
index c4807c6..0000000
Binary files a/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar and /dev/null differ
diff --git a/modules/enterprise/server/client-api/src/test/resources/security.policy b/modules/enterprise/server/client-api/src/test/resources/security.policy
deleted file mode 100644
index 8860b47..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/security.policy
+++ /dev/null
@@ -1,10 +0,0 @@
-// We need the SecurityManager installed to enable sandboxing of CLI scripts
-// but we don't define any other security measures on the RHQ server itself.
-//
-// Granting all permissions allows us to run the RHQ server as if no security
-// manager was in place (which is assumed by default by JBoss AS) but be able
-// to use it when we need it for our own purposes.
-
-grant {
- permission java.security.AllPermission;
-};
diff --git a/modules/enterprise/server/itests/pom.xml b/modules/enterprise/server/itests/pom.xml
index 6898621..653ef99 100644
--- a/modules/enterprise/server/itests/pom.xml
+++ b/modules/enterprise/server/itests/pom.xml
@@ -58,6 +58,7 @@
<groupId>org.rhq</groupId>
<artifactId>rhq-container-lib</artifactId>
<version>${project.version}</version>
+ <scope>test</scope>
</dependency>
<dependency>
@@ -84,6 +85,32 @@
</dependency>
<dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-script-bindings</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-server-client-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
<groupId>org.rhq.helpers</groupId>
<artifactId>perftest-support</artifactId>
<version>${project.version}</version>
@@ -232,6 +259,7 @@
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy.version}</version>
</dependency>
+
</dependencies>
<build>
@@ -270,6 +298,23 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <!-- Everything but the web service tests, this is the standard test execution -->
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <groups>${rhq.testng.includedGroups}</groups>
+ <systemPropertyVariables>
+ <embeddedDeployment>true</embeddedDeployment>
+ <deploymentDirectory>target/test-classes</deploymentDirectory>
+ </systemPropertyVariables>
+ <argLine>-Djava.security.manager -Djava.security.policy==${basedir}/target/test-classes/security.policy</argLine>
+ <additionalClasspathElements>
+ <!-- The below is required for tests to run against Oracle. -->
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
new file mode 100644
index 0000000..ae848a8
--- /dev/null
+++ b/modules/enterprise/server/itests/src/test/java/org/rhq/enterprise/client/security/test/JndiAccessTest.java
@@ -0,0 +1,198 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.client.security.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.SerializablePermission;
+import java.security.PermissionCollection;
+import java.util.Collections;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.rhq.bindings.SandboxedScriptEngine;
+import org.rhq.bindings.ScriptEngineFactory;
+import org.rhq.bindings.StandardBindings;
+import org.rhq.bindings.StandardScriptPermissions;
+import org.rhq.bindings.util.PackageFinder;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class JndiAccessTest extends AbstractEJB3Test {
+
+ public void testEjbsAccessibleThroughPrivilegedCode() {
+ LookupUtil.getSubjectManager().getOverlord();
+ }
+
+ public void testEjbsAccessibleThroughLocalClient() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ engine.eval("SubjectManager.getSubjectByName('rhqadmin');");
+ }
+
+ public void testLocalEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/local');\n"
+ + "subjectManager.getOverlord();");
+
+ Assert.fail("The script shouldn't have been able to call local SLSB method.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testRemoteEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/remote');\n"
+ + "subjectManager.getSubjectByName('rhqadmin');");
+
+ Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testScriptCantUseSessionManagerMethods() throws Exception {
+
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ final ScriptEngine engine = getEngine(overlord);
+
+ class G {
+ private String sessionManager = ""
+ + "org.rhq.enterprise.server.auth.SessionManager.getInstance().";
+
+ public void testInvoke(String methodCall) throws ScriptException {
+ String code = sessionManager + methodCall;
+
+ try {
+ engine.eval(code);
+ Assert.fail("The script shouldn't have been able to call a method on a SessionManager: " + methodCall);
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+ };
+ G manager = new G();
+
+ manager.testInvoke("getlastAccess(0);");
+ manager.testInvoke("getOverlord()");
+ manager.testInvoke("getSubject(2);");
+ manager.testInvoke("invalidate(0);");
+ manager.testInvoke("invalidate(\"\");");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject());");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
+ }
+
+ public void testScriptCantObtainRawJDBCConnectionsWithoutCredentials() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "datasource = context.lookup('java:/RHQDS');\n"
+ + "con = datasource.getConnection();");
+
+ Assert.fail("The script shouldn't have been able to obtain the datasource from the JNDI.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testScriptCantUseEntityManager() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+
+ //try harder with manually specifying the initial context factory
+ try {
+ engine.eval(""
+ + "env = new java.util.Hashtable();"
+ + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.LocalOnlyContextFactory');"
+ + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');"
+ + "context = new javax.naming.InitialContext(env);\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager even using custom initial context factory.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
+ StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
+ ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
+
+ PermissionCollection perms = new StandardScriptPermissions();
+ perms.add(new SerializablePermission("enableSubclassImplementation"));
+
+ return new SandboxedScriptEngine(engine, perms);
+ }
+
+ private static void checkIsDesiredSecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
+ }
+}
diff --git a/modules/enterprise/server/itests/src/test/resources/embedded-jboss-beans.xml b/modules/enterprise/server/itests/src/test/resources/embedded-jboss-beans.xml
index 05edefa..85e2fb3 100644
--- a/modules/enterprise/server/itests/src/test/resources/embedded-jboss-beans.xml
+++ b/modules/enterprise/server/itests/src/test/resources/embedded-jboss-beans.xml
@@ -4,6 +4,14 @@
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
+ <!-- This installs a custom initial context factory builder into the JVM
+ that will ensure that all the default InitialContexts are going to check
+ for the permission to access the RHQ internals. -->
+ <bean class="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
+ name="AccessCheckingInitialContextFactoryBuilderInstaller">
+ </bean>
+
+
<bean name="Naming" class="org.jnp.server.SingletonNamingServer"/>
<bean name="InitialContextProperties" class="java.util.Hashtable">
@@ -20,7 +28,7 @@
</entry>
</map>
</parameter>
- </constructor>
+ </constructor>
</bean>
<bean name="java:comp/Initializer" class="org.jboss.ejb3.embedded.JavaCompInitializer">
diff --git a/modules/enterprise/server/itests/src/test/resources/security.policy b/modules/enterprise/server/itests/src/test/resources/security.policy
new file mode 100644
index 0000000..8860b47
--- /dev/null
+++ b/modules/enterprise/server/itests/src/test/resources/security.policy
@@ -0,0 +1,10 @@
+// We need the SecurityManager installed to enable sandboxing of CLI scripts
+// but we don't define any other security measures on the RHQ server itself.
+//
+// Granting all permissions allows us to run the RHQ server as if no security
+// manager was in place (which is assumed by default by JBoss AS) but be able
+// to use it when we need it for our own purposes.
+
+grant {
+ permission java.security.AllPermission;
+};
commit 583cdadd3ac3f2aabec176c57423895292fe6348
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 10 10:40:27 2012 +0100
Make sure the decorated contexts behave the same as the originals.
hashCode and equals of the decorators are now taken from the original,
the exceptions from the method calls are rethrown from
the DispatchingInvocationHandler.
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
index 19b30ea..e0f1d84 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
@@ -96,5 +96,15 @@ public class DecoratingInitialContextFactory implements InitialContextFactory {
if (cls.getSuperclass() != null) {
getAllImplementedInterfaces(cls.getSuperclass(), output);
}
- }
+ }
+
+ @Override
+ public int hashCode() {
+ return factory.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return factory.equals(o);
+ }
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
index 6bfec7e..8970b0a 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
@@ -251,4 +251,14 @@ public class AccessCheckingContextDecorator implements Context, ContextDecorator
return str.substring(0, colon_posn);
return null;
}
+
+ @Override
+ public int hashCode() {
+ return getOriginal() == null ? super.hashCode() : getOriginal().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return getOriginal() == null ? super.equals(o) : getOriginal().equals(o);
+ }
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
index 20077de..3f3a95d 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
@@ -209,4 +209,14 @@ public class URLPreferringContextDecorator implements Context, ContextDecorator,
public String getNameInNamespace() throws NamingException {
return getOriginal().getNameInNamespace();
}
+
+ @Override
+ public int hashCode() {
+ return original == null ? super.hashCode() : original.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return original == null ? super.equals(o) : original.equals(o);
+ }
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
index 356a6e9..1bfa7ac 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
@@ -20,6 +20,7 @@
package org.rhq.jndi.util;
import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
@@ -41,6 +42,14 @@ public class DecoratingInvocationHandler<Type, Decorator extends Type> implement
target = picker.decorate(target, methodClass);
}
- return method.invoke(target, args);
+ try {
+ return method.invoke(target, args);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() != null) {
+ throw e.getCause();
+ } else {
+ throw e;
+ }
+ }
}
}
\ No newline at end of file
commit 2c2d2aeffc8dd7adf3e0f60711f9556b52355baf
Author: John Sanda <jsanda(a)redhat.com>
Date: Mon Jan 9 16:25:45 2012 -0500
[BZ 772749] Adding null check for when there are no repos
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/content/repository/tree/ContentRepositoryTreeView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/content/repository/tree/ContentRepositoryTreeView.java
index fac5b79..ffaf0e3 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/content/repository/tree/ContentRepositoryTreeView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/content/repository/tree/ContentRepositoryTreeView.java
@@ -58,8 +58,11 @@ public class ContentRepositoryTreeView extends LocatableTreeGrid {
addNodeClickHandler(new NodeClickHandler() {
public void onNodeClick(NodeClickEvent event) {
- String path = event.getNode().getAttribute("id").replaceAll(":", "/");
- CoreGUI.goToView("Bundles/Repository/" + path);
+ String id = event.getNode().getAttribute("id");
+ if (id != null) {
+ String path = id.replaceAll(":", "/");
+ CoreGUI.goToView("Bundles/Repository/" + path);
+ }
}
});
}
commit c6706aed03df889e23102ea254b2d342141d8b9b
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 9 15:45:21 2012 -0500
[Bug 772742 - DB upgrade gives "All Resources Role" an unintended permission]
Fix the upgrade step that grants the bad permission. And add a new
step to revoke it if it exists.
diff --git a/modules/core/dbutils/pom.xml b/modules/core/dbutils/pom.xml
index 3350cdd..c18ffe1 100644
--- a/modules/core/dbutils/pom.xml
+++ b/modules/core/dbutils/pom.xml
@@ -15,7 +15,7 @@
<description>Database schema setup, upgrade and other utilities</description>
<properties>
- <db.schema.version>2.117</db.schema.version>
+ <db.schema.version>2.118</db.schema.version>
<rhq.ds.type-mapping>${rhq.test.ds.type-mapping}</rhq.ds.type-mapping>
<rhq.ds.db-name>${rhq.test.ds.db-name}</rhq.ds.db-name>
<rhq.ds.connection-url>${rhq.test.ds.connection-url}</rhq.ds.connection-url>
diff --git a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
index 24c536d..c9b0bea 100644
--- a/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
+++ b/modules/core/dbutils/src/main/scripts/dbupgrade/db-upgrade.xml
@@ -3370,12 +3370,12 @@
</statement>
</schema-directSQL>
- <!-- Now add modify the permissions to give all the roles with MANAGE_INVENTORY
- the new MANAGE_REPOSITORIES privilege so that people's privs remain unchanged. -->
+ <!-- Now modify the permissions to give all the roles with MANAGE_INVENTORY, except for
+ all-resources-role, the new MANAGE_REPOSITORIES privilege so that privs remain unchanged. -->
<schema-directSQL>
<statement>
INSERT INTO RHQ_PERMISSION (role_id, operation)
- SELECT role_id, 15 FROM RHQ_PERMISSION WHERE operation = 1
+ SELECT role_id, 15 FROM RHQ_PERMISSION WHERE operation = 1 AND NOT role_id = 2
</statement>
</schema-directSQL>
</schemaSpec>
@@ -3831,6 +3831,15 @@
<!-- Remove an unwanted null consraint -->
<schema-alterColumn table="RHQ_DRIFT_CHANGE_SET" column="DRIFT_DEFINITION_ID" nullable="TRUE" />
</schemaSpec>
+
+ <schemaSpec version="2.118">
+ <!-- Correct an earlier upgrade issue where 'All Resources Role' was granted MANAGE_REPOSITORIES. -->
+ <schema-directSQL>
+ <statement>
+ DELETE FROM RHQ_PERMISSION WHERE role_id = 2 AND operation = 15
+ </statement>
+ </schema-directSQL>
+ </schemaSpec>
</dbupgrade>
</target>
commit da342ac1a965e70e78eb088328fa3c0bdbbdbca7
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 9 15:34:07 2012 -0500
Fix an NPE issue generated for unavailable TC webapp resources. Also,
tune down logging in general for unavailable TC server resources to
help reduce noise in the agent log file. And get rid of a few compile
warnings.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerComponent.java
index bc843ef..98f861b 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerComponent.java
@@ -23,7 +23,6 @@
package org.jboss.on.plugins.tomcat;
import java.io.File;
-import java.sql.SQLException;
import java.util.Properties;
import java.util.Set;
@@ -124,7 +123,7 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
*/
private TomcatServerOperationsDelegate operationsDelegate;
- private ResourceContext resourceContext;
+ private ResourceContext<T> resourceContext;
// JMXComponent Implementation --------------------------------------------
@@ -134,7 +133,9 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
try {
emsConnection = loadConnection();
} catch (Exception e) {
- log.error("Component attempting to access a connection that could not be loaded");
+ if (log.isTraceEnabled()) {
+ log.debug("Component attempting to access a connection that could not be loaded:" + e.getMessage());
+ }
}
return emsConnection;
@@ -232,6 +233,7 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
if (log.isDebugEnabled())
log.debug("Successfully made connection to the Tomcat Server for resource ["
+ this.resourceContext.getResourceKey() + "]");
+
} catch (Exception e) {
// The connection will be established even in the case that the principal cannot be authenticated,
@@ -239,8 +241,9 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
// the connection is established. If we get to this point that an exception was thrown, close any
// connection that was made and null it out so we can try to establish it again.
if (this.connection != null) {
- if (log.isDebugEnabled())
+ if (log.isDebugEnabled()) {
log.debug("Connection created but an exception was thrown. Closing the connection.", e);
+ }
try {
this.connection.close();
} catch (Exception e2) {
@@ -250,19 +253,21 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
}
// Since the connection is attempted each time it's used, failure to connect could result in log
- // file spamming. Log it once for every 10 consecutive times it's encountered.
- if (consecutiveConnectionErrors % 10 == 0) {
- log.warn(
- "Could not establish connection to the Tomcat instance [" + (consecutiveConnectionErrors + 1)
- + "] times for resource [" + resourceContext.getResourceKey() + "]", e);
+ // file spamming. Log a warning only one time outside of debug mode, and throttle even in debug
+ // mode (once for every 10 connect errors).
+ if (0 == consecutiveConnectionErrors) {
+ log.warn("Could not connect to the Tomcat instance for resource ["
+ + resourceContext.getResourceKey() + "] (enable debug logging for more info): "
+ + e.getMessage());
}
- if (log.isDebugEnabled())
+ if (log.isDebugEnabled() && (consecutiveConnectionErrors % 10 == 0)) {
log.debug(
- "Could not connect to the Tomcat instance for resource [" + resourceContext.getResourceKey()
- + "]", e);
+ "Could not establish connection to the Tomcat instance [" + (consecutiveConnectionErrors + 1)
+ + "] times for resource [" + resourceContext.getResourceKey() + "]", e);
+ }
- consecutiveConnectionErrors++;
+ ++consecutiveConnectionErrors;
throw e;
}
@@ -293,7 +298,8 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
}
}
- public void start(ResourceContext context) throws SQLException {
+ @Override
+ public void start(ResourceContext<T> context) throws InvalidPluginConfigurationException, Exception {
this.resourceContext = context;
this.operationsDelegate = new TomcatServerOperationsDelegate(this, resourceContext.getSystemInformation());
@@ -360,7 +366,7 @@ public class TomcatServerComponent<T extends ResourceComponent<?>> implements JM
}
}
- ResourceContext getResourceContext() {
+ ResourceContext<T> getResourceContext() {
return this.resourceContext;
}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
index 9ecc0d7..d1c0f59 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarComponent.java
@@ -349,13 +349,13 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
throw new IllegalStateException("Could not find MBean for WAR '" + getApplicationName() + "'.");
}
- EmsOperation mbeanOperation = this.webModuleMBean.getOperation(name);
+ // NOTE: None of the supported operations have any parameters or return values, which makes our job easier.
+ EmsOperation mbeanOperation = this.webModuleMBean.getOperation(name, new Class[0]);
if (mbeanOperation == null) {
throw new IllegalStateException("Operation [" + name + "] not found on bean ["
+ this.webModuleMBean.getBeanName() + "]");
}
- // NOTE: None of the supported operations have any parameters or return values, which makes our job easier.
Object[] paramValues = new Object[0];
mbeanOperation.invoke(paramValues);
@@ -417,12 +417,15 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
String webModuleMBeanName = getWebModuleMBeanName();
EmsBean result = null;
- if (webModuleMBeanName != null) {
- ObjectNameQueryUtility queryUtility = new ObjectNameQueryUtility(webModuleMBeanName);
- List<EmsBean> mBeans = getEmsConnection().queryBeans(queryUtility.getTranslatedQuery());
- // There should only be one mBean for this match.
- if (mBeans.size() == 1) {
- result = mBeans.get(0);
+ if (null != webModuleMBeanName) {
+ EmsConnection conn = getEmsConnection();
+ if (null != conn) {
+ ObjectNameQueryUtility queryUtility = new ObjectNameQueryUtility(webModuleMBeanName);
+ List<EmsBean> mBeans = conn.queryBeans(queryUtility.getTranslatedQuery());
+ // There should only be one mBean for this match.
+ if (mBeans.size() == 1) {
+ result = mBeans.get(0);
+ }
}
}
@@ -449,8 +452,8 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
private List<EmsBean> getVHosts() {
EmsConnection emsConnection = getEmsConnection();
String query = QUERY_TEMPLATE_HOST;
- query = query.replace("%PATH%", getResourceContext().getPluginConfiguration().getSimpleValue(
- PROPERTY_CONTEXT_ROOT, ""));
+ query = query.replace("%PATH%",
+ getResourceContext().getPluginConfiguration().getSimpleValue(PROPERTY_CONTEXT_ROOT, ""));
ObjectNameQueryUtility queryUtil = new ObjectNameQueryUtility(query);
List<EmsBean> mBeans = emsConnection.queryBeans(queryUtil.getTranslatedQuery());
return mBeans;
@@ -741,9 +744,8 @@ public class TomcatWarComponent extends MBeanResourceComponent<TomcatVHostCompon
File file = new File(fileName);
if (!file.exists()) {
- log
- .warn("Could not delete web application files (perhaps removed manually?). Proceeding with resource removal for: "
- + fileName);
+ log.warn("Could not delete web application files (perhaps removed manually?). Proceeding with resource removal for: "
+ + fileName);
} else {
deleteApp(pluginConfiguration, file, false, true);
}
commit 791205857b2e3550e51ea1e101b8a4704ebfad33
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Mon Jan 9 15:32:22 2012 -0500
[Bug 703562 - Tomcat plugin missing support for JNDI configured Datasources]
Added support for Datasources. Tomcat allows DS Resource declaration at the
global/host/app level. A global DS is available to all apps, a host DS is
available to all apps for that host, and then at the app level, just the
declaring app. As such Tomcat creates DS Mbeans at the app level, one for
each DS available to the app. This structure is reflected in the updated
Tomcat resource hierarchy. Although there is seeming redundancy for global
amd host level datasources, it seems to best reflect the TC intents, and
also the underlying mbeans.
For more on configuring datasources see:
http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html
http://tomcat.apache.org/tomcat-6.0-doc/config/context.html
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceComponent.java
new file mode 100644
index 0000000..df74483
--- /dev/null
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceComponent.java
@@ -0,0 +1,35 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.jboss.on.plugins.tomcat;
+
+import org.rhq.plugins.jmx.MBeanResourceComponent;
+
+/**
+ * Handle generic information about an application cache
+ *
+ * @author Jay Shaughnessy
+ *
+ */
+public class TomcatDatasourceComponent extends MBeanResourceComponent<TomcatWarComponent> {
+
+ public static final String PROPERTY_HOST = "host";
+ public static final String PROPERTY_PATH = "path";
+
+}
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java
new file mode 100644
index 0000000..4749544
--- /dev/null
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatDatasourceDiscoveryComponent.java
@@ -0,0 +1,63 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.jboss.on.plugins.tomcat;
+
+import java.util.Set;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+import org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent;
+
+/**
+ * Discover Application Datasource
+ *
+ * @author Jay Shaughnessy
+ */
+public class TomcatDatasourceDiscoveryComponent extends MBeanResourceDiscoveryComponent<TomcatWarComponent> {
+
+ @Override
+ public Set<DiscoveredResourceDetails> discoverResources(
+ ResourceDiscoveryContext<TomcatWarComponent> discoveryContext) {
+
+ Configuration defaultPluginConfig = discoveryContext.getDefaultPluginConfiguration();
+ String objectNameTemplate = defaultPluginConfig.getSimple(PROPERTY_OBJECT_NAME).getStringValue();
+ String host = discoveryContext.getParentResourceContext().getPluginConfiguration()
+ .getSimpleValue(TomcatWarComponent.PROPERTY_VHOST, null);
+ String path = discoveryContext.getParentResourceContext().getPluginConfiguration()
+ .getSimpleValue(TomcatWarComponent.PROPERTY_CONTEXT_ROOT, null);
+ objectNameTemplate = objectNameTemplate.replace("%host%", host);
+ objectNameTemplate = objectNameTemplate.replace("%path%", path);
+ defaultPluginConfig.put(new PropertySimple(PROPERTY_OBJECT_NAME, objectNameTemplate));
+
+ Set<DiscoveredResourceDetails> resources = super.performDiscovery(defaultPluginConfig,
+ discoveryContext.getParentResourceComponent(), discoveryContext.getResourceType());
+
+ for (DiscoveredResourceDetails detail : resources) {
+ Configuration pluginConfiguration = detail.getPluginConfiguration();
+ pluginConfiguration.put(new PropertySimple(TomcatDatasourceComponent.PROPERTY_HOST, host));
+ pluginConfiguration.put(new PropertySimple(TomcatDatasourceComponent.PROPERTY_PATH, path));
+ String resourceName = detail.getResourceName();
+ detail.setResourceName(resourceName);
+ }
+ return resources;
+ }
+}
diff --git a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
index a5277a8..e86f1d5 100644
--- a/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/tomcat/src/main/resources/META-INF/rhq-plugin.xml
@@ -576,7 +576,103 @@
description="Pathname to a scratch directory to be provided by this Context for temporary read-write use by servlets within the associated web application. This directory will be made visible to servlets in the web application by a servlet context attribute (of type java.io.File) named javax.servlet.context.tempdir as described in the Servlet Specification. If not specified, a suitable directory underneath $CATALINA_BASE/work will be provided."
required="false" />
</c:group>
- </resource-configuration>
+ </resource-configuration>
+
+ <service
+ name="Tomcat Datasource"
+ discovery="TomcatDatasourceDiscoveryComponent"
+ class="TomcatDatasourceComponent"
+ description="A Tomcat Application (WAR) Datasource"
+ singleton="false">
+
+ <plugin-configuration>
+ <c:group name="General">
+ <c:simple-property
+ name="objectName"
+ readOnly="true"
+ default="Catalina:type=DataSource,path=%path%,host=%host%,class=javax.sql.DataSource,name=%name%" />
+ </c:group>
+
+ <c:group
+ name="Advanced"
+ hiddenByDefault="true">
+ <c:simple-property
+ name="name"
+ type="string"
+ readOnly="true"
+ description="The virtual host" />
+ <c:simple-property
+ name="host"
+ description="The datasource host"
+ readOnly="true" />
+ <c:simple-property
+ name="path"
+ description="The datasource application path"
+ readOnly="true" />
+ <c:simple-property
+ name="nameTemplate"
+ default="{name}" />
+ <c:simple-property
+ name="descriptionTemplate"
+ default="Tomcat Web Application Datasource"
+ readOnly="true" />
+ </c:group>
+ </plugin-configuration>
+
+ <metric
+ property="numActive"
+ displayType="summary"
+ description="Number of active connections in the pool" />
+ <metric
+ property="numIdle"
+ displayType="summary"
+ description="Number of idle connections in the pool" />
+
+ <resource-configuration>
+ <c:group name="Attributes">
+ <c:simple-property
+ name="initialSize"
+ type="integer"
+ description="The initial number of connections that are created when the pool is started. Default is 0." />
+ <c:simple-property
+ name="maxActive"
+ type="integer"
+ description="The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit. Default is 8." />
+ <c:simple-property
+ name="maxIdle"
+ type="integer"
+ description="The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit. Default is 8." />
+ <c:simple-property
+ name="minIdle"
+ type="integer"
+ description="The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none. Default is 0." />
+ <c:simple-property
+ name="maxWait"
+ type="integer"
+ description="The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely. Default is indefinitely." />
+ <c:simple-property
+ name="poolPreparedStatements"
+ type="boolean"
+ description="Enable prepared statement pooling for this pool. Default is false." />
+ <c:simple-property
+ name="maxOpenPreparedStatements"
+ type="integer"
+ description="The maximum number of open statements that can be allocated from the statement pool at the same time, or zero for no limit. Default is unlimited." />
+ <c:simple-property
+ name="removeAbandoned"
+ type="boolean"
+ description="Flag to remove abandoned connections if they exceed the removeAbandonedTimout. If set to true a connection is considered abandoned and eligible for removal if it has been idle longer than the removeAbandonedTimeout. Setting this to true can recover db connections from poorly written applications which fail to close a connection. Default is false." />
+ <c:simple-property
+ name="removeAbandonedTimeout"
+ type="integer"
+ description="Timeout in seconds before an abandoned connection can be removed. Default is 300." />
+ <c:simple-property
+ name="logAbandoned"
+ type="boolean"
+ description="Flag to log stack traces for application code which abandoned a Statement or Connection. Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because a stack trace has to be generated. Default is false." />
+ </c:group>
+ </resource-configuration>
+ </service>
<service
name="Tomcat Cache"
@@ -630,6 +726,7 @@
property="cacheMaxSize"
description="Maximum number of cache entries" />
</service>
+
</service>
</service>
commit ac2391109a7b141312f95595341a7dabed4551a4
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Mon Jan 9 15:23:50 2012 -0500
[BZ 771984] is appears that trying to concurrently update a subject's user preferences fails when one of the updates involves inserting a new property. The problem appears from the GWT client, so at the GWT servlet layer, we will now ensure that no two GWT requests can concurrently update a subject.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java
index b790b79..e175134 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/server/gwt/SubjectGWTServiceImpl.java
@@ -36,6 +36,7 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub
private static final long serialVersionUID = 1L;
private SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ private Object subjectLock = new Object(); // used to lock out concurrent subject updates
public void createPrincipal(String username, String password) throws RuntimeException {
try {
@@ -57,7 +58,7 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub
public Subject createSubject(Subject subjectToCreate, String password) throws RuntimeException {
try {
return SerialUtility.prepare(subjectManager.createSubject(getSessionSubject(), subjectToCreate, password),
- "SubjectManager.createSubject");
+ "SubjectManager.createSubjectPW");
} catch (Throwable t) {
throw getExceptionToThrowToClient(t);
}
@@ -89,8 +90,12 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub
public Subject updateSubject(Subject subjectToModify) throws RuntimeException {
try {
- Subject subject = SerialUtility.prepare(subjectManager.updateSubject(getSessionSubject(), subjectToModify),
- "SubjectManager.updateSubject");
+ Subject sessionSubject = getSessionSubject();
+ Subject modifiedSubject;
+ synchronized (subjectLock) {
+ modifiedSubject = subjectManager.updateSubject(sessionSubject, subjectToModify);
+ }
+ Subject subject = SerialUtility.prepare(modifiedSubject, "SubjectManager.updateSubject");
// Clear the prefs for this subject from the user prefs cache that portal-war uses, in case we just
// changed any prefs; otherwise the cache would contain stale prefs.
SubjectPreferencesCache.getInstance().clearConfiguration(subject.getId());
@@ -102,8 +107,16 @@ public class SubjectGWTServiceImpl extends AbstractGWTServiceImpl implements Sub
public Subject updateSubject(Subject subjectToModify, String newPassword) throws RuntimeException {
try {
- return SerialUtility.prepare(subjectManager
- .updateSubject(getSessionSubject(), subjectToModify, newPassword), "SubjectManager.updateSubject");
+ Subject sessionSubject = getSessionSubject();
+ Subject modifiedSubject;
+ synchronized (subjectLock) {
+ modifiedSubject = subjectManager.updateSubject(sessionSubject, subjectToModify, newPassword);
+ }
+ Subject subject = SerialUtility.prepare(modifiedSubject, "SubjectManager.updateSubjectPW");
+ // Clear the prefs for this subject from the user prefs cache that portal-war uses, in case we just
+ // changed any prefs; otherwise the cache would contain stale prefs.
+ SubjectPreferencesCache.getInstance().clearConfiguration(subject.getId());
+ return subject;
} catch (Throwable t) {
throw getExceptionToThrowToClient(t);
}
commit 0e36c3ee8f1954486b1c12ee22ddd4b90cf7e685
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 9 16:57:11 2012 +0100
reverting the secured JNDI access... This functionality is still failing
some tests and so it won't re-emerge in master until I fix them.
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
index 5822d44..894c953 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
@@ -20,7 +20,6 @@
package org.rhq.bindings;
import java.io.FilePermission;
-import java.io.SerializablePermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.Permission;
@@ -84,11 +83,6 @@ public class StandardScriptPermissions extends PermissionCollection {
add(new PropertyPermission("*", "read"));
add(new ReflectPermission("suppressAccessChecks"));
-
- //these 2 are required for server-side scripts to be able to
- //invoke remote EJBs.
- add(new SerializablePermission("enableSubclassImplementation"));
- add(new RuntimePermission("reflectionFactoryAccess"));
}
public void add(Permission permission) {
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index 4dfd109..e777e21 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -17,35 +17,15 @@
<properties>
<persistence-api.version>1.0</persistence-api.version>
- <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
- <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
-
- <!-- dependency versions -->
- <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
-
- <clean.db>true</clean.db>
</properties>
<dependencies>
-
- <!-- Note, the test deps are intentionally placed above the other scoped deps because of classpath
- reasons. Maven orders the [test] classpath in the order listed in the pom. We specifically
- need the embeddable-ejb3 jar above the standard ejb3 jars because we need the embeddble packages
- loaded when testing. -->
- <dependency>
- <groupId>jboss.jboss-embeddable-ejb3</groupId>
- <artifactId>jboss-ejb3-all</artifactId>
- <version>${jboss-embeddable-ejb3.version}</version>
- <scope>test</scope>
- </dependency>
-
<dependency>
<groupId>org.rhq</groupId>
<artifactId>rhq-script-bindings</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
-
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
@@ -60,333 +40,20 @@
section. -->
<scope>provided</scope>
</dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-ejb3x</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <!-- Test deps - this insane list of deps is needed to get the embedded JBoss server with RHQ server deployed running -->
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>test-utils</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-container-lib</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate</groupId>
- <artifactId>hibernate3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate-entitymanager</groupId>
- <artifactId>hibernate-entitymanager</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-javamail_1.3.1_spec</artifactId>
- <!-- The Sun javamail jar isn't available from a public repo due to licensing issues,
- so use the Geronimo one instead. -->
- <version>1.3</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.4</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>jsp-api</artifactId>
- <version>2.0</version>
- <scope>test</scope>
- </dependency>
-
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz-oracle</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-annotations-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-cache</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-common</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed by the PoolClass annotation used on some
- of our SLSB's -->
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-j2ee</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-jmx</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-system</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jbosssx</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jbpm</artifactId>
- <version>3.1.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>antlr</groupId>
- <artifactId>antlr</artifactId>
- <version>2.7.7</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javassist</groupId>
- <artifactId>javassist</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>trove</groupId>
- <artifactId>trove</artifactId>
- <version>1.0.2</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.8.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>net.sf.opencsv</groupId>
- <artifactId>opencsv</artifactId>
- <version>1.8</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>commons-jxpath</groupId>
- <artifactId>commons-jxpath</artifactId>
- <version>1.3</version>
- <scope>test</scope>
- </dependency>
-
- <!-- for the transaction interrupt EJB3 interceptor -->
- <dependency>
- <groupId>org.jboss.transaction</groupId>
- <artifactId>jboss-jta</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>tomcat</groupId>
- <artifactId>catalina</artifactId>
- <version>5.5.20</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>tomcat</groupId>
- <artifactId>tomcat-jk</artifactId>
- <version>4.1.31</version>
- <scope>test</scope>
- </dependency>
-
- <!-- Needed by com.jboss.jbossnetwork.apl.actions.xml.XPathProcessor; TODO: Remove once APL has been excised. -->
- <dependency>
- <groupId>xalan</groupId>
- <artifactId>xalan</artifactId>
- <version>2.5.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>com.jcraft</groupId>
- <artifactId>jsch</artifactId>
- <version>0.1.29</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-jaxrs</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-jettison-provider</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-links</artifactId>
- <version>${resteasy.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.jboss.el</groupId>
- <artifactId>jboss-el</artifactId>
- <version>2.0.1.GA</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- <version>2.3.18</version>
- <scope>test</scope>
- </dependency>
-
</dependencies>
<build>
- <testResources>
- <testResource>
- <directory>src/test/resources</directory>
- <filtering>true</filtering>
- </testResource>
- </testResources>
-
<plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <!-- Everything but the web service tests, this is the standard test execution -->
- <configuration>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <groups>${rhq.testng.includedGroups}</groups>
- <systemPropertyVariables>
- <embeddedDeployment>true</embeddedDeployment>
- <deploymentDirectory>target/test-classes</deploymentDirectory>
- <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
- <clean.db>${clean.db}</clean.db>
- </systemPropertyVariables>
- <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
- <additionalClasspathElements>
- <!-- The below is required for tests to run against Oracle. -->
- <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
- </additionalClasspathElements>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <!-- <argLine>-Xdebug -Xnoagent -Djava.compiler=NONE
+ -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> -->
</configuration>
- </plugin>
-
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
-
- <!-- in order to get JMS to work properly in embedded test container, extract jms-rs.rar classes -->
- <execution>
- <id>Extract JMS classes from RAR needed for JMS tests</id>
- <phase>process-classes</phase>
- <configuration>
- <tasks>
- <unzip src="src/test/resources/jms-ra.rar" dest="target">
- <patternset>
- <include name="jms-ra.jar"/>
- </patternset>
- </unzip>
- <unzip src="target/jms-ra.jar" dest="target/test-classes">
- <patternset>
- <include name="org/**"/>
- </patternset>
- </unzip>
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
+ </plugin>
- </executions>
- </plugin>
</plugins>
</build>
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
index e9f1e4d..5f3ff90 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
@@ -20,8 +20,6 @@
package org.rhq.enterprise.client;
import java.lang.reflect.Method;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import org.apache.commons.logging.Log;
@@ -56,21 +54,11 @@ public class LocalClientProxy extends AbstractRhqFacadeProxy<LocalClient> {
}
}
- protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, final Object[] args) throws Throwable {
+ protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, Object[] args) throws Throwable {
try {
- final Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
-
- //run this through the privileged block to elevate the privs of the script
- //the scripts don't have the AllowEjbAccessPermission but this code has
- //all perms (or at least all perms assigned to it by the current context,
- //which at the time of writing is defined by the rhq-server.policy file
- //which gives all code all permissions).
- return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
- @Override
- public Object run() throws Exception {
- return realMethod.invoke(localSLSB, args);
- }
- });
+ Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
+
+ return realMethod.invoke(localSLSB, args);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Method [" + originalMethod + "] does not have a desimplified counterpart with arguments " + Arrays.asList(argTypes) + ".", e);
}
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
deleted file mode 100644
index dc1fc83..0000000
--- a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package org.rhq.enterprise.client.security.test;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.SerializablePermission;
-import java.security.PermissionCollection;
-import java.util.Collections;
-
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import org.rhq.bindings.SandboxedScriptEngine;
-import org.rhq.bindings.ScriptEngineFactory;
-import org.rhq.bindings.StandardBindings;
-import org.rhq.bindings.StandardScriptPermissions;
-import org.rhq.bindings.util.PackageFinder;
-import org.rhq.core.domain.auth.Subject;
-import org.rhq.enterprise.client.LocalClient;
-import org.rhq.enterprise.server.test.AbstractEJB3Test;
-import org.rhq.enterprise.server.util.LookupUtil;
-import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-@Test
-public class EjbAccessTest extends AbstractEJB3Test {
-
- public void testEjbsAccessibleThroughPrivilegedCode() {
- LookupUtil.getSubjectManager().getOverlord();
- }
-
- public void testEjbsAccessibleThroughLocalClient() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- engine.eval("SubjectManager.getSubjectByName('rhqadmin');");
- }
-
- public void testLocalEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "subjectManager = context.lookup('SubjectManagerBean/local');\n"
- + "subjectManager.getOverlord();");
-
- Assert.fail("The script shouldn't have been able to call local SLSB method.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testRemoteEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "subjectManager = context.lookup('SubjectManagerBean/remote');\n"
- + "subjectManager.getSubjectByName('rhqadmin');");
-
- Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testScriptCantUseSessionManagerMethods() throws Exception {
-
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- final ScriptEngine engine = getEngine(overlord);
-
- class G {
- private String sessionManager = ""
- + "org.rhq.enterprise.server.auth.SessionManager.getInstance().";
-
- public void testInvoke(String methodCall) throws ScriptException {
- String code = sessionManager + methodCall;
-
- try {
- engine.eval(code);
- Assert.fail("The script shouldn't have been able to call a method on a SessionManager: " + methodCall);
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
- };
- G manager = new G();
-
- manager.testInvoke("getlastAccess(0);");
- manager.testInvoke("getOverlord()");
- manager.testInvoke("getSubject(2);");
- manager.testInvoke("invalidate(0);");
- manager.testInvoke("invalidate(\"\");");
- manager.testInvoke("put(new org.rhq.core.domain.auth.Subject());");
- manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
- }
-
- public void testScriptCantObtainRawJDBCConnectionsWithoutCredentials() throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "datasource = context.lookup('java:/RHQDS');\n"
- + "con = datasource.getConnection();");
-
- Assert.fail("The script shouldn't have been able to obtain the datasource from the JNDI.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- public void testScriptCantUseEntityManager() throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
- + "entityManager = entityManagerFactory.createEntityManager();\n"
- + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
-
- Assert.fail("The script shouldn't have been able to use the EntityManager.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
-
- //try harder with manually specifying the initial context factory
- try {
- engine.eval(""
- + "env = new java.util.Hashtable();"
- + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.LocalOnlyContextFactory');"
- + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');"
- + "context = new javax.naming.InitialContext(env);\n"
- + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
- + "entityManager = entityManagerFactory.createEntityManager();\n"
- + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
-
- Assert.fail("The script shouldn't have been able to use the EntityManager even using custom initial context factory.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
- StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
- ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
-
- PermissionCollection perms = new StandardScriptPermissions();
- perms.add(new SerializablePermission("enableSubclassImplementation"));
-
- return new SandboxedScriptEngine(engine, perms);
- }
-
- private static void checkIsDesiredSecurityException(ScriptException e) {
- String message = e.getMessage();
- String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
-
- Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
- }
-}
diff --git a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
deleted file mode 100644
index 1951b84..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
-# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
-# WORK IN THIS MODULE.
-
-hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
-#hibernate.connection.release_mode=after_statement
-#hibernate.transaction.flush_before_completion=false
-#hibernate.transaction.auto_close_session=false
-#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
-#hibernate.hbm2ddl.auto=create-drop
-#hibernate.hbm2ddl.auto=create
-hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
-# Clustered cache with TreeCache
-#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
-#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
-#hibernate.dialect=org.hibernate.dialect.HSQLDialect
-hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
-hibernate.bytecode.use_reflection_optimizer=false
-# I don't think this is honored, but EJB3Deployer uses it
-hibernate.bytecode.provider=javassist
-hibernate.jdbc.use_streams_for_binary=true
-hibernate.show_sql=false
-hibernate.format_sql=true
-hibernate.default_batch_fetch_size=16
-hibernate.jdbc.batch_size=20
diff --git a/modules/enterprise/server/client-api/src/test/resources/security.policy b/modules/enterprise/server/client-api/src/test/resources/security.policy
deleted file mode 100644
index 8860b47..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/security.policy
+++ /dev/null
@@ -1,10 +0,0 @@
-// We need the SecurityManager installed to enable sandboxing of CLI scripts
-// but we don't define any other security measures on the RHQ server itself.
-//
-// Granting all permissions allows us to run the RHQ server as if no security
-// manager was in place (which is assumed by default by JBoss AS) but be able
-// to use it when we need it for our own purposes.
-
-grant {
- permission java.security.AllPermission;
-};
diff --git a/modules/enterprise/server/container-lib/pom.xml b/modules/enterprise/server/container-lib/pom.xml
index 0974431..b832b06 100644
--- a/modules/enterprise/server/container-lib/pom.xml
+++ b/modules/enterprise/server/container-lib/pom.xml
@@ -39,12 +39,6 @@
<scope>provided</scope> <!-- by JBossAS -->
</dependency>
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jnpserver</artifactId>
- <version>4.2.2.GA</version>
- <scope>provided</scope>
- </dependency>
</dependencies>
<profiles>
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
deleted file mode 100644
index 3046af7..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Set;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.naming.event.EventContext;
-import javax.naming.event.EventDirContext;
-import javax.naming.ldap.LdapContext;
-import javax.naming.spi.InitialContextFactory;
-import javax.naming.spi.InitialContextFactoryBuilder;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jnp.interfaces.NamingContextFactory;
-
-import org.rhq.jndi.context.AccessCheckingContextDecorator;
-import org.rhq.jndi.context.AccessCheckingContextDecoratorSetContext;
-import org.rhq.jndi.context.ContextDecorator;
-import org.rhq.jndi.context.URLPreferringContextDecoratorSetContext;
-import org.rhq.jndi.util.DecoratorPicker;
-
-/**
- * This initial context factory builder is installed early on during the RHQ server startup
- * and is later on used for obtaining the {@link Context}s for all JNDI lookups in the
- * RHQ server.
- * <p>
- * We use a custom initial context factory builder to prevent the potential malicious 3rd party
- * code (like CLI alert scripts) from supplying custom environment variables to {@link InitialContext}
- * that would modify the JNDI lookup to skip our security access checks.
- * <p>
- * By using a builder we effectively take control of the initial context creation process
- * and are free to ignore whatever the script is trying to supply.
- * <p>
- * This builder makes sure to install the RHQ server's security access checks to whatever
- * initial context that is configured by the standard environment variables
- * ({@link Context#INITIAL_CONTEXT_FACTORY}, etc.)
- * <p>
- * This class is heavily inspired by the implementation of a similar builder in JBoss AS 7.
- *
- * @see AllowRhqServerInternalsAccessPermission
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
- private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
-
- /**
- * The list of JNDI name schemes that should be checked for security permissions
- * (in addition to the names with no scheme).
- *
- * @see AccessCheckingContextDecorator
- */
- private static final String[] CHECKED_SCHEMES = { "java" };
-
- private static final Set<Class<? extends Context>> SUPPORTED_CONTEXT_INTERFACES;
-
- static {
- SUPPORTED_CONTEXT_INTERFACES = new HashSet<Class<? extends Context>>();
- SUPPORTED_CONTEXT_INTERFACES.add(Context.class);
- SUPPORTED_CONTEXT_INTERFACES.add(DirContext.class);
- SUPPORTED_CONTEXT_INTERFACES.add(EventContext.class);
- SUPPORTED_CONTEXT_INTERFACES.add(EventDirContext.class);
- SUPPORTED_CONTEXT_INTERFACES.add(LdapContext.class);
- }
-
- private static final Set<InetAddress> SERVER_BIND_IPS;
- static {
- SERVER_BIND_IPS = new HashSet<InetAddress>();
-
- try {
- String bindingAddressString = System.getProperty("jboss.bind.address");
- InetAddress bindingAddress = InetAddress.getByName(bindingAddressString);
-
- if (bindingAddress.isAnyLocalAddress()) {
- Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
- while (ifaces.hasMoreElements()) {
- NetworkInterface iface = ifaces.nextElement();
- SERVER_BIND_IPS.addAll(Collections.list(iface.getInetAddresses()));
- }
- } else {
- SERVER_BIND_IPS.add(bindingAddress);
- }
- } catch (SocketException e) {
- LOG.error("Could not obtain the list of local IPs", e);
- } catch (UnknownHostException e) {
- LOG.error("Failed to get the binding address of the RHQ server.", e);
- }
- }
-
- private static final int JNP_PORT = Integer.parseInt(System.getProperty("rhq.server.startup.namingservice.port",
- "2099"));
-
- /**
- * This is the default initial context factory that is returned when no other is
- * configured using the environment variables.
- * <p>
- * It uses {@link NamingContextFactory} as the underlying mechanism - the same
- * as the default configuration in JBoss 4.
- */
- private static final InitialContextFactory DEFAULT_FACTORY = new InitialContextFactory() {
- public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
- return createSecureWrapper(new NamingContextFactory(), environment).getInitialContext(environment);
- }
- };
-
- /**
- * Create a InitialContext factory. If the environment does not override the factory class it will use the
- * default context factory.
- *
- * @param environment The environment
- * @return An initial context factory
- * @throws NamingException If an error occurs loading the factory class.
- */
- public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
- final String factoryClassName = (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
- if (factoryClassName == null) {
- return DEFAULT_FACTORY;
- }
- final ClassLoader classLoader = getContextClassLoader();
- try {
- final Class<?> factoryClass = Class.forName(factoryClassName, true, classLoader);
- InitialContextFactory configuredFactory = (InitialContextFactory) factoryClass.newInstance();
- return createSecureWrapper(configuredFactory, environment);
- } catch (Exception e) {
- throw new NamingException("Failed instantiate InitialContextFactory " + factoryClassName
- + " from classloader " + classLoader);
- }
- }
-
- private ClassLoader getContextClassLoader() {
- return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
- public ClassLoader run() {
- return Thread.currentThread().getContextClassLoader();
- }
- });
- }
-
- private static InitialContextFactory
- createSecureWrapper(InitialContextFactory factory, Hashtable<?, ?> environment) {
- String providerUrl = (String) environment.get(Context.PROVIDER_URL);
-
- if (providerUrl == null) {
- return getAccessCheckingFactory(factory);
- } else {
- try {
- URI uri = new URI(providerUrl);
- InetAddress providerHost = InetAddress.getByName(uri.getHost());
-
- //check if we are accessing the RHQ server through some remoting
- //interface.
- if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
- return getAccessCheckingFactory(factory);
- } else {
- return getURLPreferringFactory(factory);
- }
- } catch (URISyntaxException e) {
- return getAccessCheckingFactory(factory);
- } catch (UnknownHostException e) {
- //let the factory deal with the unknown host...
- //this most probably shouldn't be secured because localhost addresses
- //should be resolvable.
- return getURLPreferringFactory(factory);
- }
- }
- }
-
- private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
- pickers.add(getURLPreferringDecoratorPicker());
- pickers.add(getAccessCheckingDecoratorPicker());
-
- return new DecoratingInitialContextFactory(original, pickers);
- }
-
- private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
- pickers.add(getURLPreferringDecoratorPicker());
-
- return new DecoratingInitialContextFactory(original, pickers);
- }
-
- private static DecoratorPicker<Context, ContextDecorator> getAccessCheckingDecoratorPicker() {
- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
- ret.setContext(new AccessCheckingContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES, CHECKED_SCHEMES));
-
- return ret;
- }
-
- private static DecoratorPicker<Context, ContextDecorator> getURLPreferringDecoratorPicker() {
- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
- ret.setContext(new URLPreferringContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES));
-
- return ret;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej
new file mode 100644
index 0000000..445fa3a
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java.rej
@@ -0,0 +1,122 @@
+--- modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
++++ modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+@@ -27,7 +27,7 @@
+ import java.net.UnknownHostException;
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
+-import java.util.ArrayList;
++import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.Enumeration;
+ import java.util.HashSet;
+@@ -37,10 +37,6 @@
+ import javax.naming.Context;
+ import javax.naming.InitialContext;
+ import javax.naming.NamingException;
+-import javax.naming.directory.DirContext;
+-import javax.naming.event.EventContext;
+-import javax.naming.event.EventDirContext;
+-import javax.naming.ldap.LdapContext;
+ import javax.naming.spi.InitialContextFactory;
+ import javax.naming.spi.InitialContextFactoryBuilder;
+
+@@ -49,10 +45,16 @@
+ import org.jnp.interfaces.NamingContextFactory;
+
+ import org.rhq.jndi.context.AccessCheckingContextDecorator;
+-import org.rhq.jndi.context.AccessCheckingContextDecoratorSetContext;
+-import org.rhq.jndi.context.ContextDecorator;
+-import org.rhq.jndi.context.URLPreferringContextDecoratorSetContext;
+-import org.rhq.jndi.util.DecoratorPicker;
++import org.rhq.jndi.context.AccessCheckingDirContextDecorator;
++import org.rhq.jndi.context.AccessCheckingEventContextDecorator;
++import org.rhq.jndi.context.AccessCheckingEventDirContextDecorator;
++import org.rhq.jndi.context.AccessCheckingLdapContextDecorator;
++import org.rhq.jndi.context.ContextDecoratorPicker;
++import org.rhq.jndi.context.URLPreferringContextDecorator;
++import org.rhq.jndi.context.URLPreferringDirContextDecorator;
++import org.rhq.jndi.context.URLPreferringEventContextDecorator;
++import org.rhq.jndi.context.URLPreferringEventDirContextDecorator;
++import org.rhq.jndi.context.URLPreferringLdapContextDecorator;
+
+ /**
+ * This initial context factory builder is installed early on during the RHQ server startup
+@@ -87,17 +89,6 @@
+ */
+ private static final String[] CHECKED_SCHEMES = { "java" };
+
+- private static final Set<Class<? extends Context>> SUPPORTED_CONTEXT_INTERFACES;
+-
+- static {
+- SUPPORTED_CONTEXT_INTERFACES = new HashSet<Class<? extends Context>>();
+- SUPPORTED_CONTEXT_INTERFACES.add(Context.class);
+- SUPPORTED_CONTEXT_INTERFACES.add(DirContext.class);
+- SUPPORTED_CONTEXT_INTERFACES.add(EventContext.class);
+- SUPPORTED_CONTEXT_INTERFACES.add(EventDirContext.class);
+- SUPPORTED_CONTEXT_INTERFACES.add(LdapContext.class);
+- }
+-
+ private static final Set<InetAddress> SERVER_BIND_IPS;
+ static {
+ SERVER_BIND_IPS = new HashSet<InetAddress>();
+@@ -200,31 +191,42 @@
+ }
+
+ private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
+- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+- pickers.add(getURLPreferringDecoratorPicker());
+- pickers.add(getAccessCheckingDecoratorPicker());
+-
+- return new DecoratingInitialContextFactory(original, pickers);
++ return new DecoratingInitialContextFactory(original, Arrays.asList(
++ getURLPreferringDecoratorPicker(), getAccessCheckingDecoratorPicker()));
+ }
+-
++
+ private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
+- ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+- pickers.add(getURLPreferringDecoratorPicker());
+-
+- return new DecoratingInitialContextFactory(original, pickers);
++ return new DecoratingInitialContextFactory(original, Arrays.asList(
++ getURLPreferringDecoratorPicker()));
+ }
+
+- private static DecoratorPicker<Context, ContextDecorator> getAccessCheckingDecoratorPicker() {
+- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+- ret.setContext(new AccessCheckingContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES, CHECKED_SCHEMES));
+-
++ private static ContextDecoratorPicker getAccessCheckingDecoratorPicker() {
++ ContextDecoratorPicker ret = new ContextDecoratorPicker();
++
++ ret.setConstructorParameters(new Object[] { CHECKED_SCHEMES });
++ ret.setConstructorParameterTypes(new Class<?>[] { String[].class });
++
++ ret.getPossibleDecorators().add(AccessCheckingContextDecorator.class);
++ ret.getPossibleDecorators().add(AccessCheckingDirContextDecorator.class);
++ ret.getPossibleDecorators().add(AccessCheckingEventContextDecorator.class);
++ ret.getPossibleDecorators().add(AccessCheckingEventDirContextDecorator.class);
++ ret.getPossibleDecorators().add(AccessCheckingLdapContextDecorator.class);
++
+ return ret;
+ }
+
+- private static DecoratorPicker<Context, ContextDecorator> getURLPreferringDecoratorPicker() {
+- DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+- ret.setContext(new URLPreferringContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES));
+-
++ private static ContextDecoratorPicker getURLPreferringDecoratorPicker() {
++ ContextDecoratorPicker ret = new ContextDecoratorPicker();
++
++ ret.setConstructorParameters(null);
++ ret.setConstructorParameterTypes(null);
++
++ ret.getPossibleDecorators().add(URLPreferringContextDecorator.class);
++ ret.getPossibleDecorators().add(URLPreferringDirContextDecorator.class);
++ ret.getPossibleDecorators().add(URLPreferringEventContextDecorator.class);
++ ret.getPossibleDecorators().add(URLPreferringEventDirContextDecorator.class);
++ ret.getPossibleDecorators().add(URLPreferringLdapContextDecorator.class);
++
+ return ret;
+ }
+ }
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
deleted file mode 100644
index aa807d6..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.security.BasicPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AllowRhqServerInternalsAccessPermission extends BasicPermission {
-
- private static final long serialVersionUID = 1L;
-
- public AllowRhqServerInternalsAccessPermission() {
- super("org.rhq.allow.server.internals.access");
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
deleted file mode 100644
index 19b30ea..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.lang.reflect.Proxy;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Set;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
-
-import org.rhq.jndi.context.ContextDecorator;
-import org.rhq.jndi.util.DecoratorPicker;
-import org.rhq.jndi.util.DecoratingInvocationHandler;
-
-/**
- * This class implements an initial context factory that decorates the contexts
- * returned from a "wrapped" initial factory passed to this class in the constructor.
- * <p>
- * The contexts returned from the wrapped initial factory are hidden behind a proxy
- * that implements the intersection of interfaces from the <code>supportedContextInterfaces</code>
- * constructor parameter and the actual interfaces the wrapped context implements.
- * <p>
- * The proxy method calls are handled using the {@link DecoratingInvocationHandler} which is initialized
- * with the list of {@link DecoratorPicker pickers} that are used to intercept the method
- * calls on the wrapped context.
- *
- * @see DecoratorPicker
- * @see DecoratingInvocationHandler
- *
- * @author Lukas Krejci
- */
-public class DecoratingInitialContextFactory implements InitialContextFactory {
-
- List<DecoratorPicker<Context, ContextDecorator>> pickers;
- private InitialContextFactory factory;
- private Set<Class<? extends Context>> supportedContextInterfaces;
-
- public DecoratingInitialContextFactory(InitialContextFactory factory, List<DecoratorPicker<Context, ContextDecorator>> decoratorPickers) {
- this.factory = factory;
- this.pickers = decoratorPickers;
- this.supportedContextInterfaces = new HashSet<Class<? extends Context>>();
- for(DecoratorPicker<Context, ContextDecorator> picker : pickers) {
- supportedContextInterfaces.addAll(picker.getContext().getSupportedInterfaces());
- }
- }
-
- public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
- Context ctx = factory.getInitialContext(environment);
-
- Set<Class<?>> implementedIfaces = getAllImplementedInterfaces(ctx.getClass());
- Class<?>[] ii = new Class<?>[implementedIfaces.size()];
- implementedIfaces.toArray(ii);
-
- return (Context) Proxy.newProxyInstance(ctx.getClass().getClassLoader(), ii, new DecoratingInvocationHandler<Context, ContextDecorator>(pickers, ctx));
- }
-
- private Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
- HashSet<Class<?>> ret = new HashSet<Class<?>>();
- getAllImplementedInterfaces(cls, ret);
-
- ret.retainAll(supportedContextInterfaces);
-
- return ret;
- }
-
- private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
- Class<?>[] ifaces = cls.getInterfaces();
-
- for (Class<?> iface : Arrays.asList(ifaces)) {
- output.add(iface);
- getAllImplementedInterfaces(iface, output);
- }
-
- if (cls.getSuperclass() != null) {
- getAllImplementedInterfaces(cls.getSuperclass(), output);
- }
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
deleted file mode 100644
index 6bfec7e..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.naming.Binding;
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameParser;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-
-import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
-
-/**
- * This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
- * applied security checks in each method (lookups, (un)bindings, etc).
- * <p>
- * The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
- * <p>
- * This decorator applies the security check on any JNDI name without a scheme and
- * on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
- * in the constructor.
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingContextDecorator implements Context, ContextDecorator, Serializable {
-
- private static final long serialVersionUID = 1L;
-
- private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
- private Context original;
- private List<String> checkedSchemes;
-
- public AccessCheckingContextDecorator(String... checkedSchemes) {
- this.checkedSchemes = Arrays.asList(checkedSchemes);
- }
-
- public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
- this.original = original;
- this.checkedSchemes = Arrays.asList(checkedSchemes);
- }
-
- public void init(Context ctx) {
- this.original = ctx;
- }
-
- protected Context getOriginal() {
- return original;
- }
-
- protected static void check() {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) sm.checkPermission(PERM);
- }
-
- private void checkScheme(String scheme) {
- if (scheme == null || checkedSchemes.contains(scheme)) {
- check();
- }
- }
-
- protected void check(String name) {
- checkScheme(getURLScheme(name));
- }
-
- protected void check(Name name) {
- if (name.size() == 0) {
- check();
- } else {
- String first = name.get(0);
- checkScheme(getURLScheme(first));
- }
- }
-
- public Object lookup(Name name) throws NamingException {
- check(name);
- return original.lookup(name);
- }
-
- public Object lookup(String name) throws NamingException {
- check(name);
- return original.lookup(name);
- }
-
- public void bind(Name name, Object obj) throws NamingException {
- check(name);
- original.bind(name, obj);
- }
-
- public void bind(String name, Object obj) throws NamingException {
- check(name);
- original.bind(name, obj);
- }
-
- public void rebind(Name name, Object obj) throws NamingException {
- check(name);
- original.rebind(name, obj);
- }
-
- public void rebind(String name, Object obj) throws NamingException {
- check(name);
- original.rebind(name, obj);
- }
-
- public void unbind(Name name) throws NamingException {
- check(name);
- original.unbind(name);
- }
-
- public void unbind(String name) throws NamingException {
- check(name);
- original.unbind(name);
- }
-
- public void rename(Name oldName, Name newName) throws NamingException {
- check(oldName);
- check(newName);
- original.rename(oldName, newName);
- }
-
- public void rename(String oldName, String newName) throws NamingException {
- check(oldName);
- check(newName);
- original.rename(oldName, newName);
- }
-
- public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
- check(name);
- return original.list(name);
- }
-
- public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
- check(name);
- return original.list(name);
- }
-
- public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
- check(name);
- return original.listBindings(name);
- }
-
- public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
- check(name);
- return original.listBindings(name);
- }
-
- public void destroySubcontext(Name name) throws NamingException {
- check(name);
- original.destroySubcontext(name);
- }
-
- public void destroySubcontext(String name) throws NamingException {
- check(name);
- original.destroySubcontext(name);
- }
-
- public Context createSubcontext(Name name) throws NamingException {
- check(name);
- return original.createSubcontext(name);
- }
-
- public Context createSubcontext(String name) throws NamingException {
- check(name);
- return original.createSubcontext(name);
- }
-
- public Object lookupLink(Name name) throws NamingException {
- check(name);
- return original.lookupLink(name);
- }
-
- public Object lookupLink(String name) throws NamingException {
- check(name);
- return original.lookupLink(name);
- }
-
- public NameParser getNameParser(Name name) throws NamingException {
- check(name);
- return original.getNameParser(name);
- }
-
- public NameParser getNameParser(String name) throws NamingException {
- check(name);
- return original.getNameParser(name);
- }
-
- public Name composeName(Name name, Name prefix) throws NamingException {
- check(name);
- return original.composeName(name, prefix);
- }
-
- public String composeName(String name, String prefix) throws NamingException {
- check(name);
- return original.composeName(name, prefix);
- }
-
- public Object addToEnvironment(String propName, Object propVal) throws NamingException {
- check();
- return original.addToEnvironment(propName, propVal);
- }
-
- public Object removeFromEnvironment(String propName) throws NamingException {
- check();
- return original.removeFromEnvironment(propName);
- }
-
- public Hashtable<?, ?> getEnvironment() throws NamingException {
- check();
- return original.getEnvironment();
- }
-
- public void close() throws NamingException {
- check();
- original.close();
- }
-
- public String getNameInNamespace() throws NamingException {
- check();
- return original.getNameInNamespace();
- }
-
- //copied from InitialContext
- private static String getURLScheme(String str) {
- int colon_posn = str.indexOf(':');
- int slash_posn = str.indexOf('/');
-
- if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
- return str.substring(0, colon_posn);
- return null;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
deleted file mode 100644
index 284fd0c..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.lang.reflect.Constructor;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.naming.Context;
-
-import org.rhq.jndi.util.DecoratorSetContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
-
- private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
- static {
- HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
- tmp.add(AccessCheckingContextDecorator.class);
- tmp.add(AccessCheckingDirContextDecorator.class);
- tmp.add(AccessCheckingEventContextDecorator.class);
- tmp.add(AccessCheckingEventDirContextDecorator.class);
- tmp.add(AccessCheckingLdapContextDecorator.class);
-
- DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
- }
-
- private Set<Class<? extends Context>> supportedInterfaces;
- private String[] checkedSchemes;
-
- public AccessCheckingContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces, String... checkedSchemes) {
- this.supportedInterfaces = supportedInterfaces;
- this.checkedSchemes = checkedSchemes;
- }
-
- public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
- Constructor<? extends ContextDecorator> ctor = decoratorClass.getConstructor(String[].class);
-
- return ctor.newInstance((Object)checkedSchemes);
- }
-
- public Set<Class<? extends Context>> getSupportedInterfaces() {
- return supportedInterfaces;
- }
-
- public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
- return DECORATOR_CLASSES;
- }
-
- public void init(ContextDecorator decorator, Context object) throws Exception {
- decorator.init(object);
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
deleted file mode 100644
index 1614180..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Name;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-
-/**
- * A decorator of {@link DirContext}.
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingDirContextDecorator extends AccessCheckingContextDecorator implements DirContext {
-
- private static final long serialVersionUID = 1L;
-
- public AccessCheckingDirContextDecorator(String... checkedSchemes) {
- super(checkedSchemes);
- }
-
- public AccessCheckingDirContextDecorator(DirContext original, String... checkedSchemes) {
- super(original, checkedSchemes);
- }
-
- @Override
- protected DirContext getOriginal() {
- return (DirContext) super.getOriginal();
- }
-
- public Attributes getAttributes(Name name) throws NamingException {
- check(name);
- return getOriginal().getAttributes(name);
- }
-
- public Attributes getAttributes(String name) throws NamingException {
- check(name);
- return getOriginal().getAttributes(name);
- }
-
- public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
- check(name);
- return getOriginal().getAttributes(name, attrIds);
- }
-
- public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
- check(name);
- return getOriginal().getAttributes(name, attrIds);
- }
-
- public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().modifyAttributes(name, mod_op, attrs);
- }
-
- public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().modifyAttributes(name, mod_op, attrs);
- }
-
- public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
- check(name);
- getOriginal().modifyAttributes(name, mods);
- }
-
- public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
- check(name);
- getOriginal().modifyAttributes(name, mods);
- }
-
- public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().bind(name, obj, attrs);
- }
-
- public void bind(String name, Object obj, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().bind(name, obj, attrs);
- }
-
- public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().rebind(name, obj, attrs);
- }
-
- public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
- check(name);
- getOriginal().rebind(name, obj, attrs);
- }
-
- public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
- check(name);
- return getOriginal().createSubcontext(name, attrs);
- }
-
- public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
- check(name);
- return getOriginal().createSubcontext(name, attrs);
- }
-
- public DirContext getSchema(Name name) throws NamingException {
- check(name);
- return getOriginal().getSchema(name);
- }
-
- public DirContext getSchema(String name) throws NamingException {
- check(name);
- return getOriginal().getSchema(name);
- }
-
- public DirContext getSchemaClassDefinition(Name name) throws NamingException {
- check(name);
- return getOriginal().getSchemaClassDefinition(name);
- }
-
- public DirContext getSchemaClassDefinition(String name) throws NamingException {
- check(name);
- return getOriginal().getSchema(name);
- }
-
- public NamingEnumeration<SearchResult>
- search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
- check(name);
- return getOriginal().search(name, matchingAttributes, attributesToReturn);
- }
-
- public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
- String[] attributesToReturn) throws NamingException {
- check(name);
- return getOriginal().search(name, matchingAttributes, attributesToReturn);
- }
-
- public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
- check(name);
- return getOriginal().search(name, matchingAttributes);
- }
-
- public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
- check(name);
- return getOriginal().search(name, matchingAttributes);
- }
-
- public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
- check(name);
- return getOriginal().search(name, filter, cons);
- }
-
- public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
- throws NamingException {
- check(name);
- return getOriginal().search(name, filter, cons);
- }
-
- public NamingEnumeration<SearchResult>
- search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
- check(name);
- return getOriginal().search(name, filterExpr, filterArgs, cons);
- }
-
- public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
- SearchControls cons) throws NamingException {
- check(name);
- return getOriginal().search(name, filterExpr, filterArgs, cons);
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
deleted file mode 100644
index 67a9527..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.event.EventContext;
-import javax.naming.event.NamingListener;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingEventContextDecorator extends AccessCheckingContextDecorator implements EventContext {
-
- private static final long serialVersionUID = 1L;
-
- public AccessCheckingEventContextDecorator(String... checkedSchemes) {
- super(checkedSchemes);
- }
-
- public AccessCheckingEventContextDecorator(EventContext original, String... checkedSchemes) {
- super(original, checkedSchemes);
- }
-
- @Override
- protected EventContext getOriginal() {
- return (EventContext) super.getOriginal();
- }
-
- public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void removeNamingListener(NamingListener l) throws NamingException {
- check();
- getOriginal().removeNamingListener(l);
- }
-
- public boolean targetMustExist() throws NamingException {
- check();
- return getOriginal().targetMustExist();
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
deleted file mode 100644
index ed7a848..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.directory.SearchControls;
-import javax.naming.event.EventDirContext;
-import javax.naming.event.NamingListener;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingEventDirContextDecorator extends AccessCheckingDirContextDecorator implements
- EventDirContext {
-
- private static final long serialVersionUID = 1L;
-
- public AccessCheckingEventDirContextDecorator(String... checkedSchemes) {
- super(checkedSchemes);
- }
-
- public AccessCheckingEventDirContextDecorator(EventDirContext original, String... checkedSchemes) {
- super(original, checkedSchemes);
- }
-
- @Override
- protected EventDirContext getOriginal() {
- return (EventDirContext) super.getOriginal();
- }
-
- public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void removeNamingListener(NamingListener l) throws NamingException {
- check();
- getOriginal().removeNamingListener(l);
- }
-
- public boolean targetMustExist() throws NamingException {
- check();
- return getOriginal().targetMustExist();
- }
-
- public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
- throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, filter, ctls, l);
- }
-
- public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
- throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, filter, ctls, l);
- }
-
- public void
- addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
- throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
- }
-
- public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
- NamingListener l) throws NamingException {
- check(target);
- getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
deleted file mode 100644
index e361db8..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.NamingException;
-import javax.naming.ldap.Control;
-import javax.naming.ldap.ExtendedRequest;
-import javax.naming.ldap.ExtendedResponse;
-import javax.naming.ldap.LdapContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingLdapContextDecorator extends AccessCheckingDirContextDecorator implements LdapContext {
-
- private static final long serialVersionUID = 1L;
-
- public AccessCheckingLdapContextDecorator(String... checkedSchemes) {
- super(checkedSchemes);
- }
-
- public AccessCheckingLdapContextDecorator(LdapContext original, String... checkedSchemes) {
- super(original, checkedSchemes);
- }
-
- @Override
- protected LdapContext getOriginal() {
- return (LdapContext) super.getOriginal();
- }
-
- public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
- check();
- return getOriginal().extendedOperation(request);
- }
-
- public LdapContext newInstance(Control[] requestControls) throws NamingException {
- check();
- return getOriginal().newInstance(requestControls);
- }
-
- public void reconnect(Control[] connCtls) throws NamingException {
- check();
- getOriginal().reconnect(connCtls);
- }
-
- public Control[] getConnectControls() throws NamingException {
- check();
- return getOriginal().getConnectControls();
- }
-
- public void setRequestControls(Control[] requestControls) throws NamingException {
- check();
- getOriginal().setRequestControls(requestControls);
- }
-
- public Control[] getRequestControls() throws NamingException {
- check();
- return getOriginal().getRequestControls();
- }
-
- public Control[] getResponseControls() throws NamingException {
- check();
- return getOriginal().getResponseControls();
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
deleted file mode 100644
index 5755ebd..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public interface ContextDecorator extends Context {
-
- void init(Context context) throws NamingException;
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
deleted file mode 100644
index 20077de..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.io.Serializable;
-import java.util.Hashtable;
-
-import javax.naming.Binding;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameParser;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-
-import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
-
-/**
- * This is a wrapper class around another {@link Context} implementation that
- * prefers to use an URL context for some operation if the JNDI name contains
- * a scheme rather than the original. This is the behavior of {@link InitialContext}
- * which we need to restore in the contexts created by the {@link AccessCheckingInitialContextFactoryBuilder}
- * (which an {@link InitialContext} uses exclusively if the builder is set).
- * <p>
- * This is important because RHQ server has its own initial context factory
- * builder that creates factories that in turn create contexts. If the default
- * {@link InitialContext} implementation was used, we'd never be able to lookup
- * scheme-based names because the default implementation of the {@link InitialContext}
- * always uses the default context of the builder if one is installed no matter
- * the scheme in the name.
- * <p>
- * The {@link AccessCheckingInitialContextFactoryBuilder} wraps the context returned
- * by the factory in an instance of this class and thus is restoring the original
- * intended behavior of the {@link InitialContext}. It looks at the name being looked
- * up (bound or whatever) and prefers to use the URL context factories if the name
- * contains the scheme (as does the {@link InitialContext} if no builder is installed).
- * If the name doesn't contain a scheme, the provided default context factory is used to
- * look up the name.
- *
- * @author Lukas Krejci
- */
-public class URLPreferringContextDecorator implements Context, ContextDecorator, Serializable {
-
- private static final long serialVersionUID = 1L;
-
- private Context original;
-
- public URLPreferringContextDecorator() {
-
- }
-
- public URLPreferringContextDecorator(Context ctx) {
- original = ctx;
- }
-
- public void init(Context context) {
- original = context;
- }
-
- protected Context getOriginal() throws NamingException {
- return original;
- }
-
- protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
- @SuppressWarnings("unchecked")
- Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
- return urlContext == null ? getOriginal() : urlContext;
- }
-
- protected Context getURLOrDefaultInitCtx(String name) throws NamingException {
- @SuppressWarnings("unchecked")
- Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
- return urlContext == null ? getOriginal() : urlContext;
- }
-
- public Object lookup(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).lookup(name);
- }
-
- public Object lookup(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).lookup(name);
- }
-
- public void bind(Name name, Object obj) throws NamingException {
- getURLOrDefaultInitCtx(name).bind(name, obj);
- }
-
- public void bind(String name, Object obj) throws NamingException {
- getURLOrDefaultInitCtx(name).bind(name, obj);
- }
-
- public void rebind(Name name, Object obj) throws NamingException {
- getURLOrDefaultInitCtx(name).rebind(name, obj);
- }
-
- public void rebind(String name, Object obj) throws NamingException {
- getURLOrDefaultInitCtx(name).rebind(name, obj);
- }
-
- public void unbind(Name name) throws NamingException {
- getURLOrDefaultInitCtx(name).unbind(name);
- }
-
- public void unbind(String name) throws NamingException {
- getURLOrDefaultInitCtx(name).unbind(name);
- }
-
- public void rename(Name oldName, Name newName) throws NamingException {
- getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
- }
-
- public void rename(String oldName, String newName) throws NamingException {
- getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
- }
-
- public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).list(name);
- }
-
- public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).list(name);
- }
-
- public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).listBindings(name);
- }
-
- public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).listBindings(name);
- }
-
- public void destroySubcontext(Name name) throws NamingException {
- getURLOrDefaultInitCtx(name).destroySubcontext(name);
- }
-
- public void destroySubcontext(String name) throws NamingException {
- getURLOrDefaultInitCtx(name).destroySubcontext(name);
- }
-
- public Context createSubcontext(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).createSubcontext(name);
- }
-
- public Context createSubcontext(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).createSubcontext(name);
- }
-
- public Object lookupLink(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).lookupLink(name);
- }
-
- public Object lookupLink(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).lookupLink(name);
- }
-
- public NameParser getNameParser(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getNameParser(name);
- }
-
- public NameParser getNameParser(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getNameParser(name);
- }
-
- public Name composeName(Name name, Name prefix) throws NamingException {
- return getOriginal().composeName(name, prefix);
- }
-
- public String composeName(String name, String prefix) throws NamingException {
- return getOriginal().composeName(name, prefix);
- }
-
- public Object addToEnvironment(String propName, Object propVal) throws NamingException {
- return getOriginal().addToEnvironment(propName, propVal);
- }
-
- public Object removeFromEnvironment(String propName) throws NamingException {
- return getOriginal().removeFromEnvironment(propName);
- }
-
- public Hashtable<?, ?> getEnvironment() throws NamingException {
- return getOriginal().getEnvironment();
- }
-
- public void close() throws NamingException {
- if (getOriginal() != null) {
- getOriginal().close();
- original = null;
- }
- }
-
- public String getNameInNamespace() throws NamingException {
- return getOriginal().getNameInNamespace();
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
deleted file mode 100644
index 6e7debc..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.spi.NamingManager;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class URLPreferringContextDecoratorHelper {
-
- private URLPreferringContextDecoratorHelper() {
-
- }
-
- public static Context getURLContext(String name, Hashtable<Object, Object> env) throws NamingException {
- String scheme = getURLScheme(name);
- if (scheme != null) {
- Context ctx = NamingManager.getURLContext(scheme, env);
- if (ctx != null) {
- return ctx;
- }
- }
-
- return null;
- }
-
- public static Context getURLContext(Name name, Hashtable<Object, Object> env) throws NamingException {
- if (name.size() > 0) {
- String first = name.get(0);
- String scheme = getURLScheme(first);
- if (scheme != null) {
- Context ctx = NamingManager.getURLContext(scheme, env);
- if (ctx != null) {
- return ctx;
- }
- }
- }
-
- return null;
- }
-
- //copied from InitialContext
- private static String getURLScheme(String str) {
- int colon_posn = str.indexOf(':');
- int slash_posn = str.indexOf('/');
-
- if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
- return str.substring(0, colon_posn);
- return null;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
deleted file mode 100644
index 828cd74..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.naming.Context;
-
-import org.rhq.jndi.util.DecoratorSetContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class URLPreferringContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
-
- private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
- static {
- HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
- tmp.add(URLPreferringContextDecorator.class);
- tmp.add(URLPreferringDirContextDecorator.class);
- tmp.add(URLPreferringEventContextDecorator.class);
- tmp.add(URLPreferringEventDirContextDecorator.class);
- tmp.add(URLPreferringLdapContextDecorator.class);
-
- DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
- }
-
- private Set<Class<? extends Context>> supportedInterfaces;
-
- public URLPreferringContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces) {
- this.supportedInterfaces = supportedInterfaces;
- }
-
- public Set<Class<? extends Context>> getSupportedInterfaces() {
- return supportedInterfaces;
- }
-
- public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
- return DECORATOR_CLASSES;
- }
-
- public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
- return decoratorClass.newInstance();
- }
-
- public void init(ContextDecorator decorator, Context object) throws Exception {
- decorator.init(object);
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
deleted file mode 100644
index 6a49942..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.NotContextException;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.ModificationItem;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-
-/**
- * Akin to {@link URLPreferringContextDecorator} this class implements the similar logic
- * for {@link DirContext}s.
- *
- * @author Lukas Krejci
- */
-public class URLPreferringDirContextDecorator extends URLPreferringContextDecorator implements DirContext {
-
- private static final long serialVersionUID = 1L;
-
- public URLPreferringDirContextDecorator() {
- super(null);
- }
-
- public URLPreferringDirContextDecorator(DirContext ctx) {
- super(ctx);
- }
-
- protected DirContext checkAndCast(Context ctx) throws NamingException {
- if (!(ctx instanceof DirContext)) {
- if (ctx == null) {
- throw new NoInitialContextException();
- } else {
- throw new NotContextException(
- "Not an instance of DirContext");
- }
- }
-
- return (DirContext) ctx;
- }
-
- @Override
- protected DirContext getURLOrDefaultInitCtx(Name name) throws NamingException {
- Context ctx = super.getURLOrDefaultInitCtx(name);
- return checkAndCast(ctx);
- }
-
- @Override
- protected DirContext getURLOrDefaultInitCtx(String name) throws NamingException {
- Context ctx = super.getURLOrDefaultInitCtx(name);
- return checkAndCast(ctx);
- }
-
- public Attributes getAttributes(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getAttributes(name);
- }
-
- public Attributes getAttributes(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getAttributes(name);
- }
-
- public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
- return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
- }
-
- public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
- return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
- }
-
- public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
- }
-
- public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
- }
-
- public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
- getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
- }
-
- public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
- getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
- }
-
- public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
- }
-
- public void bind(String name, Object obj, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
- }
-
- public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
- }
-
- public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
- getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
- }
-
- public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
- return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
- }
-
- public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
- return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
- }
-
- public DirContext getSchema(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getSchema(name);
- }
-
- public DirContext getSchema(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getSchema(name);
- }
-
- public DirContext getSchemaClassDefinition(Name name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
- }
-
- public DirContext getSchemaClassDefinition(String name) throws NamingException {
- return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
- }
-
- public NamingEnumeration<SearchResult>
- search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
- }
-
- public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
- String[] attributesToReturn) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
- }
-
- public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
- }
-
- public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
- }
-
- public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, filter, cons);
- }
-
- public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
- throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, filter, cons);
- }
-
- public NamingEnumeration<SearchResult>
- search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
- }
-
- public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
- SearchControls cons) throws NamingException {
- return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
deleted file mode 100644
index e3298a0..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.NotContextException;
-import javax.naming.event.EventContext;
-import javax.naming.event.NamingListener;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class URLPreferringEventContextDecorator extends URLPreferringContextDecorator implements EventContext {
-
- private static final long serialVersionUID = 1L;
-
- public URLPreferringEventContextDecorator() {
- super(null);
- }
-
- public URLPreferringEventContextDecorator(EventContext ctx) {
- super(ctx);
- }
-
- protected EventContext checkAndCast(Context ctx) throws NamingException {
- if (!(ctx instanceof EventContext)) {
- if (ctx == null) {
- throw new NoInitialContextException();
- } else {
- throw new NotContextException(
- "Not an instance of EventContext");
- }
- }
-
- return (EventContext) ctx;
- }
-
- @Override
- protected EventContext getOriginal() throws NamingException {
- return checkAndCast(super.getOriginal());
- }
-
- public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void removeNamingListener(NamingListener l) throws NamingException {
- getOriginal().removeNamingListener(l);
- }
-
- public boolean targetMustExist() throws NamingException {
- return getOriginal().targetMustExist();
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
deleted file mode 100644
index 4925297..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.NotContextException;
-import javax.naming.directory.SearchControls;
-import javax.naming.event.EventDirContext;
-import javax.naming.event.NamingListener;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class URLPreferringEventDirContextDecorator extends URLPreferringDirContextDecorator implements EventDirContext {
-
- private static final long serialVersionUID = 1L;
-
- public URLPreferringEventDirContextDecorator() {
- super(null);
- }
-
- public URLPreferringEventDirContextDecorator(EventDirContext ctx) {
- super(ctx);
- }
-
- @Override
- protected EventDirContext checkAndCast(Context ctx) throws NamingException {
- if (!(ctx instanceof EventDirContext)) {
- if (ctx == null) {
- throw new NoInitialContextException();
- } else {
- throw new NotContextException(
- "Not an instance of EventDirContext");
- }
- }
-
- return (EventDirContext) ctx;
- }
-
- @Override
- protected EventDirContext getOriginal() throws NamingException {
- return checkAndCast(super.getOriginal());
- }
-
- public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
- getOriginal().addNamingListener(target, scope, l);
- }
-
- public void removeNamingListener(NamingListener l) throws NamingException {
- getOriginal().removeNamingListener(l);
- }
-
- public boolean targetMustExist() throws NamingException {
- return getOriginal().targetMustExist();
- }
-
- public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
- throws NamingException {
- getOriginal().addNamingListener(target, filter, ctls, l);
- }
-
- public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
- throws NamingException {
- getOriginal().addNamingListener(target, filter, ctls, l);
- }
-
- public void
- addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
- throws NamingException {
- getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
- }
-
- public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
- NamingListener l) throws NamingException {
- getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
deleted file mode 100644
index c74df39..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.NotContextException;
-import javax.naming.ldap.Control;
-import javax.naming.ldap.ExtendedRequest;
-import javax.naming.ldap.ExtendedResponse;
-import javax.naming.ldap.LdapContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class URLPreferringLdapContextDecorator extends URLPreferringDirContextDecorator implements LdapContext {
-
- private static final long serialVersionUID = 1L;
-
- public URLPreferringLdapContextDecorator() {
- super(null);
- }
-
- public URLPreferringLdapContextDecorator(LdapContext original) {
- super(original);
- }
-
- @Override
- protected LdapContext checkAndCast(Context ctx) throws NamingException {
- if (!(ctx instanceof LdapContext)) {
- if (ctx == null) {
- throw new NoInitialContextException();
- } else {
- throw new NotContextException("Not an instance of LdapContext");
- }
- }
-
- return (LdapContext) ctx;
- }
-
- @Override
- protected LdapContext getOriginal() throws NamingException {
- return checkAndCast(super.getOriginal());
- }
-
- public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
- return getOriginal().extendedOperation(request);
- }
-
- public LdapContext newInstance(Control[] requestControls) throws NamingException {
- return new URLPreferringLdapContextDecorator(getOriginal().newInstance(requestControls));
- }
-
- public void reconnect(Control[] connCtls) throws NamingException {
- getOriginal().reconnect(connCtls);
- }
-
- public Control[] getConnectControls() throws NamingException {
- return getOriginal().getConnectControls();
- }
-
- public void setRequestControls(Control[] requestControls) throws NamingException {
- getOriginal().setRequestControls(requestControls);
- }
-
- public Control[] getRequestControls() throws NamingException {
- return getOriginal().getRequestControls();
- }
-
- public Control[] getResponseControls() throws NamingException {
- return getOriginal().getResponseControls();
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
deleted file mode 100644
index d938c50..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.mbean;
-
-import javax.naming.spi.NamingManager;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingInitialContextFactoryBuilderInstaller implements AccessCheckingInitialContextFactoryBuilderInstallerMBean {
- private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
-
- public void start() throws Exception {
- LOG.info("Installing RHQ's access permission checking initial context factory builder");
-
- NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
- }
-
- public void stop() throws Exception {
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
deleted file mode 100644
index 87d19ab..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.mbean;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public interface AccessCheckingInitialContextFactoryBuilderInstallerMBean {
-
- void start() throws Exception;
-
- void stop() throws Exception;
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
deleted file mode 100644
index 356a6e9..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.util;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.util.List;
-
-public class DecoratingInvocationHandler<Type, Decorator extends Type> implements InvocationHandler {
-
- private final List<DecoratorPicker<Type, Decorator>> pickers;
- private Type object;
-
- public DecoratingInvocationHandler(List<DecoratorPicker<Type, Decorator>> pickers, Type object) {
- this.pickers = pickers;
- this.object = object;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Type target = object;
- Class<?> methodClass = method.getDeclaringClass();
-
- for(DecoratorPicker<Type, Decorator> picker : pickers) {
- target = picker.decorate(target, methodClass);
- }
-
- return method.invoke(target, args);
- }
-}
\ No newline at end of file
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
deleted file mode 100644
index 017d29f..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.util;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Given as set of decorators extending given type, this class can pick
- * the most appropriate set of decorators for a class or a method call.
- * <p>
- * To configure the decorator, one has to provide a {@link DecoratorSetContext} that
- * is then used to obtain the list of
- * {@link DecoratorSetContext#getSupportedInterfaces() supported interfaces}, which are
- * all the interfaces that should be used for decorator resolution (i.e. all other interfaces
- * that a class might implement are ignored during decorator resolution), the list of
- * {@link DecoratorSetContext#getDecoratorClasses() decorator classes}, which is a list
- * of decorators the picker can choose from and is also used to instantiate and initialize
- * the decorators.
- *
- * @author Lukas Krejci
- */
-public class DecoratorPicker<Type, Decorator extends Type> {
-
- private DecoratorSetContext<Type, Decorator> context;
-
- public DecoratorSetContext<Type, Decorator> getContext() {
- return context;
- }
-
- public void setContext(DecoratorSetContext<Type, Decorator> decoratorSetContext) {
- this.context = decoratorSetContext;
- }
-
- /**
- * Returns a set of decorators applicable for given method. The set is established based
- * on the declaring class of the method.
- *
- * @param method the method to inspect
- * @return the set of decorators that can be used to wrap a method call
- * @throws Exception
- */
- public Set<Decorator> getDecoratorsForMethod(Method method) throws Exception {
- return getDecoratorsForClass_Private(method.getDeclaringClass());
- }
-
- /**
- * Returns a set of decorators that can be used on instances of given class.
- * @param cls the class to inspect
- * @return
- * @throws Exception
- */
- public Set<Decorator> getDecoratorsForClass(Class<? extends Type> cls) throws Exception {
- return getDecoratorsForClass_Private(cls);
- }
-
- /**
- * This method first establishes the set of decorators to use based on the class of the supplied
- * object and then chains the decorators (in arbitrary order) with the supplied object at the
- * "root" of the chain.
- * <p>
- * If a method is then called on the returned object, the methods of all the decorators are called
- * in chain (each supposedly calling the next) and finally, at the end of the chain, the method on
- * the original object (the one supplied to this method) is called.
- * <p>
- * Note that the above is only an intended behavior and actually depends on the implementation of
- * the decorators that are resposinble for the chaining. Each decorator is initialized
- * (@{link {@link DecoratorSetContext#init(Object, Object)} which should set it up for such chaining.
- *
- * @param object
- * @return
- * @throws Exception
- */
- public Type decorate(Type object) throws Exception {
- Set<Decorator> decs = getDecoratorsForClass_Private(object.getClass());
- Type ret = object;
- for(Decorator d : decs) {
- context.init(d, ret);
- ret = d;
- }
-
- return ret;
- }
-
- /**
- * Similar to {@link #decorate(Object)} but instead of the class of the object itself,
- * uses the significantSuperClass as the basis for the decorator resolution.
- * <p>
- * This is important, because if the object implements two mutually incompatible sub-interfaces of <code>Type</code>,
- * the chained decorators might fail to execute a method later on if the decorator depends on the upper part
- * of the chain to implement certain sub-interface of <code>Type</code>.
- *
- * @param object the object to wrap in decorators
- * @param significantSuperClass the class to base the decorator resolution on
- * @return
- * @throws Exception
- */
- public Type decorate(Type object, Class<?> significantSuperClass) throws Exception {
- Set<Decorator> decs = getDecoratorsForClass_Private(significantSuperClass);
- Type ret = object;
- for(Decorator d : decs) {
- context.init(d, ret);
- ret = d;
- }
-
- return ret;
- }
-
- private Set<Decorator> getDecoratorsForClass_Private(Class<?> cls) throws Exception {
- Set<Class<? extends Type>> ifaces = getNearestApplicableInterfaces(cls);
-
- HashSet<Decorator> ret = new HashSet<Decorator>();
-
- for (Class<? extends Type> iface : ifaces) {
- for (Class<? extends Decorator> decClass : getMatch(iface)) {
- ret.add(context.instantiate(decClass));
- }
- }
-
- return ret;
- }
-
- private Set<Class<? extends Type>> getNearestApplicableInterfaces(Class<?> cls) {
- List<Class<? extends Type>> ifaces = new ArrayList<Class<? extends Type>>(getAllApplicableInterfaces(cls));
-
- //now compact the set to only contain the most concrete interfaces
-
- Iterator<Class<? extends Type>> it = ifaces.iterator();
- while (it.hasNext()) {
- Class<? extends Type> c = it.next();
-
- for (int i = 0; i < ifaces.size(); ++i) {
- Class<? extends Type> nextC = ifaces.get(i);
- if (!c.equals(nextC) && c.isAssignableFrom(nextC)) {
- it.remove();
- break;
- }
- }
- }
-
- return new HashSet<Class<? extends Type>>(ifaces);
- }
-
- private Set<Class<? extends Type>> getAllApplicableInterfaces(Class<?> cls) {
- Set<Class<? extends Type>> ifaces = new HashSet<Class<? extends Type>>();
-
- for (Class<? extends Type> iface : context.getSupportedInterfaces()) {
- if (iface.isAssignableFrom(cls)) {
- ifaces.add(iface);
- }
- }
-
- if (ifaces.isEmpty()) {
- throw new IllegalArgumentException("Class " + cls
- + " doesn't implement any of the applicable interfaces. Cannot find decorators for it.");
- }
-
- return ifaces;
- }
-
- private Set<Class<? extends Decorator>> getMatch(Class<?> targetIface) {
-
- Set<Class<? extends Decorator>> ret = new HashSet<Class<? extends Decorator>>();
-
- for (Class<? extends Decorator> cls : context.getDecoratorClasses()) {
- if (Arrays.asList(cls.getInterfaces()).contains(targetIface)) {
- ret.add(cls);
- }
- }
-
- return ret;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
deleted file mode 100644
index d7b1676..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.util;
-
-import java.util.Set;
-
-/**
- * Implementations of this interface provide a context to the {@link DecoratorPicker}.
- *
- * @author Lukas Krejci
- */
-public interface DecoratorSetContext<Type, Decorator> {
-
- /**
- * @return the set of interfaces that the decorators are able support.
- * Usually this should be just a union of all interfaces the decorators implement
- * but can be trimmed down.
- */
- Set<Class<? extends Type>> getSupportedInterfaces();
-
- /**
- * @return the set of all decorator classes in this set
- */
- Set<Class<? extends Decorator>> getDecoratorClasses();
-
- /**
- * Instantiates a new decorator of given class.
- * @param decoratorClass
- * @return
- * @throws Exception
- */
- Decorator instantiate(Class<? extends Decorator> decoratorClass) throws Exception;
-
- /**
- * Initializes the decorator to decorate given object.
- *
- * @param decorator
- * @param object
- * @throws Exception on error
- */
- void init(Decorator decorator, Type object) throws Exception;
-}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
deleted file mode 100644
index 45ba114..0000000
--- a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.Set;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.naming.event.EventContext;
-import javax.naming.event.NamingListener;
-import javax.naming.spi.InitialContextFactory;
-import javax.naming.spi.NamingManager;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-@Test
-public class DecoratingInvocationHandlerTest {
- private static final Set<String> INVOKED_METHODS = new HashSet<String>();
-
- private static final InvocationHandler NOTE_TAKING_HANDLER = new InvocationHandler() {
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- INVOKED_METHODS.add(method.getName());
-
- if ("hashCode".equals(method.getName())) {
- return 0;
- } else if ("equals".equals(method.getName())) {
- return false;
- }
-
- return null;
- }
- };
-
- private static Class<?>[] CONTEXT_INTERFACES;
-
- public static class Factory implements InitialContextFactory {
- public Context getInitialContext(Hashtable<?, ?> environment)
- throws NamingException {
-
- return (Context) Proxy.newProxyInstance(DecoratingInvocationHandlerTest.class.getClassLoader(), CONTEXT_INTERFACES, NOTE_TAKING_HANDLER);
- }
- }
-
- private static class DummyInitialEventContext extends InitialContext implements EventContext {
-
- /**
- * @param environment
- * @throws NamingException
- */
- public DummyInitialEventContext(Hashtable<?, ?> environment) throws NamingException {
- super(environment);
- }
-
- public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
- ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
- }
-
- public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
- ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
- }
-
- public void removeNamingListener(NamingListener l) throws NamingException {
- ((EventContext)getDefaultInitCtx()).removeNamingListener(l);
- }
-
- public boolean targetMustExist() throws NamingException {
- return ((EventContext)getDefaultInitCtx()).targetMustExist();
- }
-
-
- }
-
- @BeforeClass
- public void setBuilder() throws Exception {
- NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
- }
-
- public void testSimpleDispatch() throws Exception {
- INVOKED_METHODS.clear();
- Properties env = new Properties();
- env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
-
- CONTEXT_INTERFACES = new Class<?>[] { Context.class };
-
- InitialContext ctx = new InitialContext(env);
-
- ctx.lookup("asdf");
-
- assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
- }
-
- public void testMultiInterfaceDispatch() throws Exception {
- INVOKED_METHODS.clear();
- Properties env = new Properties();
- env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
-
- CONTEXT_INTERFACES = new Class<?>[] { EventContext.class, DirContext.class };
-
- InitialContext ctx = new InitialContext(env);
-
- ctx.lookup("asdf");
-
- DummyInitialEventContext ectx = new DummyInitialEventContext(env);
-
- ectx.addNamingListener("hodiny", 0, null);
-
- assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
- assert INVOKED_METHODS.contains("addNamingListener") : "The addNamingListener doesn't seem to have propagated to the actual context to be used.";
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
deleted file mode 100644
index e2d7429..0000000
--- a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.naming.Context;
-import javax.naming.directory.DirContext;
-import javax.naming.event.EventContext;
-import javax.naming.ldap.LdapContext;
-
-import org.testng.annotations.Test;
-
-import org.rhq.jndi.util.DecoratorPicker;
-import org.rhq.jndi.util.DecoratorSetContext;
-
-/**
- * @author Lukas Krejci
- */
-@Test
-public class DecoratorPickerTest {
-
- private static final InvocationHandler DUMMY_HANDLER = new InvocationHandler() {
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if ("hashCode".equals(method.getName())) {
- return 0;
- } else if ("equals".equals(method.getName())) {
- return false;
- }
-
- return null;
- }
- };
-
- private static final Class<?> TEST_OBJECT_CLASS1 = createProxyClass(Context.class);
- private static final Class<?> TEST_OBJECT_CLASS2 = createProxyClass(DirContext.class);
- private static final Class<?> TEST_OBJECT_CLASS3 = createProxyClass(LdapContext.class);
- private static final Class<?> TEST_OBJECT_CLASS4 = createProxyClass(LdapContext.class, EventContext.class);
- private static final Class<?> DECORATOR_CLASS1 = createProxyClass(Context.class);
- private static final Class<?> DECORATOR_CLASS2 = createProxyClass(EventContext.class);
- private static final Class<?> DECORATOR_CLASS3 = createProxyClass(LdapContext.class);
- private static final Class<?> DECORATOR_CLASS4 = createProxyClass(DirContext.class);
-
- public void testSimpleDecoratorIdentifiedByClass() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS1);
- assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for Context class");
- assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], Context.class);
- }
-
- public void testSuperClassDecoratorHasPrecedenceOverSubClassDecorator() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- //this tests that the LdapContext isn't returned even though it subclasses the DirContext
- Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS2);
- assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for DirContext class");
- assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], DirContext.class);
- }
-
- public void testSubClassDecoratorCorrectlyIdentified() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS3);
- assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for LdapContext class");
- assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
- }
-
- public void testMultipleDecoratorsDetectable() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- Set<Object> decorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS4);
- assertEquals(decorators.size(), 2,
- "Exactly 2 decorators should have been found for a class implementing 2 interfaces.");
-
- boolean ldapContextDecoratorFound = false;
- boolean eventContextDecoratorFound = false;
-
- for (Object d : decorators) {
- if (LdapContext.class.isAssignableFrom(d.getClass())) {
- ldapContextDecoratorFound = true;
- continue; //just to make sure that somehow the decorator doesn't implement both
- }
- if (EventContext.class.isAssignableFrom(d.getClass())) {
- eventContextDecoratorFound = true;
- }
- }
-
- assertTrue(ldapContextDecoratorFound && eventContextDecoratorFound,
- "The found decorators don't implement the desired interfaces.");
- }
-
- public void testDecoratorsIdentifiedByMethod() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- Set<Object> decorators =
- picker.getDecoratorsForMethod(LdapContext.class.getMethod("getConnectControls", (Class<?>[]) null));
- assertEquals(decorators.size(), 1,
- "Expected exactly one decorator for method 'getConnectControls()' from LdapContext class");
- assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
- }
-
- public void testMethodFromSubclassMatchesSubclassDecorator() throws Exception {
- DecoratorPicker<Object, Object> picker = createTestPicker();
-
- //this is a method from the DirContext but we're asking for it from a class
- //that implements also an LdapContext
- //The LdapContext decorator also inherits from the DirContext decorator
- //(by the virtue of LdapContext interface inheriting from the DirContext)
- //The picker should therefore match the LdapContext decorator because its
- //the "closest" one to the actual class.
- Set<Object> decorators =
- picker.getDecoratorsForMethod(TEST_OBJECT_CLASS3.getMethod("getSchemaClassDefinition",
- new Class<?>[] { String.class }));
- assertEquals(decorators.size(), 1,
- "Expected exactly one decorator for method 'getSchemaClassDefinition(String)' from LdapContext class");
- assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
- }
-
- private static Class<?> createProxyClass(Class<?>... ifaces) {
- return Proxy.getProxyClass(DecoratorPickerTest.class.getClassLoader(), ifaces);
- }
-
- private static DecoratorPicker<Object, Object> createTestPicker() {
- DecoratorPicker<Object, Object> picker = new DecoratorPicker<Object, Object>();
-
- DecoratorSetContext<Object, Object> decSet = new DecoratorSetContext<Object, Object>() {
-
- public Object instantiate(Class<? extends Object> decoratorClass) throws Exception {
- Constructor<? extends Object> ctor = decoratorClass.getConstructor(InvocationHandler.class);
- return ctor.newInstance(DUMMY_HANDLER);
- }
-
- public void init(Object decorator, Object object) throws Exception {
- }
-
- @SuppressWarnings("unchecked")
- public Set<Class<? extends Object>> getSupportedInterfaces() {
- return new HashSet<Class<? extends Object>>(Arrays.asList(Context.class, EventContext.class,
- LdapContext.class, DirContext.class));
- }
-
- @SuppressWarnings("unchecked")
- public Set<Class<? extends Object>> getDecoratorClasses() {
- return new HashSet<Class<? extends Object>>(Arrays.asList(DECORATOR_CLASS1, DECORATOR_CLASS2, DECORATOR_CLASS3, DECORATOR_CLASS4));
- }
- };
-
- picker.setContext(decSet);
-
- return picker;
- }
-}
diff --git a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
index f231f15..859b552 100644
--- a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
+++ b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
@@ -225,13 +225,6 @@
<!-- JNDI -->
<!-- ==================================================================== -->
- <!-- This installs a custom initial context factory builder into the JVM
- that will ensure that all the default InitialContexts are going to check
- for the permission to access the RHQ internals. -->
- <mbean code="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
- name="org.rhq:service=AccessCheckingInitialContextFactoryBuilderInstaller">
- </mbean>
-
<!-- A simple mbean wrapper around the jndi Naming object. This
only handles an in memory instance. The NamingService uses this
as the JNDI store and exposes it remotely.
diff --git a/modules/enterprise/server/itests/pom.xml b/modules/enterprise/server/itests/pom.xml
index 6898621..8753e6f 100644
--- a/modules/enterprise/server/itests/pom.xml
+++ b/modules/enterprise/server/itests/pom.xml
@@ -56,12 +56,6 @@
<dependency>
<groupId>org.rhq</groupId>
- <artifactId>rhq-container-lib</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
<artifactId>rhq-enterprise-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
diff --git a/modules/enterprise/server/jar/pom.xml b/modules/enterprise/server/jar/pom.xml
index 92f4cf1..6eaf304 100644
--- a/modules/enterprise/server/jar/pom.xml
+++ b/modules/enterprise/server/jar/pom.xml
@@ -78,13 +78,6 @@
<version>${project.version}</version>
</dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-container-lib</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
-
<dependency>
<groupId>com.googlecode.java-diff-utils</groupId>
<artifactId>diffutils</artifactId>
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
index ecf2f6f..39b6076 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
@@ -26,41 +26,29 @@ import java.util.Random;
import org.rhq.core.domain.auth.Subject;
import org.rhq.enterprise.server.util.LookupUtil;
-import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
/**
* This is the JON Server's own session ID generator. It is outside any container-provided session mechanism. Its sole
* purpose is to provide session IDs to logged in {@link Subject}s. It will timeout those sessions regardless of any
* container-provided session-timeout mechanism.
- * <p>
- * Because this is a very security-sensitive class, any public method requires the caller to
- * have the {@link AllowEjbAccessPermission} as any other calls to the EJB layer. This is so that the
- * malicious users can't trick the EJB layer into thinking that some users are logged in or log out other
- * users.
- * <p>
- * Also, for security reasons, this class is final so that malicious code can't subclass it and modify its
- * behavior.
- *
+ *
* <p>This object is a {@link #getInstance() singleton}.</p>
*/
-public final class SessionManager {
-
- private static final AllowRhqServerInternalsAccessPermission ACCESS_PERMISSION = new AllowRhqServerInternalsAccessPermission();
-
+public class SessionManager {
/**
* Our source for random session IDs.
*/
- private static final Random _random = new Random();
+ private static Random _random = new Random();
/**
* Our session cache that is keyed on the session ID.
*/
- private static final Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
+ private static Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
/**
* The singleton instance
*/
- private static final SessionManager _manager = new SessionManager();
+ private static SessionManager _manager = new SessionManager();
/**
* The timeout for all user sessions.
@@ -90,7 +78,7 @@ public final class SessionManager {
/**
* Return the singleton object.
- *
+ *
* @return the {@link SessionManager}
*/
public static SessionManager getInstance() {
@@ -107,7 +95,6 @@ public final class SessionManager {
* sessionId will be assigned.
*/
public Subject put(Subject subject) {
- checkPermission();
return put(subject, DEFAULT_TIMEOUT);
}
@@ -121,7 +108,6 @@ public final class SessionManager {
* that Subject is overlord). The sessionId will be assigned.
*/
public synchronized Subject put(Subject subject, long timeout) {
- checkPermission();
Integer key;
do {
@@ -155,7 +141,6 @@ public final class SessionManager {
* @throws SessionTimeoutException
*/
public synchronized Subject getSubject(int sessionId) throws SessionNotFoundException, SessionTimeoutException {
- checkPermission();
Integer id = new Integer(sessionId);
AuthSession session = _cache.get(id);
@@ -177,7 +162,6 @@ public final class SessionManager {
* @param sessionId session id to invalidate
*/
public synchronized void invalidate(int sessionId) {
- checkPermission();
_cache.remove(new Integer(sessionId));
// while we are here, let's go through the entire session cache and remove expired sessions
@@ -203,7 +187,6 @@ public final class SessionManager {
* @param username username for the sessions to be invalidated
*/
public synchronized void invalidate(String username) {
- checkPermission();
List<Integer> doomedSessionIds = new ArrayList<Integer>(_cache.size());
for (AuthSession s : _cache.values()) {
if (username.equals(s.getSubject(false).getName())) {
@@ -218,7 +201,6 @@ public final class SessionManager {
}
public long getlastAccess(int sessionId) {
- checkPermission();
AuthSession session = _cache.get(sessionId);
if (session == null) {
return -1;
@@ -227,7 +209,6 @@ public final class SessionManager {
}
public Subject getOverlord() {
- checkPermission();
if (overlordSubject == null) {
overlordSubject = LookupUtil.getSubjectManager().getSubjectById(OVERLORD_SUBJECT_ID);
@@ -275,9 +256,4 @@ public final class SessionManager {
return copy;
}
-
- private static void checkPermission() {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
- }
}
\ No newline at end of file
diff --git a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
index 85e2fb3..05edefa 100644
--- a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
+++ b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
@@ -4,14 +4,6 @@
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
- <!-- This installs a custom initial context factory builder into the JVM
- that will ensure that all the default InitialContexts are going to check
- for the permission to access the RHQ internals. -->
- <bean class="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
- name="AccessCheckingInitialContextFactoryBuilderInstaller">
- </bean>
-
-
<bean name="Naming" class="org.jnp.server.SingletonNamingServer"/>
<bean name="InitialContextProperties" class="java.util.Hashtable">
@@ -28,7 +20,7 @@
</entry>
</map>
</parameter>
- </constructor>
+ </constructor>
</bean>
<bean name="java:comp/Initializer" class="org.jboss.ejb3.embedded.JavaCompInitializer">
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
deleted file mode 100644
index 1991e0e..0000000
--- a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
+++ /dev/null
@@ -1,315 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <artifactId>jndi-access-test-parent</artifactId>
- <groupId>org.rhq</groupId>
- <version>4.3.0-SNAPSHOT</version>
- </parent>
-
- <groupId>org.rhq</groupId>
- <artifactId>jndi-access-test</artifactId>
- <packaging>jar</packaging>
-
- <name>JNDI access integration test</name>
- <description>Tests for local and remote JNDI access from within serverside scripts.</description>
-
- <properties>
- <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
- <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
- <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
- <jnp.port>54987</jnp.port>
- <jnp.rmiPort>54988</jnp.rmiPort>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>runtime</scope>
- </dependency>
-
- <!--================ Test Deps ================ -->
-
- <!-- Note, the test deps are intentionally placed above the other
- scoped deps because of classpath reasons. Maven orders the [test] classpath
- in the order listed in the pom. We specifically need the embeddable-ejb3
- jar above the standard ejb3 jars because we need the embeddble packages loaded
- when testing. -->
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>test-utils</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>org.testng</groupId>
- <artifactId>testng</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>rhq-core-domain</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>rhq-enterprise-server</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-core-client-api</artifactId>
- <version>${project.version}</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-container-lib</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>rhq-server-client-api</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.rhq</groupId>
- <artifactId>jndi-access-remote-server</artifactId>
- <version>${project.version}</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>jboss.jboss-embeddable-ejb3</groupId>
- <artifactId>jboss-ejb3-all</artifactId>
- <version>${jboss-embeddable-ejb3.version}</version>
- <scope>test</scope>
- </dependency>
-
- <!-- NOTE: The remaining test deps correspond to the classes contained
- in hibernate-all.jar and thirdparty-all.jar. -->
-
- <dependency>
- <groupId>javassist</groupId>
- <artifactId>javassist</artifactId>
- <scope>test</scope>
- </dependency>
-
- <!-- needed by embedded ejb container -->
- <dependency>
- <groupId>trove</groupId>
- <artifactId>trove</artifactId>
- <version>1.0.2</version>
- <scope>test</scope>
- </dependency>
-
- <!-- needed by embedded ejb container -->
- <dependency>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- <version>2.8.1</version>
- <scope>test</scope>
- </dependency>
-
- <!-- 3rd Party Deps -->
-
- <!-- required by RHQ server classes, as well as EJB3 Embedded -->
- <dependency>
- <groupId>dom4j</groupId>
- <artifactId>dom4j</artifactId>
- <version>1.6.1-jboss</version>
- <scope>runtime</scope>
- </dependency>
-
- <dependency>
- <groupId>hibernate</groupId>
- <artifactId>hibernate3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <dependency>
- <groupId>hibernate-annotations</groupId>
- <artifactId>hibernate-annotations</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <dependency>
- <groupId>hibernate-entitymanager</groupId>
- <artifactId>hibernate-entitymanager</artifactId>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <version>1.4</version>
- </dependency>
-
- <dependency>
- <groupId>javax.persistence</groupId>
- <artifactId>persistence-api</artifactId>
- <version>1.0</version>
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-annotations-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed
- by the PoolClass annotation used on some of our SLSB's -->
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-ejb3</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <!-- for the transaction interrupt EJB3 interceptor -->
- <dependency>
- <groupId>org.jboss.transaction</groupId>
- <artifactId>jboss-jta</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS -->
- </dependency>
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
- </dependency>
-
- <dependency>
- <groupId>org.opensymphony.quartz</groupId>
- <artifactId>quartz-oracle</artifactId>
- <!-- NOTE: The version is defined in the root POM's dependencyManagement
- section. -->
- <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
- </dependency>
-
- <!-- This is needed cglib which is in turn needed by hibernate -->
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymockclassextension</artifactId>
- <version>2.2</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- <version>2.3.18</version>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>resteasy-jaxrs</artifactId>
- <version>${resteasy.version}</version>
- </dependency>
- </dependencies>
-
- <build>
- <testResources>
- <testResource>
- <directory>src/test/resources</directory>
- <filtering>true</filtering>
- </testResource>
- </testResources>
-
- <plugins>
- <plugin>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <!-- in order to get JMS to work properly in embedded
- test container, extract jms-rs.rar classes -->
- <execution>
- <id>Extract JMS classes from RAR needed for JMS tests</id>
- <phase>process-classes</phase>
- <configuration>
- <tasks>
- <unzip src="src/test/resources/jms-ra.rar"
- dest="target">
- <patternset>
- <include name="jms-ra.jar" />
- </patternset>
- </unzip>
- <unzip src="target/jms-ra.jar"
- dest="target/test-classes">
- <patternset>
- <include name="org/**" />
- </patternset>
- </unzip>
- </tasks>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <!-- Everything but the web service tests, this is the standard
- test execution -->
- <configuration>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <groups>${rhq.testng.includedGroups}</groups>
- <systemPropertyVariables>
- <embeddedDeployment>true</embeddedDeployment>
- <deploymentDirectory>target/test-classes</deploymentDirectory>
- <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
- <clean.db>${clean.db}</clean.db>
- <test.server.jar.path>${settings.localRepository}/org/rhq/jndi-access-remote-server/${project.version}/jndi-access-remote-server-${project.version}.jar</test.server.jar.path>
- <jnp.port>${jnp.port}</jnp.port>
- <jnp.rmiPort>${jnp.rmiPort}</jnp.rmiPort>
- </systemPropertyVariables>
- <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
- <additionalClasspathElements>
- <!-- The below is required for tests to run against
- Oracle. -->
- <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
- </additionalClasspathElements>
- </configuration>
- </plugin>
-
- </plugins>
- </build>
-
-</project>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
deleted file mode 100644
index f20d4f1..0000000
--- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.test;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.io.SerializablePermission;
-import java.security.PermissionCollection;
-import java.util.Collections;
-import java.util.Properties;
-
-import javax.naming.InitialContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Parameters;
-import org.testng.annotations.Test;
-
-import org.rhq.bindings.SandboxedScriptEngine;
-import org.rhq.bindings.ScriptEngineFactory;
-import org.rhq.bindings.StandardBindings;
-import org.rhq.bindings.StandardScriptPermissions;
-import org.rhq.bindings.util.PackageFinder;
-import org.rhq.core.domain.auth.Subject;
-import org.rhq.enterprise.client.LocalClient;
-import org.rhq.enterprise.server.test.AbstractEJB3Test;
-import org.rhq.enterprise.server.util.LookupUtil;
-import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-@Test
-public class JndiAccessTest extends AbstractEJB3Test {
- private static final Log JNP_SERVER_LOG = LogFactory.getLog("Test JNP Server");
-
- private Process testServerProcess;
- private Thread testServerStdErrReader;
- private Thread testServerStdOutReader;
-
- @BeforeClass
- @Parameters({"test.server.jar.path", "jnp.port", "jnp.rmiPort"})
- public void startTestJnpServer(String testServerJar, int jnpPort, int rmiPort) throws Exception {
- ProcessBuilder bld = new ProcessBuilder("java", "-Djnp.port=" + jnpPort, "-Djnp.rmiPort=" + rmiPort, "-jar", testServerJar);
-
- testServerProcess = bld.start();
-
- testServerStdErrReader = new Thread(new Runnable() {
- @Override
- public void run() {
- BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getErrorStream()));
- try {
- String line;
- while((line = rdr.readLine()) != null) {
- JNP_SERVER_LOG.warn(line);
- }
- } catch (IOException e) {
- JNP_SERVER_LOG.error("Reading test JNP server error output failed.", e);
- } finally {
- try {
- rdr.close();
- } catch (IOException e) {
- JNP_SERVER_LOG.error("Failed to close the test server error stream.", e);
- }
- }
- }
- });
- testServerStdErrReader.start();
-
- testServerStdOutReader = new Thread(new Runnable() {
- @Override
- public void run() {
- BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getInputStream()));
- try {
- String line;
- while((line = rdr.readLine()) != null) {
- JNP_SERVER_LOG.debug(line);
- }
- } catch (IOException e) {
- JNP_SERVER_LOG.error("Reading test JNP server standard output failed.", e);
- } finally {
- try {
- rdr.close();
- } catch (IOException e) {
- JNP_SERVER_LOG.error("Failed to close the test server standard output stream.", e);
- }
- }
- }
- });
- testServerStdOutReader.start();
-
- //give the JNP server some time to start up
- Thread.sleep(5000);
- }
-
- @AfterClass
- public void stopTestJnpServer() throws Exception {
- testServerProcess.destroy();
- testServerStdErrReader.join();
- testServerStdOutReader.join();
- }
-
- @Parameters("jnp.port")
- public void testRemoteConnectionWorkingFromJava(int jnpPort) throws Exception {
- Properties env = new Properties();
- env.put("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory");
- env.put("java.naming.provider.url", "jnp://localhost:" + jnpPort);
- InitialContext ctx = new InitialContext(env);
- Object kachny = ctx.lookup("kachny");
-
- assert kachny != null;
- }
-
- public void testLocalJNDILookupFailsFromScripts() throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "context = new javax.naming.InitialContext();\n"
- + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
- + "entityManager = entityManagerFactory.createEntityManager();\n"
- + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
-
- Assert.fail("The script shouldn't have been able to use the EntityManager.");
- } catch (ScriptException e) {
- checkIsDesiredSecurityException(e);
- }
- }
-
- @Parameters("jnp.port")
- public void testRemoteJNDILookupWorksFromScripts(int jnpPort) throws Exception {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval(""
- + "env = new java.util.Hashtable();"
- + "env.put('java.naming.factory.initial', 'org.jboss.naming.NamingContextFactory');"
- + "env.put('java.naming.provider.url', 'jnp://localhost:" + jnpPort + "');"
- + "context = new javax.naming.InitialContext(env);\n"
- + "kachny = context.lookup('kachny');\n"
- + "assertNotNull(kachny);\n");
- } catch (ScriptException e) {
- Assert.fail("The script should have been able to access a remote JNDI server.", e);
- }
- }
-
- private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
- StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
- ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
-
- PermissionCollection perms = new StandardScriptPermissions();
-
- return new SandboxedScriptEngine(engine, perms);
- }
-
- private static void checkIsDesiredSecurityException(ScriptException e) {
- String message = e.getMessage();
- String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
-
- Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
- }
-}
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
deleted file mode 100644
index 1951b84..0000000
--- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
-# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
-# WORK IN THIS MODULE.
-
-hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
-#hibernate.connection.release_mode=after_statement
-#hibernate.transaction.flush_before_completion=false
-#hibernate.transaction.auto_close_session=false
-#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
-#hibernate.hbm2ddl.auto=create-drop
-#hibernate.hbm2ddl.auto=create
-hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
-# Clustered cache with TreeCache
-#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
-#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
-#hibernate.dialect=org.hibernate.dialect.HSQLDialect
-hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
-hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
-hibernate.bytecode.use_reflection_optimizer=false
-# I don't think this is honored, but EJB3Deployer uses it
-hibernate.bytecode.provider=javassist
-hibernate.jdbc.use_streams_for_binary=true
-hibernate.show_sql=false
-hibernate.format_sql=true
-hibernate.default_batch_fetch_size=16
-hibernate.jdbc.batch_size=20
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
deleted file mode 100644
index ec09ed7..0000000
--- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-
-<!-- ===================================================================== -->
-<!-- -->
-<!-- Log4j Configuration -->
-<!-- -->
-<!-- ===================================================================== -->
-
-<!-- $Id: log4j.xml 39945 2006-01-12 02:44:07Z bill $ -->
-
-<!--
- | For more configuration infromation and examples see the Jakarta Log4j
- | owebsite: http://jakarta.apache.org/log4j
- -->
-
-<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
-
- <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
- <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
- <param name="Target" value="System.out"/>
- <param name="Threshold" value="WARN"/>
-
- <layout class="org.apache.log4j.PatternLayout">
- <!-- The default pattern: Date Priority [Category] Messagen -->
- <!--
- <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
- -->
- <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
- </layout>
- </appender>
-
- <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
- <param name="File" value="target/server-jar-test.log"/>
- <param name="Threshold" value="WARN"/>
- <param name="Append" value="false"/>
-
- <layout class="org.apache.log4j.PatternLayout">
- <!-- The default pattern: Date Priority [Category] Messagen -->
- <!--
- <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
- -->
- <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
- </layout>
- </appender>
-
- <category name="Test JNP Server">
- <priority value="DEBUG"/>
- </category>
-
- <!-- Hibernate logs WARNINGS frequent from this class, in test envs. -->
- <category name="org.hibernate.hql.ast.QueryTranslatorImpl">
- <priority value="ERROR"/>
- </category>
-
- <!-- hides the TIMER SERVICE IS NOT INSTALLED warning - we know embedded EJB3 container doesn't support timers -->
- <category name="org.jboss.ejb3.timerservice.jboss.JBossTimerServiceFactory">
- <priority value="ERROR"/>
- </category>
-
- <!-- hides the shutdown warnings - for some reason, the container spits out some warnings when shutting down -->
- <category name="org.jboss.kernel.plugins.dependency.StartStopLifecycleAction">
- <priority value="ERROR"/>
- </category>
-
- <!-- Hibernate SQL logs -->
- <!--
- <category name="org.hibernate.SQL">
- <priority value="DEBUG"/>
- </category>
- -->
-
- <root>
- <appender-ref ref="CONSOLE"/>
- <appender-ref ref="FILE"/>
- </root>
-
-</log4j:configuration>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
deleted file mode 100644
index 8860b47..0000000
--- a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
+++ /dev/null
@@ -1,10 +0,0 @@
-// We need the SecurityManager installed to enable sandboxing of CLI scripts
-// but we don't define any other security measures on the RHQ server itself.
-//
-// Granting all permissions allows us to run the RHQ server as if no security
-// manager was in place (which is assumed by default by JBoss AS) but be able
-// to use it when we need it for our own purposes.
-
-grant {
- permission java.security.AllPermission;
-};
diff --git a/modules/integration-tests/jndi-access/pom.xml b/modules/integration-tests/jndi-access/pom.xml
deleted file mode 100644
index 6e9c673..0000000
--- a/modules/integration-tests/jndi-access/pom.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <artifactId>rhq-integration-tests</artifactId>
- <groupId>org.rhq</groupId>
- <version>4.3.0-SNAPSHOT</version>
- </parent>
-
- <groupId>org.rhq</groupId>
- <artifactId>jndi-access-test-parent</artifactId>
- <packaging>pom</packaging>
-
- <name>JNDI access tests</name>
- <description>Tests for the secured JNDI access tests</description>
-
- <modules>
- <module>remote-server</module>
- <module>jndi-access-test</module>
- </modules>
-</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/pom.xml b/modules/integration-tests/jndi-access/remote-server/pom.xml
deleted file mode 100644
index 9046e6f..0000000
--- a/modules/integration-tests/jndi-access/remote-server/pom.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <artifactId>jndi-access-test-parent</artifactId>
- <groupId>org.rhq</groupId>
- <version>4.3.0-SNAPSHOT</version>
- </parent>
-
- <groupId>org.rhq</groupId>
- <artifactId>jndi-access-remote-server</artifactId>
- <packaging>jar</packaging>
-
- <name>Test JNDI-enabled remote server</name>
- <description>
- A testing JNDI-enabled server to test the ability to connect to remote servers without security
- checks from within the scripts running inside the RHQ server.
- </description>
-
- <dependencies>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jnpserver</artifactId>
- <version>4.2.2.GA</version>
- </dependency>
-
- <dependency>
- <groupId>jboss</groupId>
- <artifactId>jboss-common</artifactId>
- <version>4.2.2.GA</version>
- </dependency>
-
- <dependency>
- <groupId>oswego-concurrent</groupId>
- <artifactId>concurrent</artifactId>
- <version>1.3.4-jboss</version>
- </dependency>
-
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>package</id>
- <phase>package</phase>
- <goals><goal>single</goal></goals>
- <configuration>
- <archive>
- <manifest>
- <mainClass>org.rhq.jndi.test.Server</mainClass>
- </manifest>
- </archive>
- <descriptorRefs>
- <descriptorRef>jar-with-dependencies</descriptorRef>
- </descriptorRefs>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- </plugins>
- </build>
-</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java b/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
deleted file mode 100644
index 7bfb8e8..0000000
--- a/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.rhq.jndi.test;
-import java.util.Properties;
-
-import javax.naming.CompoundName;
-
-import org.jnp.server.Main;
-import org.jnp.server.NamingBeanImpl;
-
-import org.jboss.logging.Logger;
-
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class Server {
- private static final Logger LOG = Logger.getLogger(Server.class);
-
- private static Server INSTANCE;
-
- private Main jnpServer;
-
- public static void main(String[] args) throws Exception {
- LOG.debug("System properties: " + System.getProperties());
- Server.start();
- }
-
- private Server() {
- jnpServer = new Main("org.rhq.jndi.access.test.server");
- }
-
- public static synchronized Server getInstance() {
- if (INSTANCE == null) {
- INSTANCE = new Server();
- }
-
- return INSTANCE;
- }
-
- public static void start() throws Exception {
- LOG.debug("Initializing the JNP server");
-
- NamingBeanImpl nbi = new NamingBeanImpl();
- getInstance().jnpServer.setNamingInfo(nbi);
- nbi.start();
-
- LOG.debug("Binding kachny");
-
- nbi.getNamingInstance().bind(new CompoundName("kachny", new Properties()), "KACHNY!", String.class.getName());
-
- LOG.debug("Starting the JNP server");
-
- getInstance().jnpServer.start();
- }
-
- public static void stop() {
- LOG.debug("Stopping the JNP server");
- getInstance().jnpServer.stop();
- }
-}
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
deleted file mode 100644
index a45f2ce..0000000
--- a/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-java.naming.factory.initial=org.jboss.naming.NamingContextFactory
-java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
deleted file mode 100644
index 2d41f83..0000000
--- a/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-log4j.rootCategory=TRACE, CONSOLE
-
-log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
-log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
-log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c] %m%n
diff --git a/modules/integration-tests/pom.xml b/modules/integration-tests/pom.xml
index 969b94a..0290729 100644
--- a/modules/integration-tests/pom.xml
+++ b/modules/integration-tests/pom.xml
@@ -62,7 +62,6 @@
<id>integration-tests</id>
<modules>
<module>apache-plugin-test</module>
- <module>jndi-access</module>
<!--<module>mod_cluster-plugin-test</module>-->
</modules>
</profile>
commit 772e9d247e524071a86d6a25b8e1615ed77e9fcf
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Jan 9 14:05:09 2012 +0100
Fixing the application of various decorators to JNDI contexts to support
contexts that implement more than 1 context interface (like LdapCtx which
implements both LdapContext and EventDirContext).
This should fix the RHQ's LDAP integration for good.
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
index 60e9bf6..3046af7 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -27,7 +27,7 @@ import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -37,6 +37,10 @@ import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.event.EventDirContext;
+import javax.naming.ldap.LdapContext;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;
@@ -45,16 +49,10 @@ import org.apache.commons.logging.LogFactory;
import org.jnp.interfaces.NamingContextFactory;
import org.rhq.jndi.context.AccessCheckingContextDecorator;
-import org.rhq.jndi.context.AccessCheckingDirContextDecorator;
-import org.rhq.jndi.context.AccessCheckingEventContextDecorator;
-import org.rhq.jndi.context.AccessCheckingEventDirContextDecorator;
-import org.rhq.jndi.context.AccessCheckingLdapContextDecorator;
-import org.rhq.jndi.context.ContextDecoratorPicker;
-import org.rhq.jndi.context.URLPreferringContextDecorator;
-import org.rhq.jndi.context.URLPreferringDirContextDecorator;
-import org.rhq.jndi.context.URLPreferringEventContextDecorator;
-import org.rhq.jndi.context.URLPreferringEventDirContextDecorator;
-import org.rhq.jndi.context.URLPreferringLdapContextDecorator;
+import org.rhq.jndi.context.AccessCheckingContextDecoratorSetContext;
+import org.rhq.jndi.context.ContextDecorator;
+import org.rhq.jndi.context.URLPreferringContextDecoratorSetContext;
+import org.rhq.jndi.util.DecoratorPicker;
/**
* This initial context factory builder is installed early on during the RHQ server startup
@@ -89,6 +87,17 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
*/
private static final String[] CHECKED_SCHEMES = { "java" };
+ private static final Set<Class<? extends Context>> SUPPORTED_CONTEXT_INTERFACES;
+
+ static {
+ SUPPORTED_CONTEXT_INTERFACES = new HashSet<Class<? extends Context>>();
+ SUPPORTED_CONTEXT_INTERFACES.add(Context.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(DirContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(EventContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(EventDirContext.class);
+ SUPPORTED_CONTEXT_INTERFACES.add(LdapContext.class);
+ }
+
private static final Set<InetAddress> SERVER_BIND_IPS;
static {
SERVER_BIND_IPS = new HashSet<InetAddress>();
@@ -191,42 +200,31 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
}
private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
- return new DecoratingInitialContextFactory(original, Arrays.asList(
- getURLPreferringDecoratorPicker(), getAccessCheckingDecoratorPicker()));
- }
-
- private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
- return new DecoratingInitialContextFactory(original, Arrays.asList(
- getURLPreferringDecoratorPicker()));
+ ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+ pickers.add(getURLPreferringDecoratorPicker());
+ pickers.add(getAccessCheckingDecoratorPicker());
+
+ return new DecoratingInitialContextFactory(original, pickers);
}
- private static ContextDecoratorPicker getAccessCheckingDecoratorPicker() {
- ContextDecoratorPicker ret = new ContextDecoratorPicker();
-
- ret.setConstructorParameters(new Object[] { CHECKED_SCHEMES });
- ret.setConstructorParameterTypes(new Class<?>[] { String[].class });
+ private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
+ ArrayList<DecoratorPicker<Context, ContextDecorator>> pickers = new ArrayList<DecoratorPicker<Context,ContextDecorator>>();
+ pickers.add(getURLPreferringDecoratorPicker());
- ret.getPossibleDecorators().add(AccessCheckingContextDecorator.class);
- ret.getPossibleDecorators().add(AccessCheckingDirContextDecorator.class);
- ret.getPossibleDecorators().add(AccessCheckingEventContextDecorator.class);
- ret.getPossibleDecorators().add(AccessCheckingEventDirContextDecorator.class);
- ret.getPossibleDecorators().add(AccessCheckingLdapContextDecorator.class);
+ return new DecoratingInitialContextFactory(original, pickers);
+ }
+ private static DecoratorPicker<Context, ContextDecorator> getAccessCheckingDecoratorPicker() {
+ DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+ ret.setContext(new AccessCheckingContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES, CHECKED_SCHEMES));
+
return ret;
}
- private static ContextDecoratorPicker getURLPreferringDecoratorPicker() {
- ContextDecoratorPicker ret = new ContextDecoratorPicker();
-
- ret.setConstructorParameters(null);
- ret.setConstructorParameterTypes(null);
-
- ret.getPossibleDecorators().add(URLPreferringContextDecorator.class);
- ret.getPossibleDecorators().add(URLPreferringDirContextDecorator.class);
- ret.getPossibleDecorators().add(URLPreferringEventContextDecorator.class);
- ret.getPossibleDecorators().add(URLPreferringEventDirContextDecorator.class);
- ret.getPossibleDecorators().add(URLPreferringLdapContextDecorator.class);
-
+ private static DecoratorPicker<Context, ContextDecorator> getURLPreferringDecoratorPicker() {
+ DecoratorPicker<Context, ContextDecorator> ret = new DecoratorPicker<Context, ContextDecorator>();
+ ret.setContext(new URLPreferringContextDecoratorSetContext(SUPPORTED_CONTEXT_INTERFACES));
+
return ret;
}
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
index 2414c98..19b30ea 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
@@ -19,45 +19,82 @@
package org.rhq.jndi;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
+import java.util.Set;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
-import org.rhq.jndi.context.ContextDecoratorPicker;
+import org.rhq.jndi.context.ContextDecorator;
+import org.rhq.jndi.util.DecoratorPicker;
+import org.rhq.jndi.util.DecoratingInvocationHandler;
/**
+ * This class implements an initial context factory that decorates the contexts
+ * returned from a "wrapped" initial factory passed to this class in the constructor.
+ * <p>
+ * The contexts returned from the wrapped initial factory are hidden behind a proxy
+ * that implements the intersection of interfaces from the <code>supportedContextInterfaces</code>
+ * constructor parameter and the actual interfaces the wrapped context implements.
+ * <p>
+ * The proxy method calls are handled using the {@link DecoratingInvocationHandler} which is initialized
+ * with the list of {@link DecoratorPicker pickers} that are used to intercept the method
+ * calls on the wrapped context.
+ *
+ * @see DecoratorPicker
+ * @see DecoratingInvocationHandler
*
- *
* @author Lukas Krejci
*/
public class DecoratingInitialContextFactory implements InitialContextFactory {
- private List<ContextDecoratorPicker> pickers;
+ List<DecoratorPicker<Context, ContextDecorator>> pickers;
private InitialContextFactory factory;
+ private Set<Class<? extends Context>> supportedContextInterfaces;
- public DecoratingInitialContextFactory(InitialContextFactory factory, List<ContextDecoratorPicker> decoratorPickers) {
+ public DecoratingInitialContextFactory(InitialContextFactory factory, List<DecoratorPicker<Context, ContextDecorator>> decoratorPickers) {
this.factory = factory;
this.pickers = decoratorPickers;
+ this.supportedContextInterfaces = new HashSet<Class<? extends Context>>();
+ for(DecoratorPicker<Context, ContextDecorator> picker : pickers) {
+ supportedContextInterfaces.addAll(picker.getContext().getSupportedInterfaces());
+ }
}
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
Context ctx = factory.getInitialContext(environment);
- try {
- for(ContextDecoratorPicker picker : pickers) {
- ctx = picker.wrapInAppropriateDecorator(ctx);
- }
- } catch (IllegalArgumentException e) {
- NamingException ex = new NamingException();
- ex.initCause(ex);
-
- throw e;
- }
+ Set<Class<?>> implementedIfaces = getAllImplementedInterfaces(ctx.getClass());
+ Class<?>[] ii = new Class<?>[implementedIfaces.size()];
+ implementedIfaces.toArray(ii);
- return ctx;
+ return (Context) Proxy.newProxyInstance(ctx.getClass().getClassLoader(), ii, new DecoratingInvocationHandler<Context, ContextDecorator>(pickers, ctx));
+ }
+
+ private Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
+ HashSet<Class<?>> ret = new HashSet<Class<?>>();
+ getAllImplementedInterfaces(cls, ret);
+
+ ret.retainAll(supportedContextInterfaces);
+
+ return ret;
}
+ private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
+ Class<?>[] ifaces = cls.getInterfaces();
+
+ for (Class<?> iface : Arrays.asList(ifaces)) {
+ output.add(iface);
+ getAllImplementedInterfaces(iface, output);
+ }
+
+ if (cls.getSuperclass() != null) {
+ getAllImplementedInterfaces(cls.getSuperclass(), output);
+ }
+ }
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
new file mode 100644
index 0000000..284fd0c
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecoratorSetContext.java
@@ -0,0 +1,75 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
+
+ private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
+ static {
+ HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
+ tmp.add(AccessCheckingContextDecorator.class);
+ tmp.add(AccessCheckingDirContextDecorator.class);
+ tmp.add(AccessCheckingEventContextDecorator.class);
+ tmp.add(AccessCheckingEventDirContextDecorator.class);
+ tmp.add(AccessCheckingLdapContextDecorator.class);
+
+ DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
+ }
+
+ private Set<Class<? extends Context>> supportedInterfaces;
+ private String[] checkedSchemes;
+
+ public AccessCheckingContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces, String... checkedSchemes) {
+ this.supportedInterfaces = supportedInterfaces;
+ this.checkedSchemes = checkedSchemes;
+ }
+
+ public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
+ Constructor<? extends ContextDecorator> ctor = decoratorClass.getConstructor(String[].class);
+
+ return ctor.newInstance((Object)checkedSchemes);
+ }
+
+ public Set<Class<? extends Context>> getSupportedInterfaces() {
+ return supportedInterfaces;
+ }
+
+ public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
+ return DECORATOR_CLASSES;
+ }
+
+ public void init(ContextDecorator decorator, Context object) throws Exception {
+ decorator.init(object);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java
deleted file mode 100644
index a088aa2..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2012 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi.context;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-
-/**
- * @author Lukas Krejci
- */
-public class ContextDecoratorPicker {
-
- private Set<Class<? extends ContextDecorator>> possibleDecorators = new HashSet<Class<? extends ContextDecorator>>();
- private Class<?>[] constructorParameterTypes;
- private Object[] constructorParameters;
-
- public ContextDecoratorPicker() {
- }
-
- public ContextDecoratorPicker(Collection<? extends Class<? extends ContextDecorator>> c) {
- possibleDecorators.addAll(c);
- }
-
- public Set<Class<? extends ContextDecorator>> getPossibleDecorators() {
- return possibleDecorators;
- }
-
- public Class<?>[] getConstructorParameterTypes() {
- return constructorParameterTypes;
- }
-
- public void setConstructorParameterTypes(Class<?>[] constructorParameterTypes) {
- this.constructorParameterTypes = constructorParameterTypes;
- }
-
- public Object[] getConstructorParameters() {
- return constructorParameters;
- }
-
- public void setConstructorParameters(Object[] constructorParameters) {
- this.constructorParameters = constructorParameters;
- }
-
- public Context wrapInAppropriateDecorator(Context context) throws NamingException {
- Class<? extends ContextDecorator> cls = getMatchByInterfaces(context, possibleDecorators);
-
- if (cls == null) {
- throw new IllegalArgumentException("Could not find a matching context decorator for " + context.getClass() + " in " + this);
- }
-
- Constructor<? extends ContextDecorator> ctor = null;
- try {
- ctor = cls.getConstructor(constructorParameterTypes);
- ContextDecorator ctx = ctor.newInstance(constructorParameters);
-
- ctx.init(context);
-
- return ctx;
- } catch (SecurityException e) {
- throw new IllegalStateException("Could not instantiate a class through reflection.", e);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException(
- "Could not construct a context decorator - unable to find a constructor with parameters "
- + (constructorParameterTypes == null ? "[no parameters]" : Arrays.asList(constructorParameterTypes)) + " on class " + cls.getName(), e);
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
- } catch (InstantiationException e) {
- throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
- } catch (IllegalAccessException e) {
- throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
- } catch (InvocationTargetException e) {
- throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
- }
- }
-
- private static <T> Class<? extends T> getMatchByInterfaces(Object obj, Set<Class<? extends T>> classes) {
- Set<Class<?>> ifaces = getAllImplementedInterfaces(obj.getClass());
-
- Class<? extends T> match = null;
- int maxMatchCnt = Integer.MIN_VALUE;
-
- for(Class<? extends T> cls : classes) {
- int cnt = getBestMatchByIfaces(cls, ifaces);
- if (cnt > maxMatchCnt) {
- maxMatchCnt = cnt;
- match = cls;
- }
- }
-
- return match;
- }
-
- private static int getBestMatchByIfaces(Class<?> cls, Set<Class<?>> ifaces) {
- int ret = 0;
-
- //count how many interfaces from the supplied array the class implements
- for(Class<?> iface : ifaces) {
- if (iface.isAssignableFrom(cls)) {
- ++ret;
- } else {
- --ret;
- }
- }
-
- //that's not all - to get the best possible match, we need to take into account
- //the fact that the class might implement more than just the interfaces provided
- Set<Class<?>> clsIfaces = getAllImplementedInterfaces(cls);
-
- for(Class<?> clsIface : clsIfaces) {
- if (!(ifaces.contains(clsIface))) {
- --ret;
- }
- }
-
- return ret;
- }
-
- private static Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
- HashSet<Class<?>> ret = new HashSet<Class<?>>();
- getAllImplementedInterfaces(cls, ret);
-
- return ret;
- }
-
- private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
- Class<?>[] ifaces = cls.getInterfaces();
-
- for(Class<?> iface : Arrays.asList(ifaces)) {
- output.add(iface);
- getAllImplementedInterfaces(iface, output);
- }
-
- if (cls.getSuperclass() != null) {
- getAllImplementedInterfaces(cls.getSuperclass(), output);
- }
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
new file mode 100644
index 0000000..828cd74
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorSetContext.java
@@ -0,0 +1,71 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecoratorSetContext implements DecoratorSetContext<Context, ContextDecorator> {
+
+ private static final Set<Class<? extends ContextDecorator>> DECORATOR_CLASSES;
+ static {
+ HashSet<Class<? extends ContextDecorator>> tmp = new HashSet<Class<? extends ContextDecorator>>();
+ tmp.add(URLPreferringContextDecorator.class);
+ tmp.add(URLPreferringDirContextDecorator.class);
+ tmp.add(URLPreferringEventContextDecorator.class);
+ tmp.add(URLPreferringEventDirContextDecorator.class);
+ tmp.add(URLPreferringLdapContextDecorator.class);
+
+ DECORATOR_CLASSES = Collections.unmodifiableSet(tmp);
+ }
+
+ private Set<Class<? extends Context>> supportedInterfaces;
+
+ public URLPreferringContextDecoratorSetContext(Set<Class<? extends Context>> supportedInterfaces) {
+ this.supportedInterfaces = supportedInterfaces;
+ }
+
+ public Set<Class<? extends Context>> getSupportedInterfaces() {
+ return supportedInterfaces;
+ }
+
+ public Set<Class<? extends ContextDecorator>> getDecoratorClasses() {
+ return DECORATOR_CLASSES;
+ }
+
+ public ContextDecorator instantiate(Class<? extends ContextDecorator> decoratorClass) throws Exception {
+ return decoratorClass.newInstance();
+ }
+
+ public void init(ContextDecorator decorator, Context object) throws Exception {
+ decorator.init(object);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
new file mode 100644
index 0000000..356a6e9
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratingInvocationHandler.java
@@ -0,0 +1,46 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public class DecoratingInvocationHandler<Type, Decorator extends Type> implements InvocationHandler {
+
+ private final List<DecoratorPicker<Type, Decorator>> pickers;
+ private Type object;
+
+ public DecoratingInvocationHandler(List<DecoratorPicker<Type, Decorator>> pickers, Type object) {
+ this.pickers = pickers;
+ this.object = object;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Type target = object;
+ Class<?> methodClass = method.getDeclaringClass();
+
+ for(DecoratorPicker<Type, Decorator> picker : pickers) {
+ target = picker.decorate(target, methodClass);
+ }
+
+ return method.invoke(target, args);
+ }
+}
\ No newline at end of file
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
new file mode 100644
index 0000000..017d29f
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorPicker.java
@@ -0,0 +1,195 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Given as set of decorators extending given type, this class can pick
+ * the most appropriate set of decorators for a class or a method call.
+ * <p>
+ * To configure the decorator, one has to provide a {@link DecoratorSetContext} that
+ * is then used to obtain the list of
+ * {@link DecoratorSetContext#getSupportedInterfaces() supported interfaces}, which are
+ * all the interfaces that should be used for decorator resolution (i.e. all other interfaces
+ * that a class might implement are ignored during decorator resolution), the list of
+ * {@link DecoratorSetContext#getDecoratorClasses() decorator classes}, which is a list
+ * of decorators the picker can choose from and is also used to instantiate and initialize
+ * the decorators.
+ *
+ * @author Lukas Krejci
+ */
+public class DecoratorPicker<Type, Decorator extends Type> {
+
+ private DecoratorSetContext<Type, Decorator> context;
+
+ public DecoratorSetContext<Type, Decorator> getContext() {
+ return context;
+ }
+
+ public void setContext(DecoratorSetContext<Type, Decorator> decoratorSetContext) {
+ this.context = decoratorSetContext;
+ }
+
+ /**
+ * Returns a set of decorators applicable for given method. The set is established based
+ * on the declaring class of the method.
+ *
+ * @param method the method to inspect
+ * @return the set of decorators that can be used to wrap a method call
+ * @throws Exception
+ */
+ public Set<Decorator> getDecoratorsForMethod(Method method) throws Exception {
+ return getDecoratorsForClass_Private(method.getDeclaringClass());
+ }
+
+ /**
+ * Returns a set of decorators that can be used on instances of given class.
+ * @param cls the class to inspect
+ * @return
+ * @throws Exception
+ */
+ public Set<Decorator> getDecoratorsForClass(Class<? extends Type> cls) throws Exception {
+ return getDecoratorsForClass_Private(cls);
+ }
+
+ /**
+ * This method first establishes the set of decorators to use based on the class of the supplied
+ * object and then chains the decorators (in arbitrary order) with the supplied object at the
+ * "root" of the chain.
+ * <p>
+ * If a method is then called on the returned object, the methods of all the decorators are called
+ * in chain (each supposedly calling the next) and finally, at the end of the chain, the method on
+ * the original object (the one supplied to this method) is called.
+ * <p>
+ * Note that the above is only an intended behavior and actually depends on the implementation of
+ * the decorators that are resposinble for the chaining. Each decorator is initialized
+ * (@{link {@link DecoratorSetContext#init(Object, Object)} which should set it up for such chaining.
+ *
+ * @param object
+ * @return
+ * @throws Exception
+ */
+ public Type decorate(Type object) throws Exception {
+ Set<Decorator> decs = getDecoratorsForClass_Private(object.getClass());
+ Type ret = object;
+ for(Decorator d : decs) {
+ context.init(d, ret);
+ ret = d;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Similar to {@link #decorate(Object)} but instead of the class of the object itself,
+ * uses the significantSuperClass as the basis for the decorator resolution.
+ * <p>
+ * This is important, because if the object implements two mutually incompatible sub-interfaces of <code>Type</code>,
+ * the chained decorators might fail to execute a method later on if the decorator depends on the upper part
+ * of the chain to implement certain sub-interface of <code>Type</code>.
+ *
+ * @param object the object to wrap in decorators
+ * @param significantSuperClass the class to base the decorator resolution on
+ * @return
+ * @throws Exception
+ */
+ public Type decorate(Type object, Class<?> significantSuperClass) throws Exception {
+ Set<Decorator> decs = getDecoratorsForClass_Private(significantSuperClass);
+ Type ret = object;
+ for(Decorator d : decs) {
+ context.init(d, ret);
+ ret = d;
+ }
+
+ return ret;
+ }
+
+ private Set<Decorator> getDecoratorsForClass_Private(Class<?> cls) throws Exception {
+ Set<Class<? extends Type>> ifaces = getNearestApplicableInterfaces(cls);
+
+ HashSet<Decorator> ret = new HashSet<Decorator>();
+
+ for (Class<? extends Type> iface : ifaces) {
+ for (Class<? extends Decorator> decClass : getMatch(iface)) {
+ ret.add(context.instantiate(decClass));
+ }
+ }
+
+ return ret;
+ }
+
+ private Set<Class<? extends Type>> getNearestApplicableInterfaces(Class<?> cls) {
+ List<Class<? extends Type>> ifaces = new ArrayList<Class<? extends Type>>(getAllApplicableInterfaces(cls));
+
+ //now compact the set to only contain the most concrete interfaces
+
+ Iterator<Class<? extends Type>> it = ifaces.iterator();
+ while (it.hasNext()) {
+ Class<? extends Type> c = it.next();
+
+ for (int i = 0; i < ifaces.size(); ++i) {
+ Class<? extends Type> nextC = ifaces.get(i);
+ if (!c.equals(nextC) && c.isAssignableFrom(nextC)) {
+ it.remove();
+ break;
+ }
+ }
+ }
+
+ return new HashSet<Class<? extends Type>>(ifaces);
+ }
+
+ private Set<Class<? extends Type>> getAllApplicableInterfaces(Class<?> cls) {
+ Set<Class<? extends Type>> ifaces = new HashSet<Class<? extends Type>>();
+
+ for (Class<? extends Type> iface : context.getSupportedInterfaces()) {
+ if (iface.isAssignableFrom(cls)) {
+ ifaces.add(iface);
+ }
+ }
+
+ if (ifaces.isEmpty()) {
+ throw new IllegalArgumentException("Class " + cls
+ + " doesn't implement any of the applicable interfaces. Cannot find decorators for it.");
+ }
+
+ return ifaces;
+ }
+
+ private Set<Class<? extends Decorator>> getMatch(Class<?> targetIface) {
+
+ Set<Class<? extends Decorator>> ret = new HashSet<Class<? extends Decorator>>();
+
+ for (Class<? extends Decorator> cls : context.getDecoratorClasses()) {
+ if (Arrays.asList(cls.getInterfaces()).contains(targetIface)) {
+ ret.add(cls);
+ }
+ }
+
+ return ret;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
new file mode 100644
index 0000000..d7b1676
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/util/DecoratorSetContext.java
@@ -0,0 +1,59 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.util;
+
+import java.util.Set;
+
+/**
+ * Implementations of this interface provide a context to the {@link DecoratorPicker}.
+ *
+ * @author Lukas Krejci
+ */
+public interface DecoratorSetContext<Type, Decorator> {
+
+ /**
+ * @return the set of interfaces that the decorators are able support.
+ * Usually this should be just a union of all interfaces the decorators implement
+ * but can be trimmed down.
+ */
+ Set<Class<? extends Type>> getSupportedInterfaces();
+
+ /**
+ * @return the set of all decorator classes in this set
+ */
+ Set<Class<? extends Decorator>> getDecoratorClasses();
+
+ /**
+ * Instantiates a new decorator of given class.
+ * @param decoratorClass
+ * @return
+ * @throws Exception
+ */
+ Decorator instantiate(Class<? extends Decorator> decoratorClass) throws Exception;
+
+ /**
+ * Initializes the decorator to decorate given object.
+ *
+ * @param decorator
+ * @param object
+ * @throws Exception on error
+ */
+ void init(Decorator decorator, Type object) throws Exception;
+}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
new file mode 100644
index 0000000..45ba114
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratingInvocationHandlerTest.java
@@ -0,0 +1,145 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.NamingManager;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class DecoratingInvocationHandlerTest {
+ private static final Set<String> INVOKED_METHODS = new HashSet<String>();
+
+ private static final InvocationHandler NOTE_TAKING_HANDLER = new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ INVOKED_METHODS.add(method.getName());
+
+ if ("hashCode".equals(method.getName())) {
+ return 0;
+ } else if ("equals".equals(method.getName())) {
+ return false;
+ }
+
+ return null;
+ }
+ };
+
+ private static Class<?>[] CONTEXT_INTERFACES;
+
+ public static class Factory implements InitialContextFactory {
+ public Context getInitialContext(Hashtable<?, ?> environment)
+ throws NamingException {
+
+ return (Context) Proxy.newProxyInstance(DecoratingInvocationHandlerTest.class.getClassLoader(), CONTEXT_INTERFACES, NOTE_TAKING_HANDLER);
+ }
+ }
+
+ private static class DummyInitialEventContext extends InitialContext implements EventContext {
+
+ /**
+ * @param environment
+ * @throws NamingException
+ */
+ public DummyInitialEventContext(Hashtable<?, ?> environment) throws NamingException {
+ super(environment);
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ ((EventContext)getURLOrDefaultInitCtx(target)).addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ ((EventContext)getDefaultInitCtx()).removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return ((EventContext)getDefaultInitCtx()).targetMustExist();
+ }
+
+
+ }
+
+ @BeforeClass
+ public void setBuilder() throws Exception {
+ NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
+ }
+
+ public void testSimpleDispatch() throws Exception {
+ INVOKED_METHODS.clear();
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
+
+ CONTEXT_INTERFACES = new Class<?>[] { Context.class };
+
+ InitialContext ctx = new InitialContext(env);
+
+ ctx.lookup("asdf");
+
+ assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
+ }
+
+ public void testMultiInterfaceDispatch() throws Exception {
+ INVOKED_METHODS.clear();
+ Properties env = new Properties();
+ env.put(Context.INITIAL_CONTEXT_FACTORY, Factory.class.getName());
+
+ CONTEXT_INTERFACES = new Class<?>[] { EventContext.class, DirContext.class };
+
+ InitialContext ctx = new InitialContext(env);
+
+ ctx.lookup("asdf");
+
+ DummyInitialEventContext ectx = new DummyInitialEventContext(env);
+
+ ectx.addNamingListener("hodiny", 0, null);
+
+ assert INVOKED_METHODS.contains("lookup") : "The lookup doesn't seem to have propagated to the actual context to be used.";
+ assert INVOKED_METHODS.contains("addNamingListener") : "The addNamingListener doesn't seem to have propagated to the actual context to be used.";
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
new file mode 100644
index 0000000..e2d7429
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/test/java/org/rhq/jndi/context/DecoratorPickerTest.java
@@ -0,0 +1,180 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.directory.DirContext;
+import javax.naming.event.EventContext;
+import javax.naming.ldap.LdapContext;
+
+import org.testng.annotations.Test;
+
+import org.rhq.jndi.util.DecoratorPicker;
+import org.rhq.jndi.util.DecoratorSetContext;
+
+/**
+ * @author Lukas Krejci
+ */
+@Test
+public class DecoratorPickerTest {
+
+ private static final InvocationHandler DUMMY_HANDLER = new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("hashCode".equals(method.getName())) {
+ return 0;
+ } else if ("equals".equals(method.getName())) {
+ return false;
+ }
+
+ return null;
+ }
+ };
+
+ private static final Class<?> TEST_OBJECT_CLASS1 = createProxyClass(Context.class);
+ private static final Class<?> TEST_OBJECT_CLASS2 = createProxyClass(DirContext.class);
+ private static final Class<?> TEST_OBJECT_CLASS3 = createProxyClass(LdapContext.class);
+ private static final Class<?> TEST_OBJECT_CLASS4 = createProxyClass(LdapContext.class, EventContext.class);
+ private static final Class<?> DECORATOR_CLASS1 = createProxyClass(Context.class);
+ private static final Class<?> DECORATOR_CLASS2 = createProxyClass(EventContext.class);
+ private static final Class<?> DECORATOR_CLASS3 = createProxyClass(LdapContext.class);
+ private static final Class<?> DECORATOR_CLASS4 = createProxyClass(DirContext.class);
+
+ public void testSimpleDecoratorIdentifiedByClass() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS1);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for Context class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], Context.class);
+ }
+
+ public void testSuperClassDecoratorHasPrecedenceOverSubClassDecorator() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ //this tests that the LdapContext isn't returned even though it subclasses the DirContext
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS2);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for DirContext class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], DirContext.class);
+ }
+
+ public void testSubClassDecoratorCorrectlyIdentified() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> contextDecorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS3);
+ assertEquals(contextDecorators.size(), 1, "Expected exactly one decorator for LdapContext class");
+ assertEquals(contextDecorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ public void testMultipleDecoratorsDetectable() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> decorators = picker.getDecoratorsForClass(TEST_OBJECT_CLASS4);
+ assertEquals(decorators.size(), 2,
+ "Exactly 2 decorators should have been found for a class implementing 2 interfaces.");
+
+ boolean ldapContextDecoratorFound = false;
+ boolean eventContextDecoratorFound = false;
+
+ for (Object d : decorators) {
+ if (LdapContext.class.isAssignableFrom(d.getClass())) {
+ ldapContextDecoratorFound = true;
+ continue; //just to make sure that somehow the decorator doesn't implement both
+ }
+ if (EventContext.class.isAssignableFrom(d.getClass())) {
+ eventContextDecoratorFound = true;
+ }
+ }
+
+ assertTrue(ldapContextDecoratorFound && eventContextDecoratorFound,
+ "The found decorators don't implement the desired interfaces.");
+ }
+
+ public void testDecoratorsIdentifiedByMethod() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ Set<Object> decorators =
+ picker.getDecoratorsForMethod(LdapContext.class.getMethod("getConnectControls", (Class<?>[]) null));
+ assertEquals(decorators.size(), 1,
+ "Expected exactly one decorator for method 'getConnectControls()' from LdapContext class");
+ assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ public void testMethodFromSubclassMatchesSubclassDecorator() throws Exception {
+ DecoratorPicker<Object, Object> picker = createTestPicker();
+
+ //this is a method from the DirContext but we're asking for it from a class
+ //that implements also an LdapContext
+ //The LdapContext decorator also inherits from the DirContext decorator
+ //(by the virtue of LdapContext interface inheriting from the DirContext)
+ //The picker should therefore match the LdapContext decorator because its
+ //the "closest" one to the actual class.
+ Set<Object> decorators =
+ picker.getDecoratorsForMethod(TEST_OBJECT_CLASS3.getMethod("getSchemaClassDefinition",
+ new Class<?>[] { String.class }));
+ assertEquals(decorators.size(), 1,
+ "Expected exactly one decorator for method 'getSchemaClassDefinition(String)' from LdapContext class");
+ assertEquals(decorators.iterator().next().getClass().getInterfaces()[0], LdapContext.class);
+ }
+
+ private static Class<?> createProxyClass(Class<?>... ifaces) {
+ return Proxy.getProxyClass(DecoratorPickerTest.class.getClassLoader(), ifaces);
+ }
+
+ private static DecoratorPicker<Object, Object> createTestPicker() {
+ DecoratorPicker<Object, Object> picker = new DecoratorPicker<Object, Object>();
+
+ DecoratorSetContext<Object, Object> decSet = new DecoratorSetContext<Object, Object>() {
+
+ public Object instantiate(Class<? extends Object> decoratorClass) throws Exception {
+ Constructor<? extends Object> ctor = decoratorClass.getConstructor(InvocationHandler.class);
+ return ctor.newInstance(DUMMY_HANDLER);
+ }
+
+ public void init(Object decorator, Object object) throws Exception {
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<Class<? extends Object>> getSupportedInterfaces() {
+ return new HashSet<Class<? extends Object>>(Arrays.asList(Context.class, EventContext.class,
+ LdapContext.class, DirContext.class));
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set<Class<? extends Object>> getDecoratorClasses() {
+ return new HashSet<Class<? extends Object>>(Arrays.asList(DECORATOR_CLASS1, DECORATOR_CLASS2, DECORATOR_CLASS3, DECORATOR_CLASS4));
+ }
+ };
+
+ picker.setContext(decSet);
+
+ return picker;
+ }
+}
commit d61a7d5a1852c017a75a13636d0f410b6d6a5dd4
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 9 11:07:36 2012 +0100
Add a graph where each days metrics consist of a certain color
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/index.html b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
index 7162c24..80472f6 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/index.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
@@ -29,6 +29,7 @@ an empty database (meaning resource ids and schedule ids starting at 10001).
<li><a href="whisker2.html">Multiple Whisker charts</a></li>
<li><a href="tree.html">Resource tree</a></li>
<li><a href="raw_graph.html">7 days of raw metrics as dot- or line- chart</a></li>
+ <li><a href="raw_graph7.html">7 days of raw metrics as dot- or line- chart - comparing daily values</a></li>
</ul>
</body>
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
new file mode 100644
index 0000000..62b2ec5
--- /dev/null
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph7.html
@@ -0,0 +1,228 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Raw mertic last 7 days</title>
+ <script type="text/javascript" src="js/d3.js"></script>
+ <script type="text/javascript" src="js/d3.layout.js"></script>
+ <script type="text/javascript" src="js/d3.time.js"></script>
+ <script type="text/javascript" src="js/jquery.js"></script>
+ <style type="text/css">
+
+svg {
+ width: 960px;
+ height: 600px;
+ border: solid 1px #ccc;
+ font: 10px sans-serif;
+ shape-rendering: crispEdges;
+}
+.axis text
+{
+ fill: #333;
+ font-family: sans-serif;
+ font-size: 10px;
+}
+.axis .domain
+{
+ opacity: 0;
+}
+.tick
+{
+ stroke: #ccc;
+ stroke-dasharray: 1 5;
+}
+
+path {
+ stroke: steelblue;
+ stroke-width: 2;
+ fill: none;
+}
+
+line {
+ stroke: black;
+}
+
+ </style>
+ </head>
+ <body>
+ <h1 id="resId">Resource</h1>
+ <h2 id="header">Schedule</h2>
+<button id="dotsButton" onClick="transitionDots() ">Dots</button>
+<button id="lineButton" onClick="transitionLine()"/>Lines</button>
+<button id="bothButton" onClick="transitionBoth()"/>Both</button>
+
+ <div id="one"></div>
+ <script type="text/javascript">
+
+// Width and height of the chart to print
+var w = 960,
+ h = 600;
+
+// Get the platforms and then the first one
+$.getJSON('/rest/1/resource/platforms.json', function (json) {
+ var res = json[0];
+ var rid = res.resourceId;
+ $("#resId").text("Resource " + rid + " (" + res.resourceName + ")");
+
+ // Now get the metrical schedules of the platform
+ $.getJSON("/rest/1/resource/"+rid+"/schedules.json?type=metric", function (json2) {
+
+ // Take the first and render it
+ var schId = json2[0].scheduleId;
+ $("#header").text("Schedule " + schId + " (" + json2[0].scheduleName + "), base unit: " + json2[0].unit);
+
+
+// '/rest/1/metric/data/' + schId + '/raw.json?duration=604800',
+ d3.json(
+ '/rest/1/metric/data/' + schId + '/raw.json?duration=604800',
+ function (jsondata) {
+
+
+
+ var w = 960,
+ h = 600;
+ // compute min/max values for x and y a
+ var minVal = d3.min(jsondata,function(d) { return d.value;});
+ var maxVal = d3.max(jsondata,function(d) { return d.value;});
+ var minTsD = 0;
+ var maxTsD = 86400*1000;
+
+ var minTimestamp = d3.min(jsondata,function(d) { return d.timeStamp;});
+
+ var avg = d3.sum(jsondata,function(d) { return d.value;}) / jsondata.length;
+
+
+
+ WIDTH = w;
+ HEIGHT = h;
+ MARGINS = {top: 10, right: 10, bottom: 20, left: 10};
+
+ var xRange = d3.time.scale().range ([MARGINS.left, WIDTH - MARGINS.right]).domain([new Date(minTsD),new Date(maxTsD)]);
+ var yRange = d3.scale.linear().range ([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([minVal, maxVal]);
+
+ // X axis range goes from lowest to highest timestamp
+ var x = d3.time.scale().domain([new Date(0),new Date(86400*1000)]).range([50, w-10]); // 50-> make room for label
+//var x = xRange;
+ var y = yRange;
+ // Y axis range goes from lowest to highest value
+ // var y = d3.scale.linear().domain([minVal, maxVal]).rangeRound([0, h]);
+ format = d3.time.format("%H:%M");
+
+
+ xAxis = d3.svg.axis() // generate an axis
+ .scale(x) // set the range of the axis
+ .tickSize(580) // height of the ticks
+ .tickSubdivide(true); // display ticks between text labels
+ yAxis = d3.svg.axis() // generate an axis
+ .scale(yRange) // set the range of the axis
+ .tickSize(3) // width of the ticks
+ .orient("right") // have the text labels on the right hand side
+ .tickFormat(d3.format("0e"))
+ .tickSubdivide(true); // display ticks between text labels
+
+// create the SVG
+ var svg = d3.select("body").append("svg:svg")
+ .attr("width", w)
+ .attr("height", h);
+
+// Create axes
+ svg.append("svg:g")
+ .attr("class","x axis")
+ .call(xAxis);
+
+ svg.append("svg:g")
+ .attr("class","y axis")
+ .attr("transform", "translate(" + (MARGINS.left) + ",0)")
+ .call(yAxis);
+
+ svg.append("svg:line")
+ .attr("x1","50")
+ .attr("x2","950")
+ .attr("y1",y(avg))
+ .attr("y2",y(avg))
+ .style("stroke","red")
+ .attr("style","stroke-dasharray:2 2; stroke:red")
+ ;
+
+// split the data into 7 data sets (1 per day)
+
+//var dat = d3.split(jsondata,function(d) { return (d.timeStamp-minTimestamp % 86400*1000) < 3*60*0000; });
+
+var colors = ["black","blue","green","cyan","red","orange","yellow"];
+var dat = putToBuckets(jsondata,7);
+
+for (day = 0 ; day < 7 ; day ++ ) {
+ var daydat = dat[day];
+ // Now lets "loop" over the data and show the dots
+ var lines = svg.append("svg:g").attr("class","linechart")
+ .attr("opacity","0");
+;
+ var dayMinTs = d3.min(daydat,function(d) { return d.timeStamp;});
+
+var line = d3.svg.line()
+ .x(function(d,i) { return x(d.timeStamp-dayMinTs); })
+ .y(function(d) { return y(d.value); })
+
+lines.append("svg:path").attr("d", line(daydat)).style("stroke",colors[day]);
+
+
+ var dot = svg.append("svg:g").attr("class","dotschart")
+ .selectAll("dot").data(jsondata)
+
+ dot.enter().append("svg:circle")
+ .attr("cx", function (d) {
+ return x(d.timeStamp-dayMinTs);
+ })
+ .attr("cy", function (d) {
+ return y(d.value);
+ })
+ .style("stroke", colors[day])
+ .attr("r", 1)
+
+}
+ });
+ })
+})
+
+function transitionDots() {
+ $(".linechart").attr("opacity",0);
+ $(".dotschart").attr("opacity",1);
+}
+
+function transitionLine() {
+ $(".linechart").attr("opacity",1);
+ $(".dotschart").attr("opacity",0);
+}
+function transitionBoth() {
+ $(".linechart").attr("opacity",1);
+ $(".dotschart").attr("opacity",1);
+}
+
+// put the data in d into n buckets
+function putToBuckets(data,n) {
+
+ var band = d3.extent(data,function(d){ return d.timeStamp;});
+ var bs = band[1] - band[0];
+// var bs = bs / n;
+ var bs = 86400*1000;
+
+console.log("bs : " + bs );
+console.log("min ts : " + band[0]);
+
+var dat = new Array(n);
+for (i = 0; i < n ; i++ ) {
+ dat[i]=new Array();
+}
+
+data.forEach(function (d) {
+ var diff = d.timeStamp-band[0];
+ var bucket = parseInt(diff / bs);
+console.log(d.timeStamp + ", " + diff + " buck : " + bucket);
+ dat[bucket].push(d);
+});
+
+return dat;
+}
+
+ </script>
+ </body>
+</html>
commit 9ada46462f71b39e160e215fce7b4676e2aadd87
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sun Jan 8 17:15:57 2012 +0100
Allow to also show lines and dots.
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html
index 598a0b8..44c42a5 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html
@@ -46,8 +46,9 @@ line {
<body>
<h1 id="resId">Resource</h1>
<h2 id="header">Schedule</h2>
-<button id="dotsButton" onClick="transitionDots() ">Dots</button>
+<button id="dotsButton" onClick="transitionDots()">Dots</button>
<button id="lineButton" onClick="transitionLine()">Lines</button>
+<button id="bothButton" onClick="transitionBoth()">Both</button>
<div id="one"></div>
<script type="text/javascript">
@@ -174,6 +175,10 @@ function transitionLine() {
$(".linechart").attr("opacity",1);
$(".dotschart").attr("opacity",0);
}
+function transitionBoth() {
+ $(".linechart").attr("opacity",1);
+ $(".dotschart").attr("opacity",1);
+}
</script>
</body>
</html>
commit 3fa0177b1a7c943bd83291f35f4027c128f26984
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Jan 6 14:16:40 2012 +0100
Add an example of graphing raw data with D3.js as dots or lines.
Use D3 helpers for max/min, draw a line for the avg.
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/index.html b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
index 9e96d76..7162c24 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/index.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
@@ -1,7 +1,7 @@
<html>
<body>
<h2>RHQ Rest API</h2>
-<b>Please note: the API is not stable at this point. Do not rely on it.</b><br/>
+<strong>Please note: the API is not stable at this point. Do not rely on it.</strong><br/>
Join us in making it great by providing feedback and contributions of code and examples
that use the api.
@@ -28,6 +28,7 @@ an empty database (meaning resource ids and schedule ids starting at 10001).
<li><a href="whisker.html">Whisker chart 1</a></li>
<li><a href="whisker2.html">Multiple Whisker charts</a></li>
<li><a href="tree.html">Resource tree</a></li>
+ <li><a href="raw_graph.html">7 days of raw metrics as dot- or line- chart</a></li>
</ul>
</body>
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html
new file mode 100644
index 0000000..598a0b8
--- /dev/null
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/raw_graph.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Raw mertic last 7 days</title>
+ <script type="text/javascript" src="js/d3.js"></script>
+ <script type="text/javascript" src="js/d3.layout.js"></script>
+ <script type="text/javascript" src="js/d3.time.js"></script>
+ <script type="text/javascript" src="js/jquery.js"></script>
+ <style type="text/css">
+
+svg {
+ width: 960px;
+ height: 600px;
+ border: solid 1px #ccc;
+ font: 10px sans-serif;
+ shape-rendering: crispEdges;
+}
+.axis text
+{
+ fill: #333;
+ font-family: sans-serif;
+ font-size: 10px;
+}
+.axis .domain
+{
+ opacity: 0;
+}
+.tick
+{
+ stroke: #ccc;
+ stroke-dasharray: 1 5;
+}
+
+path {
+ stroke: steelblue;
+ stroke-width: 2;
+ fill: none;
+}
+
+line {
+ stroke: black;
+}
+
+ </style>
+ </head>
+ <body>
+ <h1 id="resId">Resource</h1>
+ <h2 id="header">Schedule</h2>
+<button id="dotsButton" onClick="transitionDots() ">Dots</button>
+<button id="lineButton" onClick="transitionLine()">Lines</button>
+
+ <div id="one"></div>
+ <script type="text/javascript">
+
+// Width and height of the chart to print
+var w = 960,
+ h = 600;
+
+// Get the platforms and then the first one
+$.getJSON('/rest/1/resource/platforms.json', function (json) {
+ var res = json[0];
+ var rid = res.resourceId;
+ $("#resId").text("Resource " + rid + " (" + res.resourceName + ")");
+
+ // Now get the metrical schedules of the platform
+ $.getJSON("/rest/1/resource/"+rid+"/schedules.json?type=metric", function (json2) {
+
+ // Take the first and render it
+ var schId = json2[0].scheduleId;
+ $("#header").text("Schedule " + schId + " (" + json2[0].scheduleName + "), base unit: " + json2[0].unit);
+
+ d3.json(
+ '/rest/1/metric/data/' + schId + '/raw.json?duration=604800',
+ function (jsondata) {
+
+ var w = 960,
+ h = 600;
+ // compute min/max values for x and y
+ var minVal = d3.min(jsondata,function(d) { return d.value;});
+ var maxVal = d3.max(jsondata,function(d) { return d.value;});
+ var minTsD = d3.min(jsondata,function(d) { return d.timeStamp;});
+ var maxTsD = d3.max(jsondata,function(d) { return d.timeStamp;});
+
+ var avg = d3.sum(jsondata,function(d) { return d.value;}) / jsondata.length;
+
+
+ WIDTH = w;
+ HEIGHT = h;
+ MARGINS = {top: 10, right: 10, bottom: 20, left: 10};
+
+ var xRange = d3.time.scale().range ([MARGINS.left, WIDTH - MARGINS.right]).domain([new Date(minTsD),new Date(maxTsD)]);
+ var yRange = d3.scale.linear().range ([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([minVal, maxVal]);
+
+ // X axis range goes from lowest to highest timestamp
+ var x = d3.time.scale().domain([new Date(minTsD),new Date(maxTsD)]).range([50, w-10]); // 50-> make room for label
+ var y = yRange;
+ // Y axis range goes from lowest to highest value
+ // var y = d3.scale.linear().domain([minVal, maxVal]).rangeRound([0, h]);
+ format = d3.time.format("%H:%M");
+
+
+ xAxis = d3.svg.axis() // generate an axis
+ .scale(x) // set the range of the axis
+ .tickSize(580) // height of the ticks
+ .tickSubdivide(true); // display ticks between text labels
+ yAxis = d3.svg.axis() // generate an axis
+ .scale(yRange) // set the range of the axis
+ .tickSize(3) // width of the ticks
+ .orient("right") // have the text labels on the right hand side
+ .tickFormat(d3.format("0e"))
+ .tickSubdivide(true); // display ticks between text labels
+
+ // create the SVG
+ var svg = d3.select("body").append("svg:svg")
+ .attr("width", w)
+ .attr("height", h);
+
+ // Create axes
+ svg.append("svg:g")
+ .attr("class","x axis")
+ .call(xAxis);
+
+ svg.append("svg:g")
+ .attr("class","y axis")
+ .attr("transform", "translate(" + (MARGINS.left) + ",0)")
+ .call(yAxis);
+
+ // create horizontal line for avg
+ svg.append("svg:line")
+ .attr("x1","50")
+ .attr("x2","950")
+ .attr("y1",y(avg))
+ .attr("y2",y(avg))
+ .style("stroke","red")
+ .attr("style","stroke-dasharray:2 2; stroke:red")
+ ;
+
+
+ // Now lets "loop" over the data and show the dots
+ var lines = svg.append("svg:g").attr("class","linechart")
+ .attr("opacity","0");
+
+ var line = d3.svg.line()
+ .x(function(d,i) { return x(d.timeStamp); })
+ .y(function(d) { return y(d.value); });
+
+ lines.append("svg:path").attr("d", line(jsondata));
+
+
+ var dot = svg.append("svg:g").attr("class","dotschart")
+ .selectAll("dot").data(jsondata);
+
+ dot.enter().append("svg:circle")
+ .attr("cx", function (d) {
+ return x(d.timeStamp);
+ })
+ .attr("cy", function (d) {
+ return y(d.value);
+ })
+ .style("stroke", "blue")
+ .attr("r", 1)
+
+
+ });
+ })
+});
+
+function transitionDots() {
+ $(".linechart").attr("opacity",0);
+ $(".dotschart").attr("opacity",1);
+}
+
+function transitionLine() {
+ $(".linechart").attr("opacity",1);
+ $(".dotschart").attr("opacity",0);
+}
+ </script>
+ </body>
+</html>
commit 625f20d6922eaa4cad999cb583821a90ba9cef44
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Thu Jan 5 22:18:14 2012 +0100
Upgrade D3.js to version 2.7.1
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.csv.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.csv.js
new file mode 100644
index 0000000..7565b83
--- /dev/null
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.csv.js
@@ -0,0 +1,92 @@
+(function(){d3.csv = function(url, callback) {
+ d3.text(url, "text/csv", function(text) {
+ callback(text && d3.csv.parse(text));
+ });
+};
+d3.csv.parse = function(text) {
+ var header;
+ return d3.csv.parseRows(text, function(row, i) {
+ if (i) {
+ var o = {}, j = -1, m = header.length;
+ while (++j < m) o[header[j]] = row[j];
+ return o;
+ } else {
+ header = row;
+ return null;
+ }
+ });
+};
+
+d3.csv.parseRows = function(text, f) {
+ var EOL = {}, // sentinel value for end-of-line
+ EOF = {}, // sentinel value for end-of-file
+ rows = [], // output rows
+ re = /\r\n|[,\r\n]/g, // field separator regex
+ n = 0, // the current line number
+ t, // the current token
+ eol; // is the current token followed by EOL?
+
+ re.lastIndex = 0; // work-around bug in FF 3.6
+
+ /** @private Returns the next token. */
+ function token() {
+ if (re.lastIndex >= text.length) return EOF; // special case: end of file
+ if (eol) { eol = false; return EOL; } // special case: end of line
+
+ // special case: quotes
+ var j = re.lastIndex;
+ if (text.charCodeAt(j) === 34) {
+ var i = j;
+ while (i++ < text.length) {
+ if (text.charCodeAt(i) === 34) {
+ if (text.charCodeAt(i + 1) !== 34) break;
+ i++;
+ }
+ }
+ re.lastIndex = i + 2;
+ var c = text.charCodeAt(i + 1);
+ if (c === 13) {
+ eol = true;
+ if (text.charCodeAt(i + 2) === 10) re.lastIndex++;
+ } else if (c === 10) {
+ eol = true;
+ }
+ return text.substring(j + 1, i).replace(/""/g, "\"");
+ }
+
+ // common case
+ var m = re.exec(text);
+ if (m) {
+ eol = m[0].charCodeAt(0) !== 44;
+ return text.substring(j, m.index);
+ }
+ re.lastIndex = text.length;
+ return text.substring(j);
+ }
+
+ while ((t = token()) !== EOF) {
+ var a = [];
+ while ((t !== EOL) && (t !== EOF)) {
+ a.push(t);
+ t = token();
+ }
+ if (f && !(a = f(a, n++))) continue;
+ rows.push(a);
+ }
+
+ return rows;
+};
+d3.csv.format = function(rows) {
+ return rows.map(d3_csv_formatRow).join("\n");
+};
+
+function d3_csv_formatRow(row) {
+ return row.map(d3_csv_formatValue).join(",");
+}
+
+function d3_csv_formatValue(text) {
+ return /[",\n]/.test(text)
+ ? "\"" + text.replace(/\"/g, "\"\"") + "\""
+ : text;
+}
+})();
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geo.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geo.js
new file mode 100644
index 0000000..2b40252
--- /dev/null
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geo.js
@@ -0,0 +1,938 @@
+(function(){d3.geo = {};
+
+var d3_geo_radians = Math.PI / 180;
+// TODO clip input coordinates on opposite hemisphere
+d3.geo.azimuthal = function() {
+ var mode = "orthographic", // or stereographic, gnomonic, equidistant or equalarea
+ origin,
+ scale = 200,
+ translate = [480, 250],
+ x0,
+ y0,
+ cy0,
+ sy0;
+
+ function azimuthal(coordinates) {
+ var x1 = coordinates[0] * d3_geo_radians - x0,
+ y1 = coordinates[1] * d3_geo_radians,
+ cx1 = Math.cos(x1),
+ sx1 = Math.sin(x1),
+ cy1 = Math.cos(y1),
+ sy1 = Math.sin(y1),
+ cc = mode !== "orthographic" ? sy0 * sy1 + cy0 * cy1 * cx1 : null,
+ c,
+ k = mode === "stereographic" ? 1 / (1 + cc)
+ : mode === "gnomonic" ? 1 / cc
+ : mode === "equidistant" ? (c = Math.acos(cc), c ? c / Math.sin(c) : 0)
+ : mode === "equalarea" ? Math.sqrt(2 / (1 + cc))
+ : 1,
+ x = k * cy1 * sx1,
+ y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
+ return [
+ scale * x + translate[0],
+ scale * y + translate[1]
+ ];
+ }
+
+ azimuthal.invert = function(coordinates) {
+ var x = (coordinates[0] - translate[0]) / scale,
+ y = (coordinates[1] - translate[1]) / scale,
+ p = Math.sqrt(x * x + y * y),
+ c = mode === "stereographic" ? 2 * Math.atan(p)
+ : mode === "gnomonic" ? Math.atan(p)
+ : mode === "equidistant" ? p
+ : mode === "equalarea" ? 2 * Math.asin(.5 * p)
+ : Math.asin(p),
+ sc = Math.sin(c),
+ cc = Math.cos(c);
+ return [
+ (x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_geo_radians,
+ Math.asin(cc * sy0 - (p ? (y * sc * cy0) / p : 0)) / d3_geo_radians
+ ];
+ };
+
+ azimuthal.mode = function(x) {
+ if (!arguments.length) return mode;
+ mode = x + "";
+ return azimuthal;
+ };
+
+ azimuthal.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ x0 = origin[0] * d3_geo_radians;
+ y0 = origin[1] * d3_geo_radians;
+ cy0 = Math.cos(y0);
+ sy0 = Math.sin(y0);
+ return azimuthal;
+ };
+
+ azimuthal.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ return azimuthal;
+ };
+
+ azimuthal.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = [+x[0], +x[1]];
+ return azimuthal;
+ };
+
+ return azimuthal.origin([0, 0]);
+};
+// Derived from Tom Carden's Albers implementation for Protovis.
+// http://gist.github.com/476238
+// http://mathworld.wolfram.com/AlbersEqual-AreaConicProjection.html
+
+d3.geo.albers = function() {
+ var origin = [-98, 38],
+ parallels = [29.5, 45.5],
+ scale = 1000,
+ translate = [480, 250],
+ lng0, // d3_geo_radians * origin[0]
+ n,
+ C,
+ p0;
+
+ function albers(coordinates) {
+ var t = n * (d3_geo_radians * coordinates[0] - lng0),
+ p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n;
+ return [
+ scale * p * Math.sin(t) + translate[0],
+ scale * (p * Math.cos(t) - p0) + translate[1]
+ ];
+ }
+
+ albers.invert = function(coordinates) {
+ var x = (coordinates[0] - translate[0]) / scale,
+ y = (coordinates[1] - translate[1]) / scale,
+ p0y = p0 + y,
+ t = Math.atan2(x, p0y),
+ p = Math.sqrt(x * x + p0y * p0y);
+ return [
+ (lng0 + t / n) / d3_geo_radians,
+ Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians
+ ];
+ };
+
+ function reload() {
+ var phi1 = d3_geo_radians * parallels[0],
+ phi2 = d3_geo_radians * parallels[1],
+ lat0 = d3_geo_radians * origin[1],
+ s = Math.sin(phi1),
+ c = Math.cos(phi1);
+ lng0 = d3_geo_radians * origin[0];
+ n = .5 * (s + Math.sin(phi2));
+ C = c * c + 2 * n * s;
+ p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
+ return albers;
+ }
+
+ albers.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = [+x[0], +x[1]];
+ return reload();
+ };
+
+ albers.parallels = function(x) {
+ if (!arguments.length) return parallels;
+ parallels = [+x[0], +x[1]];
+ return reload();
+ };
+
+ albers.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ return albers;
+ };
+
+ albers.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = [+x[0], +x[1]];
+ return albers;
+ };
+
+ return reload();
+};
+
+// A composite projection for the United States, 960x500. The set of standard
+// parallels for each region comes from USGS, which is published here:
+// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
+// TODO allow the composite projection to be rescaled?
+d3.geo.albersUsa = function() {
+ var lower48 = d3.geo.albers();
+
+ var alaska = d3.geo.albers()
+ .origin([-160, 60])
+ .parallels([55, 65]);
+
+ var hawaii = d3.geo.albers()
+ .origin([-160, 20])
+ .parallels([8, 18]);
+
+ var puertoRico = d3.geo.albers()
+ .origin([-60, 10])
+ .parallels([8, 18]);
+
+ function albersUsa(coordinates) {
+ var lon = coordinates[0],
+ lat = coordinates[1];
+ return (lat > 50 ? alaska
+ : lon < -140 ? hawaii
+ : lat < 21 ? puertoRico
+ : lower48)(coordinates);
+ }
+
+ albersUsa.scale = function(x) {
+ if (!arguments.length) return lower48.scale();
+ lower48.scale(x);
+ alaska.scale(x * .6);
+ hawaii.scale(x);
+ puertoRico.scale(x * 1.5);
+ return albersUsa.translate(lower48.translate());
+ };
+
+ albersUsa.translate = function(x) {
+ if (!arguments.length) return lower48.translate();
+ var dz = lower48.scale() / 1000,
+ dx = x[0],
+ dy = x[1];
+ lower48.translate(x);
+ alaska.translate([dx - 400 * dz, dy + 170 * dz]);
+ hawaii.translate([dx - 190 * dz, dy + 200 * dz]);
+ puertoRico.translate([dx + 580 * dz, dy + 430 * dz]);
+ return albersUsa;
+ };
+
+ return albersUsa.scale(lower48.scale());
+};
+d3.geo.bonne = function() {
+ var scale = 200,
+ translate = [480, 250],
+ x0, // origin longitude in radians
+ y0, // origin latitude in radians
+ y1, // parallel latitude in radians
+ c1; // cot(y1)
+
+ function bonne(coordinates) {
+ var x = coordinates[0] * d3_geo_radians - x0,
+ y = coordinates[1] * d3_geo_radians - y0;
+ if (y1) {
+ var p = c1 + y1 - y, E = x * Math.cos(y) / p;
+ x = p * Math.sin(E);
+ y = p * Math.cos(E) - c1;
+ } else {
+ x *= Math.cos(y);
+ y *= -1;
+ }
+ return [
+ scale * x + translate[0],
+ scale * y + translate[1]
+ ];
+ }
+
+ bonne.invert = function(coordinates) {
+ var x = (coordinates[0] - translate[0]) / scale,
+ y = (coordinates[1] - translate[1]) / scale;
+ if (y1) {
+ var c = c1 + y, p = Math.sqrt(x * x + c * c);
+ y = c1 + y1 - p;
+ x = x0 + p * Math.atan2(x, c) / Math.cos(y);
+ } else {
+ y *= -1;
+ x /= Math.cos(y);
+ }
+ return [
+ x / d3_geo_radians,
+ y / d3_geo_radians
+ ];
+ };
+
+ // 90° for Werner, 0° for Sinusoidal
+ bonne.parallel = function(x) {
+ if (!arguments.length) return y1 / d3_geo_radians;
+ c1 = 1 / Math.tan(y1 = x * d3_geo_radians);
+ return bonne;
+ };
+
+ bonne.origin = function(x) {
+ if (!arguments.length) return [x0 / d3_geo_radians, y0 / d3_geo_radians];
+ x0 = x[0] * d3_geo_radians;
+ y0 = x[1] * d3_geo_radians;
+ return bonne;
+ };
+
+ bonne.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ return bonne;
+ };
+
+ bonne.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = [+x[0], +x[1]];
+ return bonne;
+ };
+
+ return bonne.origin([0, 0]).parallel(45);
+};
+d3.geo.equirectangular = function() {
+ var scale = 500,
+ translate = [480, 250];
+
+ function equirectangular(coordinates) {
+ var x = coordinates[0] / 360,
+ y = -coordinates[1] / 360;
+ return [
+ scale * x + translate[0],
+ scale * y + translate[1]
+ ];
+ }
+
+ equirectangular.invert = function(coordinates) {
+ var x = (coordinates[0] - translate[0]) / scale,
+ y = (coordinates[1] - translate[1]) / scale;
+ return [
+ 360 * x,
+ -360 * y
+ ];
+ };
+
+ equirectangular.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ return equirectangular;
+ };
+
+ equirectangular.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = [+x[0], +x[1]];
+ return equirectangular;
+ };
+
+ return equirectangular;
+};
+d3.geo.mercator = function() {
+ var scale = 500,
+ translate = [480, 250];
+
+ function mercator(coordinates) {
+ var x = coordinates[0] / 360,
+ y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_geo_radians / 2)) / d3_geo_radians) / 360;
+ return [
+ scale * x + translate[0],
+ scale * Math.max(-.5, Math.min(.5, y)) + translate[1]
+ ];
+ }
+
+ mercator.invert = function(coordinates) {
+ var x = (coordinates[0] - translate[0]) / scale,
+ y = (coordinates[1] - translate[1]) / scale;
+ return [
+ 360 * x,
+ 2 * Math.atan(Math.exp(-360 * y * d3_geo_radians)) / d3_geo_radians - 90
+ ];
+ };
+
+ mercator.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = +x;
+ return mercator;
+ };
+
+ mercator.translate = function(x) {
+ if (!arguments.length) return translate;
+ translate = [+x[0], +x[1]];
+ return mercator;
+ };
+
+ return mercator;
+};
+function d3_geo_type(types, defaultValue) {
+ return function(object) {
+ return object && object.type in types ? types[object.type](object) : defaultValue;
+ };
+}
+/**
+ * Returns a function that, given a GeoJSON object (e.g., a feature), returns
+ * the corresponding SVG path. The function can be customized by overriding the
+ * projection. Point features are mapped to circles with a default radius of
+ * 4.5px; the radius can be specified either as a constant or a function that
+ * is evaluated per object.
+ */
+d3.geo.path = function() {
+ var pointRadius = 4.5,
+ pointCircle = d3_path_circle(pointRadius),
+ projection = d3.geo.albersUsa();
+
+ function path(d, i) {
+ if (typeof pointRadius === "function") {
+ pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
+ }
+ return pathType(d) || null;
+ }
+
+ function project(coordinates) {
+ return projection(coordinates).join(",");
+ }
+
+ var pathType = d3_geo_type({
+
+ FeatureCollection: function(o) {
+ var path = [],
+ features = o.features,
+ i = -1, // features.index
+ n = features.length;
+ while (++i < n) path.push(pathType(features[i].geometry));
+ return path.join("");
+ },
+
+ Feature: function(o) {
+ return pathType(o.geometry);
+ },
+
+ Point: function(o) {
+ return "M" + project(o.coordinates) + pointCircle;
+ },
+
+ MultiPoint: function(o) {
+ var path = [],
+ coordinates = o.coordinates,
+ i = -1, // coordinates.index
+ n = coordinates.length;
+ while (++i < n) path.push("M", project(coordinates[i]), pointCircle);
+ return path.join("");
+ },
+
+ LineString: function(o) {
+ var path = ["M"],
+ coordinates = o.coordinates,
+ i = -1, // coordinates.index
+ n = coordinates.length;
+ while (++i < n) path.push(project(coordinates[i]), "L");
+ path.pop();
+ return path.join("");
+ },
+
+ MultiLineString: function(o) {
+ var path = [],
+ coordinates = o.coordinates,
+ i = -1, // coordinates.index
+ n = coordinates.length,
+ subcoordinates, // coordinates[i]
+ j, // subcoordinates.index
+ m; // subcoordinates.length
+ while (++i < n) {
+ subcoordinates = coordinates[i];
+ j = -1;
+ m = subcoordinates.length;
+ path.push("M");
+ while (++j < m) path.push(project(subcoordinates[j]), "L");
+ path.pop();
+ }
+ return path.join("");
+ },
+
+ Polygon: function(o) {
+ var path = [],
+ coordinates = o.coordinates,
+ i = -1, // coordinates.index
+ n = coordinates.length,
+ subcoordinates, // coordinates[i]
+ j, // subcoordinates.index
+ m; // subcoordinates.length
+ while (++i < n) {
+ subcoordinates = coordinates[i];
+ j = -1;
+ if ((m = subcoordinates.length - 1) > 0) {
+ path.push("M");
+ while (++j < m) path.push(project(subcoordinates[j]), "L");
+ path[path.length - 1] = "Z";
+ }
+ }
+ return path.join("");
+ },
+
+ MultiPolygon: function(o) {
+ var path = [],
+ coordinates = o.coordinates,
+ i = -1, // coordinates index
+ n = coordinates.length,
+ subcoordinates, // coordinates[i]
+ j, // subcoordinates index
+ m, // subcoordinates.length
+ subsubcoordinates, // subcoordinates[j]
+ k, // subsubcoordinates index
+ p; // subsubcoordinates.length
+ while (++i < n) {
+ subcoordinates = coordinates[i];
+ j = -1;
+ m = subcoordinates.length;
+ while (++j < m) {
+ subsubcoordinates = subcoordinates[j];
+ k = -1;
+ if ((p = subsubcoordinates.length - 1) > 0) {
+ path.push("M");
+ while (++k < p) path.push(project(subsubcoordinates[k]), "L");
+ path[path.length - 1] = "Z";
+ }
+ }
+ }
+ return path.join("");
+ },
+
+ GeometryCollection: function(o) {
+ var path = [],
+ geometries = o.geometries,
+ i = -1, // geometries index
+ n = geometries.length;
+ while (++i < n) path.push(pathType(geometries[i]));
+ return path.join("");
+ }
+
+ });
+
+ var areaType = path.area = d3_geo_type({
+
+ FeatureCollection: function(o) {
+ var area = 0,
+ features = o.features,
+ i = -1, // features.index
+ n = features.length;
+ while (++i < n) area += areaType(features[i]);
+ return area;
+ },
+
+ Feature: function(o) {
+ return areaType(o.geometry);
+ },
+
+ Polygon: function(o) {
+ return polygonArea(o.coordinates);
+ },
+
+ MultiPolygon: function(o) {
+ var sum = 0,
+ coordinates = o.coordinates,
+ i = -1, // coordinates index
+ n = coordinates.length;
+ while (++i < n) sum += polygonArea(coordinates[i]);
+ return sum;
+ },
+
+ GeometryCollection: function(o) {
+ var sum = 0,
+ geometries = o.geometries,
+ i = -1, // geometries index
+ n = geometries.length;
+ while (++i < n) sum += areaType(geometries[i]);
+ return sum;
+ }
+
+ }, 0);
+
+ function polygonArea(coordinates) {
+ var sum = area(coordinates[0]), // exterior ring
+ i = 0, // coordinates.index
+ n = coordinates.length;
+ while (++i < n) sum -= area(coordinates[i]); // holes
+ return sum;
+ }
+
+ function polygonCentroid(coordinates) {
+ var polygon = d3.geom.polygon(coordinates[0].map(projection)), // exterior ring
+ area = polygon.area(),
+ centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1),
+ x = centroid[0],
+ y = centroid[1],
+ z = area,
+ i = 0, // coordinates index
+ n = coordinates.length;
+ while (++i < n) {
+ polygon = d3.geom.polygon(coordinates[i].map(projection)); // holes
+ area = polygon.area();
+ centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1);
+ x -= centroid[0];
+ y -= centroid[1];
+ z -= area;
+ }
+ return [x, y, 6 * z]; // weighted centroid
+ }
+
+ var centroidType = path.centroid = d3_geo_type({
+
+ // TODO FeatureCollection
+ // TODO Point
+ // TODO MultiPoint
+ // TODO LineString
+ // TODO MultiLineString
+ // TODO GeometryCollection
+
+ Feature: function(o) {
+ return centroidType(o.geometry);
+ },
+
+ Polygon: function(o) {
+ var centroid = polygonCentroid(o.coordinates);
+ return [centroid[0] / centroid[2], centroid[1] / centroid[2]];
+ },
+
+ MultiPolygon: function(o) {
+ var area = 0,
+ coordinates = o.coordinates,
+ centroid,
+ x = 0,
+ y = 0,
+ z = 0,
+ i = -1, // coordinates index
+ n = coordinates.length;
+ while (++i < n) {
+ centroid = polygonCentroid(coordinates[i]);
+ x += centroid[0];
+ y += centroid[1];
+ z += centroid[2];
+ }
+ return [x / z, y / z];
+ }
+
+ });
+
+ function area(coordinates) {
+ return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
+ }
+
+ path.projection = function(x) {
+ projection = x;
+ return path;
+ };
+
+ path.pointRadius = function(x) {
+ if (typeof x === "function") pointRadius = x;
+ else {
+ pointRadius = +x;
+ pointCircle = d3_path_circle(pointRadius);
+ }
+ return path;
+ };
+
+ return path;
+};
+
+function d3_path_circle(radius) {
+ return "m0," + radius
+ + "a" + radius + "," + radius + " 0 1,1 0," + (-2 * radius)
+ + "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius)
+ + "z";
+}
+/**
+ * Given a GeoJSON object, returns the corresponding bounding box. The bounding
+ * box is represented by a two-dimensional array: [[left, bottom], [right,
+ * top]], where left is the minimum longitude, bottom is the minimum latitude,
+ * right is maximum longitude, and top is the maximum latitude.
+ */
+d3.geo.bounds = function(feature) {
+ var left = Infinity,
+ bottom = Infinity,
+ right = -Infinity,
+ top = -Infinity;
+ d3_geo_bounds(feature, function(x, y) {
+ if (x < left) left = x;
+ if (x > right) right = x;
+ if (y < bottom) bottom = y;
+ if (y > top) top = y;
+ });
+ return [[left, bottom], [right, top]];
+};
+
+function d3_geo_bounds(o, f) {
+ if (o.type in d3_geo_boundsTypes) d3_geo_boundsTypes[o.type](o, f);
+}
+
+var d3_geo_boundsTypes = {
+ Feature: d3_geo_boundsFeature,
+ FeatureCollection: d3_geo_boundsFeatureCollection,
+ GeometryCollection: d3_geo_boundsGeometryCollection,
+ LineString: d3_geo_boundsLineString,
+ MultiLineString: d3_geo_boundsMultiLineString,
+ MultiPoint: d3_geo_boundsLineString,
+ MultiPolygon: d3_geo_boundsMultiPolygon,
+ Point: d3_geo_boundsPoint,
+ Polygon: d3_geo_boundsPolygon
+};
+
+function d3_geo_boundsFeature(o, f) {
+ d3_geo_bounds(o.geometry, f);
+}
+
+function d3_geo_boundsFeatureCollection(o, f) {
+ for (var a = o.features, i = 0, n = a.length; i < n; i++) {
+ d3_geo_bounds(a[i].geometry, f);
+ }
+}
+
+function d3_geo_boundsGeometryCollection(o, f) {
+ for (var a = o.geometries, i = 0, n = a.length; i < n; i++) {
+ d3_geo_bounds(a[i], f);
+ }
+}
+
+function d3_geo_boundsLineString(o, f) {
+ for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
+ f.apply(null, a[i]);
+ }
+}
+
+function d3_geo_boundsMultiLineString(o, f) {
+ for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
+ for (var b = a[i], j = 0, m = b.length; j < m; j++) {
+ f.apply(null, b[j]);
+ }
+ }
+}
+
+function d3_geo_boundsMultiPolygon(o, f) {
+ for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
+ for (var b = a[i][0], j = 0, m = b.length; j < m; j++) {
+ f.apply(null, b[j]);
+ }
+ }
+}
+
+function d3_geo_boundsPoint(o, f) {
+ f.apply(null, o.coordinates);
+}
+
+function d3_geo_boundsPolygon(o, f) {
+ for (var a = o.coordinates[0], i = 0, n = a.length; i < n; i++) {
+ f.apply(null, a[i]);
+ }
+}
+// TODO breakAtDateLine?
+
+d3.geo.circle = function() {
+ var origin = [0, 0],
+ degrees = 90 - 1e-2,
+ radians = degrees * d3_geo_radians,
+ arc = d3.geo.greatArc().target(Object);
+
+ function circle() {
+ // TODO render a circle as a Polygon
+ }
+
+ function visible(point) {
+ return arc.distance(point) < radians;
+ }
+
+ circle.clip = function(d) {
+ arc.source(typeof origin === "function" ? origin.apply(this, arguments) : origin);
+ return clipType(d);
+ };
+
+ var clipType = d3_geo_type({
+
+ FeatureCollection: function(o) {
+ var features = o.features.map(clipType).filter(Object);
+ return features && (o = Object.create(o), o.features = features, o);
+ },
+
+ Feature: function(o) {
+ var geometry = clipType(o.geometry);
+ return geometry && (o = Object.create(o), o.geometry = geometry, o);
+ },
+
+ Point: function(o) {
+ return visible(o.coordinates) && o;
+ },
+
+ MultiPoint: function(o) {
+ var coordinates = o.coordinates.filter(visible);
+ return coordinates.length && {
+ type: o.type,
+ coordinates: coordinates
+ };
+ },
+
+ LineString: function(o) {
+ var coordinates = clip(o.coordinates);
+ return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
+ },
+
+ MultiLineString: function(o) {
+ var coordinates = o.coordinates.map(clip).filter(function(d) { return d.length; });
+ return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
+ },
+
+ Polygon: function(o) {
+ var coordinates = o.coordinates.map(clip);
+ return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o);
+ },
+
+ MultiPolygon: function(o) {
+ var coordinates = o.coordinates.map(function(d) { return d.map(clip); }).filter(function(d) { return d[0].length; });
+ return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
+ },
+
+ GeometryCollection: function(o) {
+ var geometries = o.geometries.map(clipType).filter(Object);
+ return geometries.length && (o = Object.create(o), o.geometries = geometries, o);
+ }
+
+ });
+
+ function clip(coordinates) {
+ var i = -1,
+ n = coordinates.length,
+ clipped = [],
+ p0,
+ p1,
+ p2,
+ d0,
+ d1;
+
+ while (++i < n) {
+ d1 = arc.distance(p2 = coordinates[i]);
+ if (d1 < radians) {
+ if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1)));
+ clipped.push(p2);
+ p0 = p1 = null;
+ } else {
+ p1 = p2;
+ if (!p0 && clipped.length) {
+ clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0)));
+ p0 = p1;
+ }
+ }
+ d0 = d1;
+ }
+
+ if (p1 && clipped.length) {
+ d1 = arc.distance(p2 = clipped[0]);
+ clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1)));
+ }
+
+ return resample(clipped);
+ }
+
+ // Resample coordinates, creating great arcs between each.
+ function resample(coordinates) {
+ var i = 0,
+ n = coordinates.length,
+ j,
+ m,
+ resampled = n ? [coordinates[0]] : coordinates,
+ resamples,
+ origin = arc.source();
+
+ while (++i < n) {
+ resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates;
+ for (j = 0, m = resamples.length; ++j < m;) resampled.push(resamples[j]);
+ }
+
+ arc.source(origin);
+ return resampled;
+ }
+
+ circle.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return circle;
+ };
+
+ circle.angle = function(x) {
+ if (!arguments.length) return degrees;
+ radians = (degrees = +x) * d3_geo_radians;
+ return circle;
+ };
+
+ // Precision is specified in degrees.
+ circle.precision = function(x) {
+ if (!arguments.length) return arc.precision();
+ arc.precision(x);
+ return circle;
+ };
+
+ return circle;
+}
+d3.geo.greatArc = function() {
+ var source = d3_geo_greatArcSource,
+ target = d3_geo_greatArcTarget,
+ precision = 6 * d3_geo_radians;
+
+ function greatArc() {
+ var a = typeof source === "function" ? source.apply(this, arguments) : source,
+ b = typeof target === "function" ? target.apply(this, arguments) : target,
+ i = d3_geo_greatArcInterpolate(a, b),
+ dt = precision / i.d,
+ t = 0,
+ coordinates = [a];
+ while ((t += dt) < 1) coordinates.push(i(t));
+ coordinates.push(b);
+ return {
+ type: "LineString",
+ coordinates: coordinates
+ };
+ }
+
+ // Length returned in radians; multiply by radius for distance.
+ greatArc.distance = function() {
+ var a = typeof source === "function" ? source.apply(this, arguments) : source,
+ b = typeof target === "function" ? target.apply(this, arguments) : target;
+ return d3_geo_greatArcInterpolate(a, b).d;
+ };
+
+ greatArc.source = function(x) {
+ if (!arguments.length) return source;
+ source = x;
+ return greatArc;
+ };
+
+ greatArc.target = function(x) {
+ if (!arguments.length) return target;
+ target = x;
+ return greatArc;
+ };
+
+ // Precision is specified in degrees.
+ greatArc.precision = function(x) {
+ if (!arguments.length) return precision / d3_geo_radians;
+ precision = x * d3_geo_radians;
+ return greatArc;
+ };
+
+ return greatArc;
+};
+
+function d3_geo_greatArcSource(d) {
+ return d.source;
+}
+
+function d3_geo_greatArcTarget(d) {
+ return d.target;
+}
+
+function d3_geo_greatArcInterpolate(a, b) {
+ var x0 = a[0] * d3_geo_radians, cx0 = Math.cos(x0), sx0 = Math.sin(x0),
+ y0 = a[1] * d3_geo_radians, cy0 = Math.cos(y0), sy0 = Math.sin(y0),
+ x1 = b[0] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1),
+ y1 = b[1] * d3_geo_radians, cy1 = Math.cos(y1), sy1 = Math.sin(y1),
+ d = interpolate.d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))),
+ sd = Math.sin(d);
+
+ // From http://williams.best.vwh.net/avform.htm#Intermediate
+ function interpolate(t) {
+ var A = Math.sin(d - (t *= d)) / sd,
+ B = Math.sin(t) / sd,
+ x = A * cy0 * cx0 + B * cy1 * cx1,
+ y = A * cy0 * sx0 + B * cy1 * sx1,
+ z = A * sy0 + B * sy1;
+ return [
+ Math.atan2(y, x) / d3_geo_radians,
+ Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians
+ ];
+ }
+
+ return interpolate;
+}
+d3.geo.greatCircle = d3.geo.circle;
+})();
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geom.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geom.js
new file mode 100644
index 0000000..d860c2b
--- /dev/null
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.geom.js
@@ -0,0 +1,835 @@
+(function(){d3.geom = {};
+/**
+ * Computes a contour for a given input grid function using the <a
+ * href="http://en.wikipedia.org/wiki/Marching_squares">marching
+ * squares</a> algorithm. Returns the contour polygon as an array of points.
+ *
+ * @param grid a two-input function(x, y) that returns true for values
+ * inside the contour and false for values outside the contour.
+ * @param start an optional starting point [x, y] on the grid.
+ * @returns polygon [[x1, y1], [x2, y2], …]
+ */
+d3.geom.contour = function(grid, start) {
+ var s = start || d3_geom_contourStart(grid), // starting point
+ c = [], // contour polygon
+ x = s[0], // current x position
+ y = s[1], // current y position
+ dx = 0, // next x direction
+ dy = 0, // next y direction
+ pdx = NaN, // previous x direction
+ pdy = NaN, // previous y direction
+ i = 0;
+
+ do {
+ // determine marching squares index
+ i = 0;
+ if (grid(x-1, y-1)) i += 1;
+ if (grid(x, y-1)) i += 2;
+ if (grid(x-1, y )) i += 4;
+ if (grid(x, y )) i += 8;
+
+ // determine next direction
+ if (i === 6) {
+ dx = pdy === -1 ? -1 : 1;
+ dy = 0;
+ } else if (i === 9) {
+ dx = 0;
+ dy = pdx === 1 ? -1 : 1;
+ } else {
+ dx = d3_geom_contourDx[i];
+ dy = d3_geom_contourDy[i];
+ }
+
+ // update contour polygon
+ if (dx != pdx && dy != pdy) {
+ c.push([x, y]);
+ pdx = dx;
+ pdy = dy;
+ }
+
+ x += dx;
+ y += dy;
+ } while (s[0] != x || s[1] != y);
+
+ return c;
+};
+
+// lookup tables for marching directions
+var d3_geom_contourDx = [1, 0, 1, 1,-1, 0,-1, 1,0, 0,0,0,-1, 0,-1,NaN],
+ d3_geom_contourDy = [0,-1, 0, 0, 0,-1, 0, 0,1,-1,1,1, 0,-1, 0,NaN];
+
+function d3_geom_contourStart(grid) {
+ var x = 0,
+ y = 0;
+
+ // search for a starting point; begin at origin
+ // and proceed along outward-expanding diagonals
+ while (true) {
+ if (grid(x,y)) {
+ return [x,y];
+ }
+ if (x === 0) {
+ x = y + 1;
+ y = 0;
+ } else {
+ x = x - 1;
+ y = y + 1;
+ }
+ }
+}
+/**
+ * Computes the 2D convex hull of a set of points using Graham's scanning
+ * algorithm. The algorithm has been implemented as described in Cormen,
+ * Leiserson, and Rivest's Introduction to Algorithms. The running time of
+ * this algorithm is O(n log n), where n is the number of input points.
+ *
+ * @param vertices [[x1, y1], [x2, y2], …]
+ * @returns polygon [[x1, y1], [x2, y2], …]
+ */
+d3.geom.hull = function(vertices) {
+ if (vertices.length < 3) return [];
+
+ var len = vertices.length,
+ plen = len - 1,
+ points = [],
+ stack = [],
+ i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
+
+ // find the starting ref point: leftmost point with the minimum y coord
+ for (i=1; i<len; ++i) {
+ if (vertices[i][1] < vertices[h][1]) {
+ h = i;
+ } else if (vertices[i][1] == vertices[h][1]) {
+ h = (vertices[i][0] < vertices[h][0] ? i : h);
+ }
+ }
+
+ // calculate polar angles from ref point and sort
+ for (i=0; i<len; ++i) {
+ if (i === h) continue;
+ y1 = vertices[i][1] - vertices[h][1];
+ x1 = vertices[i][0] - vertices[h][0];
+ points.push({angle: Math.atan2(y1, x1), index: i});
+ }
+ points.sort(function(a, b) { return a.angle - b.angle; });
+
+ // toss out duplicate angles
+ a = points[0].angle;
+ v = points[0].index;
+ u = 0;
+ for (i=1; i<plen; ++i) {
+ j = points[i].index;
+ if (a == points[i].angle) {
+ // keep angle for point most distant from the reference
+ x1 = vertices[v][0] - vertices[h][0];
+ y1 = vertices[v][1] - vertices[h][1];
+ x2 = vertices[j][0] - vertices[h][0];
+ y2 = vertices[j][1] - vertices[h][1];
+ if ((x1*x1 + y1*y1) >= (x2*x2 + y2*y2)) {
+ points[i].index = -1;
+ } else {
+ points[u].index = -1;
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ } else {
+ a = points[i].angle;
+ u = i;
+ v = j;
+ }
+ }
+
+ // initialize the stack
+ stack.push(h);
+ for (i=0, j=0; i<2; ++j) {
+ if (points[j].index !== -1) {
+ stack.push(points[j].index);
+ i++;
+ }
+ }
+ sp = stack.length;
+
+ // do graham's scan
+ for (; j<plen; ++j) {
+ if (points[j].index === -1) continue; // skip tossed out points
+ while (!d3_geom_hullCCW(stack[sp-2], stack[sp-1], points[j].index, vertices)) {
+ --sp;
+ }
+ stack[sp++] = points[j].index;
+ }
+
+ // construct the hull
+ var poly = [];
+ for (i=0; i<sp; ++i) {
+ poly.push(vertices[stack[i]]);
+ }
+ return poly;
+}
+
+// are three points in counter-clockwise order?
+function d3_geom_hullCCW(i1, i2, i3, v) {
+ var t, a, b, c, d, e, f;
+ t = v[i1]; a = t[0]; b = t[1];
+ t = v[i2]; c = t[0]; d = t[1];
+ t = v[i3]; e = t[0]; f = t[1];
+ return ((f-b)*(c-a) - (d-b)*(e-a)) > 0;
+}
+// Note: requires coordinates to be counterclockwise and convex!
+d3.geom.polygon = function(coordinates) {
+
+ coordinates.area = function() {
+ var i = 0,
+ n = coordinates.length,
+ a = coordinates[n - 1][0] * coordinates[0][1],
+ b = coordinates[n - 1][1] * coordinates[0][0];
+ while (++i < n) {
+ a += coordinates[i - 1][0] * coordinates[i][1];
+ b += coordinates[i - 1][1] * coordinates[i][0];
+ }
+ return (b - a) * .5;
+ };
+
+ coordinates.centroid = function(k) {
+ var i = -1,
+ n = coordinates.length - 1,
+ x = 0,
+ y = 0,
+ a,
+ b,
+ c;
+ if (!arguments.length) k = -1 / (6 * coordinates.area());
+ while (++i < n) {
+ a = coordinates[i];
+ b = coordinates[i + 1];
+ c = a[0] * b[1] - b[0] * a[1];
+ x += (a[0] + b[0]) * c;
+ y += (a[1] + b[1]) * c;
+ }
+ return [x * k, y * k];
+ };
+
+ // The Sutherland-Hodgman clipping algorithm.
+ coordinates.clip = function(subject) {
+ var input,
+ i = -1,
+ n = coordinates.length,
+ j,
+ m,
+ a = coordinates[n - 1],
+ b,
+ c,
+ d;
+ while (++i < n) {
+ input = subject.slice();
+ subject.length = 0;
+ b = coordinates[i];
+ c = input[(m = input.length) - 1];
+ j = -1;
+ while (++j < m) {
+ d = input[j];
+ if (d3_geom_polygonInside(d, a, b)) {
+ if (!d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ subject.push(d);
+ } else if (d3_geom_polygonInside(c, a, b)) {
+ subject.push(d3_geom_polygonIntersect(c, d, a, b));
+ }
+ c = d;
+ }
+ a = b;
+ }
+ return subject;
+ };
+
+ return coordinates;
+};
+
+function d3_geom_polygonInside(p, a, b) {
+ return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
+}
+
+// Intersect two infinite lines cd and ab.
+function d3_geom_polygonIntersect(c, d, a, b) {
+ var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0],
+ y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1],
+ x13 = x1 - x3,
+ x21 = x2 - x1,
+ x43 = x4 - x3,
+ y13 = y1 - y3,
+ y21 = y2 - y1,
+ y43 = y4 - y3,
+ ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21);
+ return [x1 + ua * x21, y1 + ua * y21];
+}
+// Adapted from Nicolas Garcia Belmonte's JIT implementation:
+// http://blog.thejit.org/2010/02/12/voronoi-tessellation/
+// http://blog.thejit.org/assets/voronoijs/voronoi.js
+// See lib/jit/LICENSE for details.
+
+// Notes:
+//
+// This implementation does not clip the returned polygons, so if you want to
+// clip them to a particular shape you will need to do that either in SVG or by
+// post-processing with d3.geom.polygon's clip method.
+//
+// If any vertices are coincident or have NaN positions, the behavior of this
+// method is undefined. Most likely invalid polygons will be returned. You
+// should filter invalid points, and consolidate coincident points, before
+// computing the tessellation.
+
+/**
+ * @param vertices [[x1, y1], [x2, y2], …]
+ * @returns polygons [[[x1, y1], [x2, y2], …], …]
+ */
+d3.geom.voronoi = function(vertices) {
+ var polygons = vertices.map(function() { return []; });
+
+ d3_voronoi_tessellate(vertices, function(e) {
+ var s1,
+ s2,
+ x1,
+ x2,
+ y1,
+ y2;
+ if (e.a === 1 && e.b >= 0) {
+ s1 = e.ep.r;
+ s2 = e.ep.l;
+ } else {
+ s1 = e.ep.l;
+ s2 = e.ep.r;
+ }
+ if (e.a === 1) {
+ y1 = s1 ? s1.y : -1e6;
+ x1 = e.c - e.b * y1;
+ y2 = s2 ? s2.y : 1e6;
+ x2 = e.c - e.b * y2;
+ } else {
+ x1 = s1 ? s1.x : -1e6;
+ y1 = e.c - e.a * x1;
+ x2 = s2 ? s2.x : 1e6;
+ y2 = e.c - e.a * x2;
+ }
+ var v1 = [x1, y1],
+ v2 = [x2, y2];
+ polygons[e.region.l.index].push(v1, v2);
+ polygons[e.region.r.index].push(v1, v2);
+ });
+
+ // Reconnect the polygon segments into counterclockwise loops.
+ return polygons.map(function(polygon, i) {
+ var cx = vertices[i][0],
+ cy = vertices[i][1];
+ polygon.forEach(function(v) {
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ return polygon.sort(function(a, b) {
+ return a.angle - b.angle;
+ }).filter(function(d, i) {
+ return !i || (d.angle - polygon[i - 1].angle > 1e-10);
+ });
+ });
+};
+
+var d3_voronoi_opposite = {"l": "r", "r": "l"};
+
+function d3_voronoi_tessellate(vertices, callback) {
+
+ var Sites = {
+ list: vertices
+ .map(function(v, i) {
+ return {
+ index: i,
+ x: v[0],
+ y: v[1]
+ };
+ })
+ .sort(function(a, b) {
+ return a.y < b.y ? -1
+ : a.y > b.y ? 1
+ : a.x < b.x ? -1
+ : a.x > b.x ? 1
+ : 0;
+ }),
+ bottomSite: null
+ };
+
+ var EdgeList = {
+ list: [],
+ leftEnd: null,
+ rightEnd: null,
+
+ init: function() {
+ EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
+ EdgeList.leftEnd.r = EdgeList.rightEnd;
+ EdgeList.rightEnd.l = EdgeList.leftEnd;
+ EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
+ },
+
+ createHalfEdge: function(edge, side) {
+ return {
+ edge: edge,
+ side: side,
+ vertex: null,
+ "l": null,
+ "r": null
+ };
+ },
+
+ insert: function(lb, he) {
+ he.l = lb;
+ he.r = lb.r;
+ lb.r.l = he;
+ lb.r = he;
+ },
+
+ leftBound: function(p) {
+ var he = EdgeList.leftEnd;
+ do {
+ he = he.r;
+ } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
+ he = he.l;
+ return he;
+ },
+
+ del: function(he) {
+ he.l.r = he.r;
+ he.r.l = he.l;
+ he.edge = null;
+ },
+
+ right: function(he) {
+ return he.r;
+ },
+
+ left: function(he) {
+ return he.l;
+ },
+
+ leftRegion: function(he) {
+ return he.edge == null
+ ? Sites.bottomSite
+ : he.edge.region[he.side];
+ },
+
+ rightRegion: function(he) {
+ return he.edge == null
+ ? Sites.bottomSite
+ : he.edge.region[d3_voronoi_opposite[he.side]];
+ }
+ };
+
+ var Geom = {
+
+ bisect: function(s1, s2) {
+ var newEdge = {
+ region: {"l": s1, "r": s2},
+ ep: {"l": null, "r": null}
+ };
+
+ var dx = s2.x - s1.x,
+ dy = s2.y - s1.y,
+ adx = dx > 0 ? dx : -dx,
+ ady = dy > 0 ? dy : -dy;
+
+ newEdge.c = s1.x * dx + s1.y * dy
+ + (dx * dx + dy * dy) * .5;
+
+ if (adx > ady) {
+ newEdge.a = 1;
+ newEdge.b = dy / dx;
+ newEdge.c /= dx;
+ } else {
+ newEdge.b = 1;
+ newEdge.a = dx / dy;
+ newEdge.c /= dy;
+ }
+
+ return newEdge;
+ },
+
+ intersect: function(el1, el2) {
+ var e1 = el1.edge,
+ e2 = el2.edge;
+ if (!e1 || !e2 || (e1.region.r == e2.region.r)) {
+ return null;
+ }
+ var d = (e1.a * e2.b) - (e1.b * e2.a);
+ if (Math.abs(d) < 1e-10) {
+ return null;
+ }
+ var xint = (e1.c * e2.b - e2.c * e1.b) / d,
+ yint = (e2.c * e1.a - e1.c * e2.a) / d,
+ e1r = e1.region.r,
+ e2r = e2.region.r,
+ el,
+ e;
+ if ((e1r.y < e2r.y) ||
+ (e1r.y == e2r.y && e1r.x < e2r.x)) {
+ el = el1;
+ e = e1;
+ } else {
+ el = el2;
+ e = e2;
+ }
+ var rightOfSite = (xint >= e.region.r.x);
+ if ((rightOfSite && (el.side === "l")) ||
+ (!rightOfSite && (el.side === "r"))) {
+ return null;
+ }
+ return {
+ x: xint,
+ y: yint
+ };
+ },
+
+ rightOf: function(he, p) {
+ var e = he.edge,
+ topsite = e.region.r,
+ rightOfSite = (p.x > topsite.x);
+
+ if (rightOfSite && (he.side === "l")) {
+ return 1;
+ }
+ if (!rightOfSite && (he.side === "r")) {
+ return 0;
+ }
+ if (e.a === 1) {
+ var dyp = p.y - topsite.y,
+ dxp = p.x - topsite.x,
+ fast = 0,
+ above = 0;
+
+ if ((!rightOfSite && (e.b < 0)) ||
+ (rightOfSite && (e.b >= 0))) {
+ above = fast = (dyp >= e.b * dxp);
+ } else {
+ above = ((p.x + p.y * e.b) > e.c);
+ if (e.b < 0) {
+ above = !above;
+ }
+ if (!above) {
+ fast = 1;
+ }
+ }
+ if (!fast) {
+ var dxs = topsite.x - e.region.l.x;
+ above = (e.b * (dxp * dxp - dyp * dyp)) <
+ (dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b));
+
+ if (e.b < 0) {
+ above = !above;
+ }
+ }
+ } else /* e.b == 1 */ {
+ var yl = e.c - e.a * p.x,
+ t1 = p.y - yl,
+ t2 = p.x - topsite.x,
+ t3 = yl - topsite.y;
+
+ above = (t1 * t1) > (t2 * t2 + t3 * t3);
+ }
+ return he.side === "l" ? above : !above;
+ },
+
+ endPoint: function(edge, side, site) {
+ edge.ep[side] = site;
+ if (!edge.ep[d3_voronoi_opposite[side]]) return;
+ callback(edge);
+ },
+
+ distance: function(s, t) {
+ var dx = s.x - t.x,
+ dy = s.y - t.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ };
+
+ var EventQueue = {
+ list: [],
+
+ insert: function(he, site, offset) {
+ he.vertex = site;
+ he.ystar = site.y + offset;
+ for (var i=0, list=EventQueue.list, l=list.length; i<l; i++) {
+ var next = list[i];
+ if (he.ystar > next.ystar ||
+ (he.ystar == next.ystar &&
+ site.x > next.vertex.x)) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ list.splice(i, 0, he);
+ },
+
+ del: function(he) {
+ for (var i=0, ls=EventQueue.list, l=ls.length; i<l && (ls[i] != he); ++i) {}
+ ls.splice(i, 1);
+ },
+
+ empty: function() { return EventQueue.list.length === 0; },
+
+ nextEvent: function(he) {
+ for (var i=0, ls=EventQueue.list, l=ls.length; i<l; ++i) {
+ if (ls[i] == he) return ls[i+1];
+ }
+ return null;
+ },
+
+ min: function() {
+ var elem = EventQueue.list[0];
+ return {
+ x: elem.vertex.x,
+ y: elem.ystar
+ };
+ },
+
+ extractMin: function() {
+ return EventQueue.list.shift();
+ }
+ };
+
+ EdgeList.init();
+ Sites.bottomSite = Sites.list.shift();
+
+ var newSite = Sites.list.shift(), newIntStar;
+ var lbnd, rbnd, llbnd, rrbnd, bisector;
+ var bot, top, temp, p, v;
+ var e, pm;
+
+ while (true) {
+ if (!EventQueue.empty()) {
+ newIntStar = EventQueue.min();
+ }
+ if (newSite && (EventQueue.empty()
+ || newSite.y < newIntStar.y
+ || (newSite.y == newIntStar.y
+ && newSite.x < newIntStar.x))) { //new site is smallest
+ lbnd = EdgeList.leftBound(newSite);
+ rbnd = EdgeList.right(lbnd);
+ bot = EdgeList.rightRegion(lbnd);
+ e = Geom.bisect(bot, newSite);
+ bisector = EdgeList.createHalfEdge(e, "l");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(lbnd, bisector);
+ if (p) {
+ EventQueue.del(lbnd);
+ EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
+ }
+ lbnd = bisector;
+ bisector = EdgeList.createHalfEdge(e, "r");
+ EdgeList.insert(lbnd, bisector);
+ p = Geom.intersect(bisector, rbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, newSite));
+ }
+ newSite = Sites.list.shift();
+ } else if (!EventQueue.empty()) { //intersection is smallest
+ lbnd = EventQueue.extractMin();
+ llbnd = EdgeList.left(lbnd);
+ rbnd = EdgeList.right(lbnd);
+ rrbnd = EdgeList.right(rbnd);
+ bot = EdgeList.leftRegion(lbnd);
+ top = EdgeList.rightRegion(rbnd);
+ v = lbnd.vertex;
+ Geom.endPoint(lbnd.edge, lbnd.side, v);
+ Geom.endPoint(rbnd.edge, rbnd.side, v);
+ EdgeList.del(lbnd);
+ EventQueue.del(rbnd);
+ EdgeList.del(rbnd);
+ pm = "l";
+ if (bot.y > top.y) {
+ temp = bot;
+ bot = top;
+ top = temp;
+ pm = "r";
+ }
+ e = Geom.bisect(bot, top);
+ bisector = EdgeList.createHalfEdge(e, pm);
+ EdgeList.insert(llbnd, bisector);
+ Geom.endPoint(e, d3_voronoi_opposite[pm], v);
+ p = Geom.intersect(llbnd, bisector);
+ if (p) {
+ EventQueue.del(llbnd);
+ EventQueue.insert(llbnd, p, Geom.distance(p, bot));
+ }
+ p = Geom.intersect(bisector, rrbnd);
+ if (p) {
+ EventQueue.insert(bisector, p, Geom.distance(p, bot));
+ }
+ } else {
+ break;
+ }
+ }//end while
+
+ for (lbnd = EdgeList.right(EdgeList.leftEnd);
+ lbnd != EdgeList.rightEnd;
+ lbnd = EdgeList.right(lbnd)) {
+ callback(lbnd.edge);
+ }
+}
+/**
+* @param vertices [[x1, y1], [x2, y2], …]
+* @returns triangles [[[x1, y1], [x2, y2], [x3, y3]], …]
+ */
+d3.geom.delaunay = function(vertices) {
+ var edges = vertices.map(function() { return []; }),
+ triangles = [];
+
+ // Use the Voronoi tessellation to determine Delaunay edges.
+ d3_voronoi_tessellate(vertices, function(e) {
+ edges[e.region.l.index].push(vertices[e.region.r.index]);
+ });
+
+ // Reconnect the edges into counterclockwise triangles.
+ edges.forEach(function(edge, i) {
+ var v = vertices[i],
+ cx = v[0],
+ cy = v[1];
+ edge.forEach(function(v) {
+ v.angle = Math.atan2(v[0] - cx, v[1] - cy);
+ });
+ edge.sort(function(a, b) {
+ return a.angle - b.angle;
+ });
+ for (var j = 0, m = edge.length - 1; j < m; j++) {
+ triangles.push([v, edge[j], edge[j + 1]]);
+ }
+ });
+
+ return triangles;
+};
+// Constructs a new quadtree for the specified array of points. A quadtree is a
+// two-dimensional recursive spatial subdivision. This implementation uses
+// square partitions, dividing each square into four equally-sized squares. Each
+// point exists in a unique node; if multiple points are in the same position,
+// some points may be stored on internal nodes rather than leaf nodes. Quadtrees
+// can be used to accelerate various spatial operations, such as the Barnes-Hut
+// approximation for computing n-body forces, or collision detection.
+d3.geom.quadtree = function(points, x1, y1, x2, y2) {
+ var p,
+ i = -1,
+ n = points.length;
+
+ // Type conversion for deprecated API.
+ if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint);
+
+ // Allow bounds to be specified explicitly.
+ if (arguments.length < 5) {
+ if (arguments.length === 3) {
+ y2 = x2 = y1;
+ y1 = x1;
+ } else {
+ x1 = y1 = Infinity;
+ x2 = y2 = -Infinity;
+
+ // Compute bounds.
+ while (++i < n) {
+ p = points[i];
+ if (p.x < x1) x1 = p.x;
+ if (p.y < y1) y1 = p.y;
+ if (p.x > x2) x2 = p.x;
+ if (p.y > y2) y2 = p.y;
+ }
+
+ // Squarify the bounds.
+ var dx = x2 - x1,
+ dy = y2 - y1;
+ if (dx > dy) y2 = y1 + dx;
+ else x2 = x1 + dy;
+ }
+ }
+
+ // Recursively inserts the specified point p at the node n or one of its
+ // descendants. The bounds are defined by [x1, x2] and [y1, y2].
+ function insert(n, p, x1, y1, x2, y2) {
+ if (isNaN(p.x) || isNaN(p.y)) return; // ignore invalid points
+ if (n.leaf) {
+ var v = n.point;
+ if (v) {
+ // If the point at this leaf node is at the same position as the new
+ // point we are adding, we leave the point associated with the
+ // internal node while adding the new point to a child node. This
+ // avoids infinite recursion.
+ if ((Math.abs(v.x - p.x) + Math.abs(v.y - p.y)) < .01) {
+ insertChild(n, p, x1, y1, x2, y2);
+ } else {
+ n.point = null;
+ insertChild(n, v, x1, y1, x2, y2);
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ } else {
+ n.point = p;
+ }
+ } else {
+ insertChild(n, p, x1, y1, x2, y2);
+ }
+ }
+
+ // Recursively inserts the specified point p into a descendant of node n. The
+ // bounds are defined by [x1, x2] and [y1, y2].
+ function insertChild(n, p, x1, y1, x2, y2) {
+ // Compute the split point, and the quadrant in which to insert p.
+ var sx = (x1 + x2) * .5,
+ sy = (y1 + y2) * .5,
+ right = p.x >= sx,
+ bottom = p.y >= sy,
+ i = (bottom << 1) + right;
+
+ // Recursively insert into the child node.
+ n.leaf = false;
+ n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
+
+ // Update the bounds as we recurse.
+ if (right) x1 = sx; else x2 = sx;
+ if (bottom) y1 = sy; else y2 = sy;
+ insert(n, p, x1, y1, x2, y2);
+ }
+
+ // Create the root node.
+ var root = d3_geom_quadtreeNode();
+
+ root.add = function(p) {
+ insert(root, p, x1, y1, x2, y2);
+ };
+
+ root.visit = function(f) {
+ d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
+ };
+
+ // Insert all points.
+ points.forEach(root.add);
+ return root;
+};
+
+function d3_geom_quadtreeNode() {
+ return {
+ leaf: true,
+ nodes: [],
+ point: null
+ };
+}
+
+function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
+ if (!f(node, x1, y1, x2, y2)) {
+ var sx = (x1 + x2) * .5,
+ sy = (y1 + y2) * .5,
+ children = node.nodes;
+ if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
+ if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
+ if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
+ if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
+ }
+}
+
+function d3_geom_quadtreePoint(p) {
+ return {
+ x: p[0],
+ y: p[1]
+ };
+}
+})();
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.js
index bfbc7ee..77ee372 100755
--- a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.js
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.js
@@ -1,22 +1,26 @@
-(function(){d3 = {version: "1.29.1"}; // semver
-if (!Date.now) Date.now = function() {
+(function(){if (!Date.now) Date.now = function() {
return +new Date;
};
-if (!Object.create) Object.create = function(o) {
- /** @constructor */ function f() {}
- f.prototype = o;
- return new f;
-};
+try {
+ document.createElement("div").style.setProperty("opacity", 0, "");
+} catch (error) {
+ var d3_style_prototype = CSSStyleDeclaration.prototype,
+ d3_style_setProperty = d3_style_prototype.setProperty;
+ d3_style_prototype.setProperty = function(name, value, priority) {
+ d3_style_setProperty.call(this, name, value + "", priority);
+ };
+}
+d3 = {version: "2.7.1"}; // semver
var d3_array = d3_arraySlice; // conversion for NodeLists
-function d3_arrayCopy(psuedoarray) {
- var i = -1, n = psuedoarray.length, array = [];
- while (++i < n) array.push(psuedoarray[i]);
+function d3_arrayCopy(pseudoarray) {
+ var i = -1, n = pseudoarray.length, array = [];
+ while (++i < n) array.push(pseudoarray[i]);
return array;
}
-function d3_arraySlice(psuedoarray) {
- return Array.prototype.slice.call(psuedoarray);
+function d3_arraySlice(pseudoarray) {
+ return Array.prototype.slice.call(pseudoarray);
}
try {
@@ -24,21 +28,63 @@ try {
} catch(e) {
d3_array = d3_arrayCopy;
}
+
+var d3_arraySubclass = [].__proto__?
+
+// Until ECMAScript supports array subclassing, prototype injection works well.
+function(array, prototype) {
+ array.__proto__ = prototype;
+}:
+
+// And if your browser doesn't support __proto__, we'll use direct extension.
+function(array, prototype) {
+ for (var property in prototype) array[property] = prototype[property];
+};
+function d3_this() {
+ return this;
+}
d3.functor = function(v) {
return typeof v === "function" ? v : function() { return v; };
};
-// A getter-setter method that preserves the appropriate `this` context.
-d3.rebind = function(object, method) {
+// Copies a variable number of methods from source to target.
+d3.rebind = function(target, source) {
+ var i = 1, n = arguments.length, method;
+ while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
+ return target;
+};
+
+// Method is assumed to be a standard D3 getter-setter:
+// If passed with no arguments, gets the value.
+// If passed with arguments, sets the value and returns the target.
+function d3_rebind(target, source, method) {
return function() {
- var x = method.apply(object, arguments);
- return arguments.length ? object : x;
+ var value = method.apply(source, arguments);
+ return arguments.length ? target : value;
};
-};
+}
d3.ascending = function(a, b) {
- return a < b ? -1 : a > b ? 1 : 0;
+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
};
d3.descending = function(a, b) {
- return b < a ? -1 : b > a ? 1 : 0;
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
+};
+d3.mean = function(array, f) {
+ var n = array.length,
+ a,
+ m = 0,
+ i = -1,
+ j = 0;
+ if (arguments.length === 1) {
+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
+ } else {
+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
+ }
+ return j ? m : undefined;
+};
+d3.median = function(array, f) {
+ if (arguments.length > 1) array = array.map(f);
+ array = array.filter(d3_number);
+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
};
d3.min = function(array, f) {
var i = -1,
@@ -68,6 +114,45 @@ d3.max = function(array, f) {
}
return a;
};
+d3.extent = function(array, f) {
+ var i = -1,
+ n = array.length,
+ a,
+ b,
+ c;
+ if (arguments.length === 1) {
+ while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
+ while (++i < n) if ((b = array[i]) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ } else {
+ while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
+ if (a > b) a = b;
+ if (c < b) c = b;
+ }
+ }
+ return [a, c];
+};
+d3.random = {
+ normal: function(mean, deviation) {
+ if (arguments.length < 2) deviation = 1;
+ if (arguments.length < 1) mean = 0;
+ return function() {
+ var x, y, r;
+ do {
+ x = Math.random() * 2 - 1;
+ y = Math.random() * 2 - 1;
+ r = x * x + y * y;
+ } while (!r || r > 1);
+ return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r);
+ };
+ }
+};
+function d3_number(x) {
+ return x != null && !isNaN(x);
+}
d3.sum = function(array, f) {
var s = 0,
n = array.length,
@@ -90,6 +175,9 @@ d3.quantile = function(values, p) {
e = H - h;
return e ? v + e * (values[h] - v) : v;
};
+d3.transpose = function(matrix) {
+ return d3.zip.apply(d3, matrix);
+};
d3.zip = function() {
if (!(n = arguments.length)) return [];
for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) {
@@ -303,27 +391,19 @@ function d3_splitter(d) {
function d3_collapse(s) {
return s.replace(/(^\s+)|(\s+$)/g, "").replace(/\s+/g, " ");
}
-//
-// Note: assigning to the arguments array simultaneously changes the value of
-// the corresponding argument!
-//
-// TODO The `this` argument probably shouldn't be the first argument to the
-// callback, anyway, since it's redundant. However, that will require a major
-// version bump due to backwards compatibility, so I'm not changing it right
-// away.
-//
-function d3_call(callback) {
- callback.apply(this, (arguments[0] = this, arguments));
- return this;
-}
/**
* @param {number} start
* @param {number=} stop
* @param {number=} step
*/
d3.range = function(start, stop, step) {
- if (arguments.length === 1) { stop = start; start = 0; }
- if (step == null) step = 1;
+ if (arguments.length < 3) {
+ step = 1;
+ if (arguments.length < 2) {
+ stop = start;
+ start = 0;
+ }
+ }
if ((stop - start) / step == Infinity) throw new Error("infinite range");
var range = [],
i = -1,
@@ -336,7 +416,7 @@ d3.requote = function(s) {
return s.replace(d3_requote_re, "\\$&");
};
-var d3_requote_re = /[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g;
+var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
d3.round = function(x, n) {
return n
? Math.round(x * Math.pow(10, n)) * Math.pow(10, -n)
@@ -344,9 +424,10 @@ d3.round = function(x, n) {
};
d3.xhr = function(url, mime, callback) {
var req = new XMLHttpRequest;
- if (arguments.length < 3) callback = mime;
+ if (arguments.length < 3) callback = mime, mime = null;
else if (mime && req.overrideMimeType) req.overrideMimeType(mime);
req.open("GET", url, true);
+ if (mime) req.setRequestHeader("Accept", mime);
req.onreadystatechange = function() {
if (req.readyState === 4) callback(req.status < 300 ? req : null);
};
@@ -387,66 +468,79 @@ d3.xml = function(url, mime, callback) {
}
d3.xhr(url, mime, ready);
};
-d3.ns = {
-
- prefix: {
- svg: "http://www.w3.org/2000/svg",
- xhtml: "http://www.w3.org/1999/xhtml",
- xlink: "http://www.w3.org/1999/xlink",
- xml: "http://www.w3.org/XML/1998/namespace",
- xmlns: "http://www.w3.org/2000/xmlns/"
- },
+var d3_nsPrefix = {
+ svg: "http://www.w3.org/2000/svg",
+ xhtml: "http://www.w3.org/1999/xhtml",
+ xlink: "http://www.w3.org/1999/xlink",
+ xml: "http://www.w3.org/XML/1998/namespace",
+ xmlns: "http://www.w3.org/2000/xmlns/"
+};
+d3.ns = {
+ prefix: d3_nsPrefix,
qualify: function(name) {
var i = name.indexOf(":");
- return i < 0 ? name : {
- space: d3.ns.prefix[name.substring(0, i)],
- local: name.substring(i + 1)
- };
+ return i < 0 ? (name in d3_nsPrefix
+ ? {space: d3_nsPrefix[name], local: name} : name)
+ : {space: d3_nsPrefix[name.substring(0, i)], local: name.substring(i + 1)};
}
-
};
-/** @param {...string} types */
-d3.dispatch = function(types) {
- var dispatch = {},
- type;
- for (var i = 0, n = arguments.length; i < n; i++) {
- type = arguments[i];
- dispatch[type] = d3_dispatch(type);
- }
+d3.dispatch = function() {
+ var dispatch = new d3_dispatch(),
+ i = -1,
+ n = arguments.length;
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event();
return dispatch;
};
-function d3_dispatch(type) {
- var dispatch = {},
- listeners = [];
+function d3_dispatch() {}
- dispatch.add = function(listener) {
- for (var i = 0; i < listeners.length; i++) {
- if (listeners[i].listener == listener) return dispatch; // already registered
- }
- listeners.push({listener: listener, on: true});
- return dispatch;
- };
+d3_dispatch.prototype.on = function(type, listener) {
+ var i = type.indexOf("."),
+ name = "";
- dispatch.remove = function(listener) {
- for (var i = 0; i < listeners.length; i++) {
- var l = listeners[i];
- if (l.listener == listener) {
- l.on = false;
- listeners = listeners.slice(0, i).concat(listeners.slice(i + 1));
- break;
- }
+ // Extract optional namespace, e.g., "click.foo"
+ if (i > 0) {
+ name = type.substring(i + 1);
+ type = type.substring(0, i);
+ }
+
+ return arguments.length < 2
+ ? this[type].on(name)
+ : (this[type].on(name, listener), this);
+};
+
+function d3_dispatch_event() {
+ var listeners = [],
+ listenerByName = {};
+
+ function dispatch() {
+ var z = listeners, // defensive reference
+ i = -1,
+ n = z.length,
+ l;
+ while (++i < n) if (l = z[i].on) l.apply(this, arguments);
+ }
+
+ dispatch.on = function(name, listener) {
+ var l, i;
+
+ // return the current listener, if any
+ if (arguments.length < 2) return (l = listenerByName[name]) && l.on;
+
+ // remove the old listener, if any (with copy-on-write)
+ if (l = listenerByName[name]) {
+ l.on = null;
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
+ delete listenerByName[name];
}
- return dispatch;
- };
- dispatch.dispatch = function() {
- var ls = listeners; // defensive reference
- for (var i = 0, n = ls.length; i < n; i++) {
- var l = ls[i];
- if (l.on) l.listener.apply(this, arguments);
+ // add the new listener, if any
+ if (listener) {
+ listeners.push(listenerByName[name] = {on: listener});
}
+
+ return dispatch;
};
return dispatch;
@@ -461,10 +555,11 @@ d3.format = function(specifier) {
comma = match[7],
precision = match[8],
type = match[9],
- percentage = false,
+ scale = 1,
+ suffix = "",
integer = false;
- if (precision) precision = precision.substring(1);
+ if (precision) precision = +precision.substring(1);
if (zfill) {
fill = "0"; // TODO align = "=";
@@ -473,22 +568,36 @@ d3.format = function(specifier) {
switch (type) {
case "n": comma = true; type = "g"; break;
- case "%": percentage = true; type = "f"; break;
- case "p": percentage = true; type = "r"; break;
- case "d": integer = true; precision = "0"; break;
+ case "%": scale = 100; suffix = "%"; type = "f"; break;
+ case "p": scale = 100; suffix = "%"; type = "r"; break;
+ case "d": integer = true; precision = 0; break;
+ case "s": scale = -1; type = "r"; break;
}
+ // If no precision is specified for r, fallback to general notation.
+ if (type == "r" && !precision) type = "g";
+
type = d3_format_types[type] || d3_format_typeDefault;
return function(value) {
- var number = percentage ? value * 100 : +value,
- negative = (number < 0) && (number = -number) ? "\u2212" : sign;
// Return the empty string for floats formatted as ints.
- if (integer && (number % 1)) return "";
+ if (integer && (value % 1)) return "";
+
+ // Convert negative to positive, and record the sign prefix.
+ var negative = (value < 0) && (value = -value) ? "\u2212" : sign;
- // Convert the input value to the desired precision.
- value = type(number, precision);
+ // Apply the scale, computing it from the value's exponent for si format.
+ if (scale < 0) {
+ var prefix = d3.formatPrefix(value, precision);
+ value *= prefix.scale;
+ suffix = prefix.symbol;
+ } else {
+ value *= scale;
+ }
+
+ // Convert to the desired precision.
+ value = type(value, precision);
// If the fill character is 0, the sign and group is applied after the fill.
if (zfill) {
@@ -505,9 +614,8 @@ d3.format = function(specifier) {
var length = value.length;
if (length < width) value = new Array(width - length + 1).join(fill) + value;
}
- if (percentage) value += "%";
- return value;
+ return value + suffix;
};
};
@@ -518,12 +626,13 @@ var d3_format_types = {
g: function(x, p) { return x.toPrecision(p); },
e: function(x, p) { return x.toExponential(p); },
f: function(x, p) { return x.toFixed(p); },
- r: function(x, p) {
- var n = 1 + Math.floor(1e-15 + Math.log(x) / Math.LN10);
- return d3.round(x, p - n).toFixed(Math.max(0, p - n));
- }
+ r: function(x, p) { return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); }
};
+function d3_format_precision(x, p) {
+ return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
+}
+
function d3_format_typeDefault(x) {
return x + "";
}
@@ -536,6 +645,26 @@ function d3_format_group(value) {
while (i > 0) t.push(value.substring(i -= 3, i + 3));
return t.reverse().join(",") + f;
}
+var d3_formatPrefixes = ["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(d3_formatPrefix);
+
+d3.formatPrefix = function(value, precision) {
+ var i = 0;
+ if (value) {
+ if (value < 0) value *= -1;
+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
+ i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
+ }
+ return d3_formatPrefixes[8 + i / 3];
+};
+
+function d3_formatPrefix(d, i) {
+ return {
+ scale: Math.pow(10, (8 - i) * 3),
+ symbol: d
+ };
+}
+
/*
* TERMS OF USE - EASING EQUATIONS
*
@@ -598,9 +727,15 @@ d3.ease = function(name) {
var i = name.indexOf("-"),
t = i >= 0 ? name.substring(0, i) : name,
m = i >= 0 ? name.substring(i + 1) : "in";
- return d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1)));
+ return d3_ease_clamp(d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1))));
};
+function d3_ease_clamp(f) {
+ return function(t) {
+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
+ };
+}
+
function d3_ease_reverse(f) {
return function(t) {
return 1 - f(1 - t);
@@ -628,7 +763,7 @@ function d3_ease_sin(t) {
}
function d3_ease_exp(t) {
- return t ? Math.pow(2, 10 * (t - 1)) - 1e-3 : 0;
+ return Math.pow(2, 10 * (t - 1));
}
function d3_ease_circle(t) {
@@ -659,6 +794,11 @@ function d3_ease_bounce(t) {
: 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
}
d3.event = null;
+
+function d3_eventCancel() {
+ d3.event.stopPropagation();
+ d3.event.preventDefault();
+}
d3.interpolate = function(a, b) {
var i = d3.interpolators.length, f;
while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
@@ -753,6 +893,10 @@ d3.interpolateString = function(a, b) {
};
};
+d3.interpolateTransform = function(a, b) {
+ return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
+};
+
d3.interpolateRgb = function(a, b) {
a = d3.rgb(a);
b = d3.rgb(b);
@@ -763,10 +907,10 @@ d3.interpolateRgb = function(a, b) {
bg = b.g - ag,
bb = b.b - ab;
return function(t) {
- return "rgb(" + Math.round(ar + br * t)
- + "," + Math.round(ag + bg * t)
- + "," + Math.round(ab + bb * t)
- + ")";
+ return "#"
+ + d3_rgb_hex(Math.round(ar + br * t))
+ + d3_rgb_hex(Math.round(ag + bg * t))
+ + d3_rgb_hex(Math.round(ab + bb * t));
};
};
@@ -823,34 +967,34 @@ d3.interpolateObject = function(a, b) {
};
}
-var d3_interpolate_number = /[-+]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][-]?\d+)?/g,
- d3_interpolate_rgb = {background: 1, fill: 1, stroke: 1};
+var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;
function d3_interpolateByName(n) {
- return n in d3_interpolate_rgb || /\bcolor\b/.test(n)
- ? d3.interpolateRgb
+ return n == "transform"
+ ? d3.interpolateTransform
: d3.interpolate;
}
d3.interpolators = [
d3.interpolateObject,
function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
- function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
- function(a, b) { return (b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b)) && d3.interpolateRgb(String(a), b); },
- function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
+ function(a, b) { return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); },
+ function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a, b); },
+ function(a, b) { return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); }
];
function d3_uninterpolateNumber(a, b) {
- b = 1 / (b - (a = +a));
+ b = b - (a = +a) ? 1 / (b - a) : 0;
return function(x) { return (x - a) * b; };
}
function d3_uninterpolateClamp(a, b) {
- b = 1 / (b - (a = +a));
+ b = b - (a = +a) ? 1 / (b - a) : 0;
return function(x) { return Math.max(0, Math.min(1, (x - a) * b)); };
}
d3.rgb = function(r, g, b) {
return arguments.length === 1
- ? d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb)
+ ? (r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b)
+ : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb))
: d3_rgb(~~r, ~~g, ~~b);
};
@@ -875,17 +1019,17 @@ d3_Rgb.prototype.brighter = function(k) {
if (g && g < i) g = i;
if (b && b < i) b = i;
return d3_rgb(
- Math.min(255, Math.floor(r / k)),
- Math.min(255, Math.floor(g / k)),
- Math.min(255, Math.floor(b / k)));
+ Math.min(255, Math.floor(r / k)),
+ Math.min(255, Math.floor(g / k)),
+ Math.min(255, Math.floor(b / k)));
};
d3_Rgb.prototype.darker = function(k) {
k = Math.pow(0.7, arguments.length ? k : 1);
return d3_rgb(
- Math.max(0, Math.floor(k * this.r)),
- Math.max(0, Math.floor(k * this.g)),
- Math.max(0, Math.floor(k * this.b)));
+ Math.floor(k * this.r),
+ Math.floor(k * this.g),
+ Math.floor(k * this.b));
};
d3_Rgb.prototype.hsl = function() {
@@ -897,7 +1041,9 @@ d3_Rgb.prototype.toString = function() {
};
function d3_rgb_hex(v) {
- return v < 0x10 ? "0" + v.toString(16) : v.toString(16);
+ return v < 0x10
+ ? "0" + Math.max(0, v).toString(16)
+ : Math.min(255, v).toString(16);
}
function d3_rgb_parse(format, rgb, hsl) {
@@ -1134,7 +1280,8 @@ for (var d3_rgb_name in d3_rgb_names) {
}
d3.hsl = function(h, s, l) {
return arguments.length === 1
- ? d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl)
+ ? (h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l)
+ : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl))
: d3_hsl(+h, +s, +l);
};
@@ -1163,7 +1310,7 @@ d3_Hsl.prototype.rgb = function() {
};
d3_Hsl.prototype.toString = function() {
- return "hsl(" + this.h + "," + this.s * 100 + "%," + this.l * 100 + "%)";
+ return this.rgb().toString();
};
function d3_hsl_rgb(h, s, l) {
@@ -1194,906 +1341,859 @@ function d3_hsl_rgb(h, s, l) {
return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
}
+function d3_selection(groups) {
+ d3_arraySubclass(groups, d3_selectionPrototype);
+ return groups;
+}
+
var d3_select = function(s, n) { return n.querySelector(s); },
- d3_selectAll = function(s, n) { return d3_array(n.querySelectorAll(s)); };
+ d3_selectAll = function(s, n) { return n.querySelectorAll(s); },
+ d3_selectRoot = document.documentElement,
+ d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector,
+ d3_selectMatches = function(n, s) { return d3_selectMatcher.call(n, s); };
-// Use Sizzle, if available.
+// Prefer Sizzle, if available.
if (typeof Sizzle === "function") {
d3_select = function(s, n) { return Sizzle(s, n)[0]; };
d3_selectAll = function(s, n) { return Sizzle.uniqueSort(Sizzle(s, n)); };
+ d3_selectMatches = Sizzle.matchesSelector;
}
-var d3_root = d3_selection([[document]]);
-d3_root[0].parentNode = document.documentElement;
-
-// TODO fast singleton implementation!
-d3.select = function(selector) {
- return typeof selector === "string"
- ? d3_root.select(selector)
- : d3_selection([[selector]]); // assume node
-};
+var d3_selectionPrototype = [];
-d3.selectAll = function(selector) {
- return typeof selector === "string"
- ? d3_root.selectAll(selector)
- : d3_selection([d3_array(selector)]); // assume node[]
+d3.selection = function() {
+ return d3_selectionRoot;
};
-function d3_selection(groups) {
-
- function select(select) {
- var subgroups = [],
- subgroup,
- subnode,
- group,
- node;
- for (var j = 0, m = groups.length; j < m; j++) {
- group = groups[j];
- subgroups.push(subgroup = []);
- subgroup.parentNode = group.parentNode;
- for (var i = 0, n = group.length; i < n; i++) {
- if (node = group[i]) {
- subgroup.push(subnode = select(node));
- if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
- } else {
- subgroup.push(null);
- }
- }
- }
- return d3_selection(subgroups);
- }
-
- function selectAll(selectAll) {
- var subgroups = [],
- subgroup,
- group,
- node;
- for (var j = 0, m = groups.length; j < m; j++) {
- group = groups[j];
- for (var i = 0, n = group.length; i < n; i++) {
- if (node = group[i]) {
- subgroups.push(subgroup = selectAll(node));
- subgroup.parentNode = node;
- }
- }
- }
- return d3_selection(subgroups);
- }
-
- // TODO select(function)?
- groups.select = function(selector) {
- return select(function(node) {
- return d3_select(selector, node);
- });
- };
-
- // TODO selectAll(function)?
- groups.selectAll = function(selector) {
- return selectAll(function(node) {
- return d3_selectAll(selector, node);
- });
- };
-
- // TODO preserve null elements to maintain index?
- groups.filter = function(filter) {
- var subgroups = [],
- subgroup,
- group,
- node;
- for (var j = 0, m = groups.length; j < m; j++) {
- group = groups[j];
- subgroups.push(subgroup = []);
- subgroup.parentNode = group.parentNode;
- for (var i = 0, n = group.length; i < n; i++) {
- if ((node = group[i]) && filter.call(node, node.__data__, i)) {
- subgroup.push(node);
- }
- }
- }
- return d3_selection(subgroups);
- };
-
- groups.map = function(map) {
- var group,
- node;
- for (var j = 0, m = groups.length; j < m; j++) {
- group = groups[j];
- for (var i = 0, n = group.length; i < n; i++) {
- if (node = group[i]) node.__data__ = map.call(node, node.__data__, i);
- }
- }
- return groups;
- };
-
- // TODO data(null) for clearing data?
- groups.data = function(data, join) {
- var enter = [],
- update = [],
- exit = [];
-
- function bind(group, groupData) {
- var i = 0,
- n = group.length,
- m = groupData.length,
- n0 = Math.min(n, m),
- n1 = Math.max(n, m),
- updateNodes = [],
- enterNodes = [],
- exitNodes = [],
- node,
- nodeData;
-
- if (join) {
- var nodeByKey = {},
- keys = [],
- key,
- j = groupData.length;
-
- for (i = 0; i < n; i++) {
- key = join.call(node = group[i], node.__data__, i);
- if (key in nodeByKey) {
- exitNodes[j++] = node; // duplicate key
- } else {
- nodeByKey[key] = node;
- }
- keys.push(key);
- }
-
- for (i = 0; i < m; i++) {
- node = nodeByKey[key = join.call(groupData, nodeData = groupData[i], i)];
- if (node) {
- node.__data__ = nodeData;
- updateNodes[i] = node;
- enterNodes[i] = exitNodes[i] = null;
- } else {
- enterNodes[i] = d3_selection_enterNode(nodeData);
- updateNodes[i] = exitNodes[i] = null;
- }
- delete nodeByKey[key];
- }
-
- for (i = 0; i < n; i++) {
- if (keys[i] in nodeByKey) {
- exitNodes[i] = group[i];
- }
- }
+d3.selection.prototype = d3_selectionPrototype;
+d3_selectionPrototype.select = function(selector) {
+ var subgroups = [],
+ subgroup,
+ subnode,
+ group,
+ node;
+
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = -1, n = group.length; ++i < n;) {
+ if (node = group[i]) {
+ subgroup.push(subnode = selector.call(node, node.__data__, i));
+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
} else {
- for (; i < n0; i++) {
- node = group[i];
- nodeData = groupData[i];
- if (node) {
- node.__data__ = nodeData;
- updateNodes[i] = node;
- enterNodes[i] = exitNodes[i] = null;
- } else {
- enterNodes[i] = d3_selection_enterNode(nodeData);
- updateNodes[i] = exitNodes[i] = null;
- }
- }
- for (; i < m; i++) {
- enterNodes[i] = d3_selection_enterNode(groupData[i]);
- updateNodes[i] = exitNodes[i] = null;
- }
- for (; i < n1; i++) {
- exitNodes[i] = group[i];
- enterNodes[i] = updateNodes[i] = null;
- }
- }
-
- enterNodes.parentNode
- = updateNodes.parentNode
- = exitNodes.parentNode
- = group.parentNode;
-
- enter.push(enterNodes);
- update.push(updateNodes);
- exit.push(exitNodes);
- }
-
- var i = -1,
- n = groups.length,
- group;
- if (typeof data === "function") {
- while (++i < n) {
- bind(group = groups[i], data.call(group, group.parentNode.__data__, i));
- }
- } else {
- while (++i < n) {
- bind(group = groups[i], data);
+ subgroup.push(null);
}
}
+ }
- var selection = d3_selection(update);
- selection.enter = function() {
- return d3_selectionEnter(enter);
- };
- selection.exit = function() {
- return d3_selection(exit);
- };
- return selection;
- };
+ return d3_selection(subgroups);
+};
- // TODO mask forEach? or rename for eachData?
- // TODO offer the same semantics for map, reduce, etc.?
- groups.each = function(callback) {
- for (var j = 0, m = groups.length; j < m; j++) {
- var group = groups[j];
- for (var i = 0, n = group.length; i < n; i++) {
- var node = group[i];
- if (node) callback.call(node, node.__data__, i);
- }
- }
- return groups;
+function d3_selection_selector(selector) {
+ return function() {
+ return d3_select(selector, this);
};
-
- function first(callback) {
- for (var j = 0, m = groups.length; j < m; j++) {
- var group = groups[j];
- for (var i = 0, n = group.length; i < n; i++) {
- var node = group[i];
- if (node) return callback.call(node, node.__data__, i);
+}
+d3_selectionPrototype.selectAll = function(selector) {
+ var subgroups = [],
+ subgroup,
+ node;
+
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
+ if (node = group[i]) {
+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
+ subgroup.parentNode = node;
}
}
- return null;
}
- groups.empty = function() {
- return !first(function() { return true; });
- };
+ return d3_selection(subgroups);
+};
- groups.node = function() {
- return first(function() { return this; });
+function d3_selection_selectorAll(selector) {
+ return function() {
+ return d3_selectAll(selector, this);
};
+}
+d3_selectionPrototype.attr = function(name, value) {
+ name = d3.ns.qualify(name);
+
+ // If no value is specified, return the first value.
+ if (arguments.length < 2) {
+ var node = this.node();
+ return name.local
+ ? node.getAttributeNS(name.space, name.local)
+ : node.getAttribute(name);
+ }
- groups.attr = function(name, value) {
- name = d3.ns.qualify(name);
-
- // If no value is specified, return the first value.
- if (arguments.length < 2) {
- return first(name.local
- ? function() { return this.getAttributeNS(name.space, name.local); }
- : function() { return this.getAttribute(name); });
- }
-
- /** @this {Element} */
- function attrNull() {
- this.removeAttribute(name);
- }
+ function attrNull() {
+ this.removeAttribute(name);
+ }
- /** @this {Element} */
- function attrNullNS() {
- this.removeAttributeNS(name.space, name.local);
- }
+ function attrNullNS() {
+ this.removeAttributeNS(name.space, name.local);
+ }
- /** @this {Element} */
- function attrConstant() {
- this.setAttribute(name, value);
- }
+ function attrConstant() {
+ this.setAttribute(name, value);
+ }
- /** @this {Element} */
- function attrConstantNS() {
- this.setAttributeNS(name.space, name.local, value);
- }
+ function attrConstantNS() {
+ this.setAttributeNS(name.space, name.local, value);
+ }
- /** @this {Element} */
- function attrFunction() {
- var x = value.apply(this, arguments);
- if (x == null) this.removeAttribute(name);
- else this.setAttribute(name, x);
- }
+ function attrFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttribute(name);
+ else this.setAttribute(name, x);
+ }
- /** @this {Element} */
- function attrFunctionNS() {
- var x = value.apply(this, arguments);
- if (x == null) this.removeAttributeNS(name.space, name.local);
- else this.setAttributeNS(name.space, name.local, x);
- }
+ function attrFunctionNS() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.removeAttributeNS(name.space, name.local);
+ else this.setAttributeNS(name.space, name.local, x);
+ }
- return groups.each(value == null
- ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
- ? (name.local ? attrFunctionNS : attrFunction)
- : (name.local ? attrConstantNS : attrConstant)));
- };
+ return this.each(value == null
+ ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
+ ? (name.local ? attrFunctionNS : attrFunction)
+ : (name.local ? attrConstantNS : attrConstant)));
+};
+d3_selectionPrototype.classed = function(name, value) {
+ var names = name.split(d3_selection_classedWhitespace),
+ n = names.length,
+ i = -1;
+ if (arguments.length > 1) {
+ while (++i < n) d3_selection_classed.call(this, names[i], value);
+ return this;
+ } else {
+ while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false;
+ return true;
+ }
+};
- groups.classed = function(name, value) {
- var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
+var d3_selection_classedWhitespace = /\s+/g;
- // If no value is specified, return the first value.
- if (arguments.length < 2) {
- return first(function() {
- if (c = this.classList) return c.contains(name);
- var c = this.className;
- re.lastIndex = 0;
- return re.test(c.baseVal != null ? c.baseVal : c);
- });
- }
+function d3_selection_classed(name, value) {
+ var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
- /** @this {Element} */
- function classedAdd() {
- if (c = this.classList) return c.add(name);
- var c = this.className,
- cb = c.baseVal != null,
- cv = cb ? c.baseVal : c;
- re.lastIndex = 0;
- if (!re.test(cv)) {
- cv = d3_collapse(cv + " " + name);
- if (cb) c.baseVal = cv;
- else this.className = cv;
- }
- }
+ // If no value is specified, return the first value.
+ if (arguments.length < 2) {
+ var node = this.node();
+ if (c = node.classList) return c.contains(name);
+ var c = node.className;
+ re.lastIndex = 0;
+ return re.test(c.baseVal != null ? c.baseVal : c);
+ }
- /** @this {Element} */
- function classedRemove() {
- if (c = this.classList) return c.remove(name);
- var c = this.className,
- cb = c.baseVal != null,
- cv = cb ? c.baseVal : c;
- cv = d3_collapse(cv.replace(re, " "));
+ function classedAdd() {
+ if (c = this.classList) return c.add(name);
+ var c = this.className,
+ cb = c.baseVal != null,
+ cv = cb ? c.baseVal : c;
+ re.lastIndex = 0;
+ if (!re.test(cv)) {
+ cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv;
else this.className = cv;
}
+ }
- /** @this {Element} */
- function classedFunction() {
- (value.apply(this, arguments)
- ? classedAdd
- : classedRemove).call(this);
- }
+ function classedRemove() {
+ if (c = this.classList) return c.remove(name);
+ var c = this.className,
+ cb = c.baseVal != null,
+ cv = cb ? c.baseVal : c;
+ cv = d3_collapse(cv.replace(re, " "));
+ if (cb) c.baseVal = cv;
+ else this.className = cv;
+ }
- return groups.each(typeof value === "function"
- ? classedFunction : value
+ function classedFunction() {
+ (value.apply(this, arguments)
? classedAdd
- : classedRemove);
- };
-
- groups.style = function(name, value, priority) {
- if (arguments.length < 3) priority = "";
+ : classedRemove).call(this);
+ }
- // If no value is specified, return the first value.
- if (arguments.length < 2) {
- return first(function() {
- return window.getComputedStyle(this, null).getPropertyValue(name);
- });
- }
+ return this.each(typeof value === "function"
+ ? classedFunction : value
+ ? classedAdd
+ : classedRemove);
+}
+d3_selectionPrototype.style = function(name, value, priority) {
+ if (arguments.length < 3) priority = "";
- /** @this {Element} */
- function styleNull() {
- this.style.removeProperty(name);
- }
+ // If no value is specified, return the first value.
+ if (arguments.length < 2) return window
+ .getComputedStyle(this.node(), null)
+ .getPropertyValue(name);
- /** @this {Element} */
- function styleConstant() {
- this.style.setProperty(name, value, priority);
- }
+ function styleNull() {
+ this.style.removeProperty(name);
+ }
- /** @this {Element} */
- function styleFunction() {
- var x = value.apply(this, arguments);
- if (x == null) this.style.removeProperty(name);
- else this.style.setProperty(name, x, priority);
- }
+ function styleConstant() {
+ this.style.setProperty(name, value, priority);
+ }
- return groups.each(value == null
- ? styleNull : (typeof value === "function"
- ? styleFunction : styleConstant));
- };
+ function styleFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) this.style.removeProperty(name);
+ else this.style.setProperty(name, x, priority);
+ }
- groups.property = function(name, value) {
- name = d3.ns.qualify(name);
+ return this.each(value == null
+ ? styleNull : (typeof value === "function"
+ ? styleFunction : styleConstant));
+};
+d3_selectionPrototype.property = function(name, value) {
- // If no value is specified, return the first value.
- if (arguments.length < 2) {
- return first(function() {
- return this[name];
- });
- }
+ // If no value is specified, return the first value.
+ if (arguments.length < 2) return this.node()[name];
- /** @this {Element} */
- function propertyNull() {
- delete this[name];
- }
+ function propertyNull() {
+ delete this[name];
+ }
- /** @this {Element} */
- function propertyConstant() {
- this[name] = value;
- }
+ function propertyConstant() {
+ this[name] = value;
+ }
- /** @this {Element} */
- function propertyFunction() {
- var x = value.apply(this, arguments);
- if (x == null) delete this[name];
- else this[name] = x;
- }
+ function propertyFunction() {
+ var x = value.apply(this, arguments);
+ if (x == null) delete this[name];
+ else this[name] = x;
+ }
- return groups.each(value == null
- ? propertyNull : (typeof value === "function"
- ? propertyFunction : propertyConstant));
- };
+ return this.each(value == null
+ ? propertyNull : (typeof value === "function"
+ ? propertyFunction : propertyConstant));
+};
+d3_selectionPrototype.text = function(value) {
+ return arguments.length < 1
+ ? this.node().textContent : this.each(typeof value === "function"
+ ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null
+ ? function() { this.textContent = ""; }
+ : function() { this.textContent = value; });
+};
+d3_selectionPrototype.html = function(value) {
+ return arguments.length < 1
+ ? this.node().innerHTML : this.each(typeof value === "function"
+ ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null
+ ? function() { this.innerHTML = ""; }
+ : function() { this.innerHTML = value; });
+};
+// TODO append(node)?
+// TODO append(function)?
+d3_selectionPrototype.append = function(name) {
+ name = d3.ns.qualify(name);
- groups.text = function(value) {
+ function append() {
+ return this.appendChild(document.createElementNS(this.namespaceURI, name));
+ }
- // If no value is specified, return the first value.
- if (arguments.length < 1) {
- return first(function() {
- return this.textContent;
- });
- }
+ function appendNS() {
+ return this.appendChild(document.createElementNS(name.space, name.local));
+ }
- /** @this {Element} */
- function textConstant() {
- this.textContent = value;
- }
+ return this.select(name.local ? appendNS : append);
+};
+// TODO insert(node, function)?
+// TODO insert(function, string)?
+// TODO insert(function, function)?
+d3_selectionPrototype.insert = function(name, before) {
+ name = d3.ns.qualify(name);
+
+ function insert() {
+ return this.insertBefore(
+ document.createElementNS(this.namespaceURI, name),
+ d3_select(before, this));
+ }
- /** @this {Element} */
- function textFunction() {
- this.textContent = value.apply(this, arguments);
- }
+ function insertNS() {
+ return this.insertBefore(
+ document.createElementNS(name.space, name.local),
+ d3_select(before, this));
+ }
- return groups.each(typeof value === "function"
- ? textFunction : textConstant);
- };
+ return this.select(name.local ? insertNS : insert);
+};
+// TODO remove(selector)?
+// TODO remove(node)?
+// TODO remove(function)?
+d3_selectionPrototype.remove = function() {
+ return this.each(function() {
+ var parent = this.parentNode;
+ if (parent) parent.removeChild(this);
+ });
+};
+// TODO data(null) for clearing data?
+d3_selectionPrototype.data = function(data, join) {
+ var enter = [],
+ update = [],
+ exit = [];
+
+ function bind(group, groupData) {
+ var i,
+ n = group.length,
+ m = groupData.length,
+ n0 = Math.min(n, m),
+ n1 = Math.max(n, m),
+ updateNodes = [],
+ enterNodes = [],
+ exitNodes = [],
+ node,
+ nodeData;
+
+ if (join) {
+ var nodeByKey = {},
+ keys = [],
+ key,
+ j = groupData.length;
+
+ for (i = -1; ++i < n;) {
+ key = join.call(node = group[i], node.__data__, i);
+ if (key in nodeByKey) {
+ exitNodes[j++] = node; // duplicate key
+ } else {
+ nodeByKey[key] = node;
+ }
+ keys.push(key);
+ }
- groups.html = function(value) {
+ for (i = -1; ++i < m;) {
+ node = nodeByKey[key = join.call(groupData, nodeData = groupData[i], i)];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ enterNodes[i] = exitNodes[i] = null;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ updateNodes[i] = exitNodes[i] = null;
+ }
+ delete nodeByKey[key];
+ }
- // If no value is specified, return the first value.
- if (arguments.length < 1) {
- return first(function() {
- return this.innerHTML;
- });
- }
-
- /** @this {Element} */
- function htmlConstant() {
- this.innerHTML = value;
+ for (i = -1; ++i < n;) {
+ if (keys[i] in nodeByKey) {
+ exitNodes[i] = group[i];
+ }
+ }
+ } else {
+ for (i = -1; ++i < n0;) {
+ node = group[i];
+ nodeData = groupData[i];
+ if (node) {
+ node.__data__ = nodeData;
+ updateNodes[i] = node;
+ enterNodes[i] = exitNodes[i] = null;
+ } else {
+ enterNodes[i] = d3_selection_dataNode(nodeData);
+ updateNodes[i] = exitNodes[i] = null;
+ }
+ }
+ for (; i < m; ++i) {
+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
+ updateNodes[i] = exitNodes[i] = null;
+ }
+ for (; i < n1; ++i) {
+ exitNodes[i] = group[i];
+ enterNodes[i] = updateNodes[i] = null;
+ }
}
- /** @this {Element} */
- function htmlFunction() {
- this.innerHTML = value.apply(this, arguments);
- }
+ enterNodes.update
+ = updateNodes;
- return groups.each(typeof value === "function"
- ? htmlFunction : htmlConstant);
- };
+ enterNodes.parentNode
+ = updateNodes.parentNode
+ = exitNodes.parentNode
+ = group.parentNode;
- // TODO append(node)?
- // TODO append(function)?
- groups.append = function(name) {
- name = d3.ns.qualify(name);
+ enter.push(enterNodes);
+ update.push(updateNodes);
+ exit.push(exitNodes);
+ }
- function append(node) {
- return node.appendChild(document.createElement(name));
+ var i = -1,
+ n = this.length,
+ group;
+ if (typeof data === "function") {
+ while (++i < n) {
+ bind(group = this[i], data.call(group, group.parentNode.__data__, i));
}
-
- function appendNS(node) {
- return node.appendChild(document.createElementNS(name.space, name.local));
+ } else {
+ while (++i < n) {
+ bind(group = this[i], data);
}
+ }
- return select(name.local ? appendNS : append);
- };
-
- // TODO insert(node, function)?
- // TODO insert(function, string)?
- // TODO insert(function, function)?
- groups.insert = function(name, before) {
- name = d3.ns.qualify(name);
+ var selection = d3_selection(update);
+ selection.enter = function() { return d3_selection_enter(enter); };
+ selection.exit = function() { return d3_selection(exit); };
+ return selection;
+};
- function insert(node) {
- return node.insertBefore(
- document.createElement(name),
- d3_select(before, node));
+function d3_selection_dataNode(data) {
+ return {__data__: data};
+}
+d3_selectionPrototype.filter = function(filter) {
+ var subgroups = [],
+ subgroup,
+ group,
+ node;
+
+ if (typeof filter !== "function") filter = d3_selection_filter(filter);
+
+ for (var j = 0, m = this.length; j < m; j++) {
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = (group = this[j]).parentNode;
+ for (var i = 0, n = group.length; i < n; i++) {
+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
+ subgroup.push(node);
+ }
}
+ }
- function insertNS(node) {
- return node.insertBefore(
- document.createElementNS(name.space, name.local),
- d3_select(before, node));
- }
+ return d3_selection(subgroups);
+};
- return select(name.local ? insertNS : insert);
+function d3_selection_filter(selector) {
+ return function() {
+ return d3_selectMatches(this, selector);
};
+}
+d3_selectionPrototype.map = function(map) {
+ return this.each(function() {
+ this.__data__ = map.apply(this, arguments);
+ });
+};
+d3_selectionPrototype.order = function() {
+ for (var j = -1, m = this.length; ++j < m;) {
+ for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
+ if (node = group[i]) {
+ if (next) next.parentNode.insertBefore(node, next);
+ next = node;
+ }
+ }
+ }
+ return this;
+};
+d3_selectionPrototype.sort = function(comparator) {
+ comparator = d3_selection_sortComparator.apply(this, arguments);
+ for (var j = -1, m = this.length; ++j < m;) this[j].sort(comparator);
+ return this.order();
+};
- // TODO remove(selector)?
- // TODO remove(node)?
- // TODO remove(function)?
- groups.remove = function() {
- return groups.each(function() {
- var parent = this.parentNode;
- if (parent) parent.removeChild(this);
- });
+function d3_selection_sortComparator(comparator) {
+ if (!arguments.length) comparator = d3.ascending;
+ return function(a, b) {
+ return comparator(a && a.__data__, b && b.__data__);
};
-
- groups.sort = function(comparator) {
- comparator = d3_selection_comparator.apply(this, arguments);
- for (var j = 0, m = groups.length; j < m; j++) {
- var group = groups[j];
- group.sort(comparator);
- for (var i = 1, n = group.length, prev = group[0]; i < n; i++) {
- var node = group[i];
- if (node) {
- if (prev) prev.parentNode.insertBefore(node, prev.nextSibling);
- prev = node;
- }
+}
+// type can be namespaced, e.g., "click.foo"
+// listener can be null for removal
+d3_selectionPrototype.on = function(type, listener, capture) {
+ if (arguments.length < 3) capture = false;
+
+ // parse the type specifier
+ var name = "__on" + type, i = type.indexOf(".");
+ if (i > 0) type = type.substring(0, i);
+
+ // if called with only one argument, return the current listener
+ if (arguments.length < 2) return (i = this.node()[name]) && i._;
+
+ // remove the old event listener, and add the new event listener
+ return this.each(function(d, i) {
+ var node = this;
+
+ if (node[name]) node.removeEventListener(type, node[name], capture);
+ if (listener) node.addEventListener(type, node[name] = l, capture);
+
+ // wrapped event listener that preserves i
+ function l(e) {
+ var o = d3.event; // Events can be reentrant (e.g., focus).
+ d3.event = e;
+ try {
+ listener.call(node, node.__data__, i);
+ } finally {
+ d3.event = o;
}
}
- return groups;
- };
-
- // type can be namespaced, e.g., "click.foo"
- // listener can be null for removal
- groups.on = function(type, listener, capture) {
- if (arguments.length < 3) capture = false;
-
- // parse the type specifier
- var i = type.indexOf("."),
- typo = i === -1 ? type : type.substring(0, i),
- name = "__on" + type;
- // remove the old event listener, and add the new event listener
- return groups.each(function(d, i) {
- if (this[name]) this.removeEventListener(typo, this[name], capture);
- if (listener) this.addEventListener(typo, this[name] = l, capture);
-
- // wrapped event listener that preserves i
- var node = this;
- function l(e) {
- var o = d3.event; // Events can be reentrant (e.g., focus).
- d3.event = e;
- try {
- listener.call(this, node.__data__, i);
- } finally {
- d3.event = o;
- }
- }
- });
- };
+ // stash the unwrapped listener for retrieval
+ l._ = listener;
+ });
+};
+d3_selectionPrototype.each = function(callback) {
+ for (var j = -1, m = this.length; ++j < m;) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
+ var node = group[i];
+ if (node) callback.call(node, node.__data__, i, j);
+ }
+ }
+ return this;
+};
+//
+// Note: assigning to the arguments array simultaneously changes the value of
+// the corresponding argument!
+//
+// TODO The `this` argument probably shouldn't be the first argument to the
+// callback, anyway, since it's redundant. However, that will require a major
+// version bump due to backwards compatibility, so I'm not changing it right
+// away.
+//
+d3_selectionPrototype.call = function(callback) {
+ callback.apply(this, (arguments[0] = this, arguments));
+ return this;
+};
+d3_selectionPrototype.empty = function() {
+ return !this.node();
+};
+d3_selectionPrototype.node = function(callback) {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) return node;
+ }
+ }
+ return null;
+};
+d3_selectionPrototype.transition = function() {
+ var subgroups = [],
+ subgroup,
+ node;
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
+ subgroup.push((node = group[i]) ? {node: node, delay: 0, duration: 250} : null);
+ }
+ }
- // TODO slice?
+ return d3_transition(subgroups, d3_transitionInheritId || ++d3_transitionId, Date.now());
+};
+var d3_selectionRoot = d3_selection([[document]]);
- groups.transition = function() {
- return d3_transition(groups);
- };
+d3_selectionRoot[0].parentNode = d3_selectRoot;
- groups.call = d3_call;
+// TODO fast singleton implementation!
+// TODO select(function)
+d3.select = function(selector) {
+ return typeof selector === "string"
+ ? d3_selectionRoot.select(selector)
+ : d3_selection([[selector]]); // assume node
+};
- return groups;
+// TODO selectAll(function)
+d3.selectAll = function(selector) {
+ return typeof selector === "string"
+ ? d3_selectionRoot.selectAll(selector)
+ : d3_selection([d3_array(selector)]); // assume node[]
+};
+function d3_selection_enter(selection) {
+ d3_arraySubclass(selection, d3_selection_enterPrototype);
+ return selection;
}
-function d3_selectionEnter(groups) {
-
- function select(select) {
- var subgroups = [],
- subgroup,
- subnode,
- group,
- node;
- for (var j = 0, m = groups.length; j < m; j++) {
- group = groups[j];
- subgroups.push(subgroup = []);
- subgroup.parentNode = group.parentNode;
- for (var i = 0, n = group.length; i < n; i++) {
- if (node = group[i]) {
- subgroup.push(subnode = select(group.parentNode));
- subnode.__data__ = node.__data__;
- } else {
- subgroup.push(null);
- }
+var d3_selection_enterPrototype = [];
+
+d3_selection_enterPrototype.append = d3_selectionPrototype.append;
+d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
+d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
+d3_selection_enterPrototype.node = d3_selectionPrototype.node;
+d3_selection_enterPrototype.select = function(selector) {
+ var subgroups = [],
+ subgroup,
+ subnode,
+ upgroup,
+ group,
+ node;
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ upgroup = (group = this[j]).update;
+ subgroups.push(subgroup = []);
+ subgroup.parentNode = group.parentNode;
+ for (var i = -1, n = group.length; ++i < n;) {
+ if (node = group[i]) {
+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
+ subnode.__data__ = node.__data__;
+ } else {
+ subgroup.push(null);
}
}
- return d3_selection(subgroups);
}
- // TODO append(node)?
- // TODO append(function)?
- groups.append = function(name) {
- name = d3.ns.qualify(name);
-
- function append(node) {
- return node.appendChild(document.createElement(name));
- }
-
- function appendNS(node) {
- return node.appendChild(document.createElementNS(name.space, name.local));
- }
-
- return select(name.local ? appendNS : append);
- };
+ return d3_selection(subgroups);
+};
+function d3_transition(groups, id, time) {
+ d3_arraySubclass(groups, d3_transitionPrototype);
- // TODO insert(node, function)?
- // TODO insert(function, string)?
- // TODO insert(function, function)?
- groups.insert = function(name, before) {
- name = d3.ns.qualify(name);
+ var tweens = {},
+ event = d3.dispatch("start", "end"),
+ ease = d3_transitionEase;
- function insert(node) {
- return node.insertBefore(
- document.createElement(name),
- d3_select(before, node));
- }
+ groups.id = id;
- function insertNS(node) {
- return node.insertBefore(
- document.createElementNS(name.space, name.local),
- d3_select(before, node));
- }
+ groups.time = time;
- return select(name.local ? insertNS : insert);
+ groups.tween = function(name, tween) {
+ if (arguments.length < 2) return tweens[name];
+ if (tween == null) delete tweens[name];
+ else tweens[name] = tween;
+ return groups;
};
- return groups;
-}
+ groups.ease = function(value) {
+ if (!arguments.length) return ease;
+ ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments);
+ return groups;
+ };
-function d3_selection_comparator(comparator) {
- if (!arguments.length) comparator = d3.ascending;
- return function(a, b) {
- return comparator(a && a.__data__, b && b.__data__);
+ groups.each = function(type, listener) {
+ if (arguments.length < 2) return d3_transition_each.call(groups, type);
+ event.on(type, listener);
+ return groups;
};
-}
-function d3_selection_enterNode(data) {
- return {__data__: data};
-}
-d3.transition = d3_root.transition;
+ d3.timer(function(elapsed) {
+ groups.each(function(d, i, j) {
+ var tweened = [],
+ node = this,
+ delay = groups[j][i].delay,
+ duration = groups[j][i].duration,
+ lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0});
-var d3_transitionId = 0,
- d3_transitionInheritId = 0;
+ ++lock.count;
-function d3_transition(groups) {
- var transition = {},
- transitionId = d3_transitionInheritId || ++d3_transitionId,
- tweens = {},
- interpolators = [],
- remove = false,
- event = d3.dispatch("start", "end"),
- stage = [],
- delay = [],
- duration = [],
- durationMax,
- ease = d3.ease("cubic-in-out");
-
- //
- // Be careful with concurrent transitions!
- //
- // Say transition A causes an exit. Before A finishes, a transition B is
- // created, and believes it only needs to do an update, because the elements
- // haven't been removed yet (which happens at the very end of the exit
- // transition).
- //
- // Even worse, what if either transition A or B has a staggered delay? Then,
- // some elements may be removed, while others remain. Transition B does not
- // know to enter the elements because they were still present at the time
- // the transition B was created (but not yet started).
- //
- // To prevent such confusion, we only trigger end events for transitions if
- // the transition ending is the only one scheduled for the given element.
- // Similarly, we only allow one transition to be active for any given
- // element, so that concurrent transitions do not overwrite each other's
- // properties.
- //
- // TODO Support transition namespaces, so that transitions can proceed
- // concurrently on the same element if needed. Hopefully, this is rare!
- //
-
- groups.each(function() {
- (this.__transition__ || (this.__transition__ = {})).owner = transitionId;
- });
+ delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time);
- function step(elapsed) {
- var clear = true,
- k = -1;
- groups.each(function() {
- if (stage[++k] === 2) return; // ended
- var t = (elapsed - delay[k]) / duration[k],
- tx = this.__transition__,
- te, // ease(t)
- tk, // tween key
- ik = interpolators[k];
-
- // Check if the (un-eased) time is outside the range [0,1].
- if (t < 1) {
- clear = false;
- if (t < 0) return;
- } else {
- t = 1;
- }
+ function start(elapsed) {
+ if (lock.active > id) return stop();
+ lock.active = id;
- // Determine the stage of this transition.
- // 0 - Not yet started.
- // 1 - In progress.
- // 2 - Ended.
- if (stage[k]) {
- if (!tx || tx.active !== transitionId) {
- stage[k] = 2;
- return;
- }
- } else if (!tx || tx.active > transitionId) {
- stage[k] = 2;
- return;
- } else {
- stage[k] = 1;
- event.start.dispatch.apply(this, arguments);
- ik = interpolators[k] = {};
- tx.active = transitionId;
- for (tk in tweens) {
- if (te = tweens[tk].apply(this, arguments)) {
- ik[tk] = te;
+ for (var tween in tweens) {
+ if (tween = tweens[tween].call(node, d, i)) {
+ tweened.push(tween);
}
}
+
+ event.start.call(node, d, i);
+ if (!tick(elapsed)) d3.timer(tick, 0, time);
+ return 1;
}
- // Apply the interpolators!
- te = ease(t);
- for (tk in ik) ik[tk].call(this, te);
-
- // Handle ending transitions.
- if (t === 1) {
- stage[k] = 2;
- if (tx.active === transitionId) {
- var owner = tx.owner;
- if (owner === transitionId) {
- delete this.__transition__;
- if (remove && this.parentNode) this.parentNode.removeChild(this);
- }
- d3_transitionInheritId = transitionId;
- event.end.dispatch.apply(this, arguments);
+ function tick(elapsed) {
+ if (lock.active !== id) return stop();
+
+ var t = (elapsed - delay) / duration,
+ e = ease(t),
+ n = tweened.length;
+
+ while (n > 0) {
+ tweened[--n].call(node, e);
+ }
+
+ if (t >= 1) {
+ stop();
+ d3_transitionInheritId = id;
+ event.end.call(node, d, i);
d3_transitionInheritId = 0;
- tx.owner = owner;
+ return 1;
}
}
- });
- return clear;
- }
- transition.delay = function(value) {
- var delayMin = Infinity,
- k = -1;
- if (typeof value === "function") {
- groups.each(function(d, i) {
- var x = delay[++k] = +value.apply(this, arguments);
- if (x < delayMin) delayMin = x;
- });
- } else {
- delayMin = +value;
- groups.each(function(d, i) {
- delay[++k] = delayMin;
- });
- }
- d3_timer(step, delayMin);
- return transition;
- };
-
- transition.duration = function(value) {
- var k = -1;
- if (typeof value === "function") {
- durationMax = 0;
- groups.each(function(d, i) {
- var x = duration[++k] = +value.apply(this, arguments);
- if (x > durationMax) durationMax = x;
- });
- } else {
- durationMax = +value;
- groups.each(function(d, i) {
- duration[++k] = durationMax;
- });
- }
- return transition;
- };
+ function stop() {
+ if (!--lock.count) delete node.__transition__;
+ return 1;
+ }
+ });
+ return 1;
+ }, 0, time);
- transition.ease = function(value) {
- ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments);
- return transition;
- };
+ return groups;
+}
- transition.attrTween = function(name, tween) {
+var d3_transitionRemove = {};
- /** @this {Element} */
- function attrTween(d, i) {
- var f = tween.call(this, d, i, this.getAttribute(name));
- return f && function(t) {
- this.setAttribute(name, f(t));
- };
- }
+function d3_transitionNull(d, i, a) {
+ return a != "" && d3_transitionRemove;
+}
- /** @this {Element} */
- function attrTweenNS(d, i) {
- var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
- return f && function(t) {
- this.setAttributeNS(name.space, name.local, f(t));
- };
- }
+function d3_transitionTween(name, b) {
+ var interpolate = d3_interpolateByName(name);
- tweens["attr." + name] = name.local ? attrTweenNS : attrTween;
- return transition;
- };
+ function transitionFunction(d, i, a) {
+ var v = b.call(this, d, i);
+ return v == null
+ ? a != "" && d3_transitionRemove
+ : a != v && interpolate(a, v);
+ }
- transition.attr = function(name, value) {
- return transition.attrTween(name, d3_transitionTween(value));
- };
+ function transitionString(d, i, a) {
+ return a != b && interpolate(a, b);
+ }
- transition.styleTween = function(name, tween, priority) {
- if (arguments.length < 3) priority = null;
+ return typeof b === "function" ? transitionFunction
+ : b == null ? d3_transitionNull
+ : (b += "", transitionString);
+}
- /** @this {Element} */
- function styleTween(d, i) {
- var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
- return f && function(t) {
- this.style.setProperty(name, f(t), priority);
- };
- }
+var d3_transitionPrototype = [],
+ d3_transitionId = 0,
+ d3_transitionInheritId = 0,
+ d3_transitionEase = d3.ease("cubic-in-out");
- tweens["style." + name] = styleTween;
- return transition;
- };
+d3_transitionPrototype.call = d3_selectionPrototype.call;
- transition.style = function(name, value, priority) {
- if (arguments.length < 3) priority = null;
- return transition.styleTween(name, d3_transitionTween(value), priority);
- };
+d3.transition = function() {
+ return d3_selectionRoot.transition();
+};
- transition.text = function(value) {
- tweens.text = function(d, i) {
- this.textContent = typeof value === "function"
- ? value.call(this, d, i)
- : value;
- };
- return transition;
- };
+d3.transition.prototype = d3_transitionPrototype;
+d3_transitionPrototype.select = function(selector) {
+ var subgroups = [],
+ subgroup,
+ subnode,
+ node;
+
+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ subgroups.push(subgroup = []);
+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
+ if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) {
+ if ("__data__" in node.node) subnode.__data__ = node.node.__data__;
+ subgroup.push({node: subnode, delay: node.delay, duration: node.duration});
+ } else {
+ subgroup.push(null);
+ }
+ }
+ }
- transition.select = function(query) {
- var k, t = d3_transition(groups.select(query)).ease(ease);
- k = -1; t.delay(function(d, i) { return delay[++k]; });
- k = -1; t.duration(function(d, i) { return duration[++k]; });
- return t;
- };
+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
+};
+d3_transitionPrototype.selectAll = function(selector) {
+ var subgroups = [],
+ subgroup,
+ subnodes,
+ node;
+
+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
+
+ for (var j = -1, m = this.length; ++j < m;) {
+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
+ if (node = group[i]) {
+ subnodes = selector.call(node.node, node.node.__data__, i);
+ subgroups.push(subgroup = []);
+ for (var k = -1, o = subnodes.length; ++k < o;) {
+ subgroup.push({node: subnodes[k], delay: node.delay, duration: node.duration});
+ }
+ }
+ }
+ }
- transition.selectAll = function(query) {
- var k, t = d3_transition(groups.selectAll(query)).ease(ease);
- k = -1; t.delay(function(d, i) { return delay[i ? k : ++k]; })
- k = -1; t.duration(function(d, i) { return duration[i ? k : ++k]; });
- return t;
- };
+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
+};
+d3_transitionPrototype.attr = function(name, value) {
+ return this.attrTween(name, d3_transitionTween(name, value));
+};
- transition.remove = function() {
- remove = true;
- return transition;
- };
+d3_transitionPrototype.attrTween = function(nameNS, tween) {
+ var name = d3.ns.qualify(nameNS);
- transition.each = function(type, listener) {
- event[type].add(listener);
- return transition;
- };
+ function attrTween(d, i) {
+ var f = tween.call(this, d, i, this.getAttribute(name));
+ return f === d3_transitionRemove
+ ? (this.removeAttribute(name), null)
+ : f && function(t) { this.setAttribute(name, f(t)); };
+ }
- transition.call = d3_call;
+ function attrTweenNS(d, i) {
+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
+ return f === d3_transitionRemove
+ ? (this.removeAttributeNS(name.space, name.local), null)
+ : f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
+ }
- return transition.delay(0).duration(250);
-}
+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
+};
+d3_transitionPrototype.style = function(name, value, priority) {
+ if (arguments.length < 3) priority = "";
+ return this.styleTween(name, d3_transitionTween(name, value), priority);
+};
-function d3_transitionTween(b) {
- return typeof b === "function"
- ? function(d, i, a) { var v = b.call(this, d, i) + ""; return a != v && d3.interpolate(a, v); }
- : (b = b + "", function(d, i, a) { return a != b && d3.interpolate(a, b); });
+d3_transitionPrototype.styleTween = function(name, tween, priority) {
+ if (arguments.length < 3) priority = "";
+ return this.tween("style." + name, function(d, i) {
+ var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
+ return f === d3_transitionRemove
+ ? (this.style.removeProperty(name), null)
+ : f && function(t) { this.style.setProperty(name, f(t), priority); };
+ });
+};
+d3_transitionPrototype.text = function(value) {
+ return this.tween("text", function(d, i) {
+ this.textContent = typeof value === "function"
+ ? value.call(this, d, i)
+ : value;
+ });
+};
+d3_transitionPrototype.remove = function() {
+ return this.each("end", function() {
+ var p;
+ if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
+ });
+};
+d3_transitionPrototype.delay = function(value) {
+ var groups = this;
+ return groups.each(typeof value === "function"
+ ? function(d, i, j) { groups[j][i].delay = +value.apply(this, arguments); }
+ : (value = +value, function(d, i, j) { groups[j][i].delay = value; }));
+};
+d3_transitionPrototype.duration = function(value) {
+ var groups = this;
+ return groups.each(typeof value === "function"
+ ? function(d, i, j) { groups[j][i].duration = +value.apply(this, arguments); }
+ : (value = +value, function(d, i, j) { groups[j][i].duration = value; }));
+};
+function d3_transition_each(callback) {
+ for (var j = 0, m = this.length; j < m; j++) {
+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
+ var node = group[i];
+ if (node) callback.call(node = node.node, node.__data__, i, j);
+ }
+ }
+ return this;
}
+d3_transitionPrototype.transition = function() {
+ return this.select(d3_this);
+};
var d3_timer_queue = null,
d3_timer_interval, // is an interval (or frame) active?
d3_timer_timeout; // is a timeout active?
// The timer will continue to fire until callback returns true.
-d3.timer = function(callback) {
- d3_timer(callback, 0);
-};
-
-function d3_timer(callback, delay) {
- var now = Date.now(),
- found = false,
+d3.timer = function(callback, delay, then) {
+ var found = false,
t0,
t1 = d3_timer_queue;
- if (!isFinite(delay)) return;
+ if (arguments.length < 3) {
+ if (arguments.length < 2) delay = 0;
+ else if (!isFinite(delay)) return;
+ then = Date.now();
+ }
// See if the callback's already in the queue.
while (t1) {
if (t1.callback === callback) {
- t1.then = now;
+ t1.then = then;
t1.delay = delay;
found = true;
break;
@@ -2105,7 +2205,7 @@ function d3_timer(callback, delay) {
// Otherwise, add the callback to the queue.
if (!found) d3_timer_queue = {
callback: callback,
- then: now,
+ then: then,
delay: delay,
next: d3_timer_queue
};
@@ -2125,7 +2225,7 @@ function d3_timer_step() {
while (t1) {
elapsed = now - t1.then;
- if (elapsed > t1.delay) t1.flush = t1.callback(elapsed);
+ if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
t1 = t1.next;
}
@@ -2178,6 +2278,66 @@ var d3_timer_frame = window.requestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { setTimeout(callback, 17); };
+d3.transform = function(string) {
+ var g = document.createElementNS(d3.ns.prefix.svg, "g"),
+ identity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
+ return (d3.transform = function(string) {
+ g.setAttribute("transform", string);
+ var t = g.transform.baseVal.consolidate();
+ return new d3_transform(t ? t.matrix : identity);
+ })(string);
+};
+
+// Compute x-scale and normalize the first row.
+// Compute shear and make second row orthogonal to first.
+// Compute y-scale and normalize the second row.
+// Finally, compute the rotation.
+function d3_transform(m) {
+ var r0 = [m.a, m.b],
+ r1 = [m.c, m.d],
+ kx = d3_transformNormalize(r0),
+ kz = d3_transformDot(r0, r1),
+ ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
+ if (r0[0] * r1[1] < r1[0] * r0[1]) {
+ r0[0] *= -1;
+ r0[1] *= -1;
+ kx *= -1;
+ kz *= -1;
+ }
+ this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
+ this.translate = [m.e, m.f];
+ this.scale = [kx, ky];
+ this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
+};
+
+d3_transform.prototype.toString = function() {
+ return "translate(" + this.translate
+ + ")rotate(" + this.rotate
+ + ")skewX(" + this.skew
+ + ")scale(" + this.scale
+ + ")";
+};
+
+function d3_transformDot(a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+}
+
+function d3_transformNormalize(a) {
+ var k = Math.sqrt(d3_transformDot(a, a));
+ if (k) {
+ a[0] /= k;
+ a[1] /= k;
+ }
+ return k;
+}
+
+function d3_transformCombine(a, b, k) {
+ a[0] += k * b[0];
+ a[1] += k * b[1];
+ return a;
+}
+
+var d3_transformDegrees = 180 / Math.PI;
function d3_noop() {}
d3.scale = {};
@@ -2185,6 +2345,10 @@ function d3_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [start, stop] : [stop, start];
}
+
+function d3_scaleRange(scale) {
+ return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
+}
function d3_scale_nice(domain, nice) {
var i0 = 0,
i1 = domain.length - 1,
@@ -2197,9 +2361,12 @@ function d3_scale_nice(domain, nice) {
dx = x0; x0 = x1; x1 = dx;
}
- nice = nice(x1 - x0);
- domain[i0] = nice.floor(x0);
- domain[i1] = nice.ceil(x1);
+ if (dx = x1 - x0) {
+ nice = nice(dx);
+ domain[i0] = nice.floor(x0);
+ domain[i1] = nice.ceil(x1);
+ }
+
return domain;
}
@@ -2207,11 +2374,11 @@ function d3_scale_niceDefault() {
return Math;
}
d3.scale.linear = function() {
- var domain = [0, 1],
- range = [0, 1],
- interpolate = d3.interpolate,
- clamp = false,
- output,
+ return d3_scale_linear([0, 1], [0, 1], d3.interpolate, false);
+};
+
+function d3_scale_linear(domain, range, interpolate, clamp) {
+ var output,
input;
function rescale() {
@@ -2272,15 +2439,15 @@ d3.scale.linear = function() {
return rescale();
};
+ scale.copy = function() {
+ return d3_scale_linear(domain, range, interpolate, clamp);
+ };
+
return rescale();
};
function d3_scale_linearRebind(scale, linear) {
- scale.range = d3.rebind(scale, linear.range);
- scale.rangeRound = d3.rebind(scale, linear.rangeRound);
- scale.interpolate = d3.rebind(scale, linear.interpolate);
- scale.clamp = d3.rebind(scale, linear.clamp);
- return scale;
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
}
function d3_scale_linearNice(dx) {
@@ -2341,9 +2508,11 @@ function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
};
}
d3.scale.log = function() {
- var linear = d3.scale.linear(),
- log = d3_scale_log,
- pow = log.pow;
+ return d3_scale_log(d3.scale.linear(), d3_scale_logp);
+};
+
+function d3_scale_log(linear, log) {
+ var pow = log.pow;
function scale(x) {
return linear(log(x));
@@ -2355,7 +2524,7 @@ d3.scale.log = function() {
scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(pow);
- log = x[0] < 0 ? d3_scale_logn : d3_scale_log;
+ log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
pow = log.pow;
linear.domain(x.map(log));
return scale;
@@ -2388,14 +2557,27 @@ d3.scale.log = function() {
return ticks;
};
- scale.tickFormat = function() {
- return d3_scale_logTickFormat;
+ scale.tickFormat = function(n, format) {
+ if (arguments.length < 2) format = d3_scale_logFormat;
+ if (arguments.length < 1) return format;
+ var k = n / scale.ticks().length,
+ f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil),
+ e;
+ return function(d) {
+ return d / pow(f(log(d) + e)) < k ? format(d) : "";
+ };
+ };
+
+ scale.copy = function() {
+ return d3_scale_log(linear.copy(), log);
};
return d3_scale_linearRebind(scale, linear);
};
-function d3_scale_log(x) {
+var d3_scale_logFormat = d3.format(".0e");
+
+function d3_scale_logp(x) {
return Math.log(x) / Math.LN10;
}
@@ -2403,22 +2585,20 @@ function d3_scale_logn(x) {
return -Math.log(-x) / Math.LN10;
}
-d3_scale_log.pow = function(x) {
+d3_scale_logp.pow = function(x) {
return Math.pow(10, x);
};
d3_scale_logn.pow = function(x) {
return -Math.pow(10, -x);
};
-
-function d3_scale_logTickFormat(d) {
- return d.toPrecision(1);
-}
d3.scale.pow = function() {
- var linear = d3.scale.linear(),
- exponent = 1,
- powp = Number,
- powb = powp;
+ return d3_scale_pow(d3.scale.linear(), 1);
+};
+
+function d3_scale_pow(linear, exponent) {
+ var powp = d3_scale_powPow(exponent),
+ powb = d3_scale_powPow(1 / exponent);
function scale(x) {
return linear(powp(x));
@@ -2430,8 +2610,6 @@ d3.scale.pow = function() {
scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(powb);
- powp = d3_scale_powPow(exponent);
- powb = d3_scale_powPow(1 / exponent);
linear.domain(x.map(powp));
return scale;
};
@@ -2451,10 +2629,15 @@ d3.scale.pow = function() {
scale.exponent = function(x) {
if (!arguments.length) return exponent;
var domain = scale.domain();
- exponent = x;
+ powp = d3_scale_powPow(exponent = x);
+ powb = d3_scale_powPow(1 / exponent);
return scale.domain(domain);
};
+ scale.copy = function() {
+ return d3_scale_pow(linear.copy(), exponent);
+ };
+
return d3_scale_linearRebind(scale, linear);
};
@@ -2467,73 +2650,69 @@ d3.scale.sqrt = function() {
return d3.scale.pow().exponent(.5);
};
d3.scale.ordinal = function() {
- var domain = [],
- index = {},
- range = [],
- rangeBand = 0,
- rerange = d3_noop;
+ return d3_scale_ordinal([], {t: "range", x: []});
+};
+
+function d3_scale_ordinal(domain, ranger) {
+ var index,
+ range,
+ rangeBand;
function scale(x) {
- var i = x in index ? index[x] : (index[x] = domain.push(x) - 1);
- return range[i % range.length];
+ return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length];
+ }
+
+ function steps(start, step) {
+ return d3.range(domain.length).map(function(i) { return start + step * i; });
}
scale.domain = function(x) {
if (!arguments.length) return domain;
- domain = x;
+ domain = [];
index = {};
- var i = -1, j = -1, n = domain.length; while (++i < n) {
- x = domain[i];
- if (!(x in index)) index[x] = ++j;
- }
- rerange();
- return scale;
+ var i = -1, n = x.length, xi;
+ while (++i < n) if (!index[xi = x[i]]) index[xi] = domain.push(xi);
+ return scale[ranger.t](ranger.x, ranger.p);
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
- rerange = d3_noop;
+ rangeBand = 0;
+ ranger = {t: "range", x: x};
return scale;
};
scale.rangePoints = function(x, padding) {
if (arguments.length < 2) padding = 0;
- (rerange = function() {
- var start = x[0],
- stop = x[1],
- step = (stop - start) / (domain.length - 1 + padding);
- range = domain.length == 1
- ? [(start + stop) / 2]
- : d3.range(start + step * padding / 2, stop + step / 2, step);
- rangeBand = 0;
- })();
+ var start = x[0],
+ stop = x[1],
+ step = (stop - start) / (domain.length - 1 + padding);
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
+ rangeBand = 0;
+ ranger = {t: "rangePoints", x: x, p: padding};
return scale;
};
scale.rangeBands = function(x, padding) {
if (arguments.length < 2) padding = 0;
- (rerange = function() {
- var start = x[0],
- stop = x[1],
- step = (stop - start) / (domain.length + padding);
- range = d3.range(start + step * padding, stop, step);
- rangeBand = step * (1 - padding);
- })();
+ var start = x[0],
+ stop = x[1],
+ step = (stop - start) / (domain.length + padding);
+ range = steps(start + step * padding, step);
+ rangeBand = step * (1 - padding);
+ ranger = {t: "rangeBands", x: x, p: padding};
return scale;
};
scale.rangeRoundBands = function(x, padding) {
if (arguments.length < 2) padding = 0;
- (rerange = function() {
- var start = x[0],
- stop = x[1],
- diff = stop - start,
- step = Math.floor(diff / (domain.length + padding)),
- err = diff - (domain.length - padding) * step;
- range = d3.range(start + Math.round(err / 2), stop, step);
- rangeBand = Math.round(step * (1 - padding));
- })();
+ var start = x[0],
+ stop = x[1],
+ step = Math.floor((stop - start) / (domain.length + padding));
+ range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
+ rangeBand = Math.round(step * (1 - padding));
+ ranger = {t: "rangeRoundBands", x: x, p: padding};
return scale;
};
@@ -2541,7 +2720,15 @@ d3.scale.ordinal = function() {
return rangeBand;
};
- return scale;
+ scale.rangeExtent = function() {
+ return ranger.t === "range" ? d3_scaleExtent(ranger.x) : ranger.x;
+ };
+
+ scale.copy = function() {
+ return d3_scale_ordinal(domain, ranger);
+ };
+
+ return scale.domain(domain);
};
/*
* This product includes color specifications and designs developed by Cynthia
@@ -2598,16 +2785,19 @@ var d3_category20c = [
"#636363", "#969696", "#bdbdbd", "#d9d9d9"
];
d3.scale.quantile = function() {
- var domain = [],
- range = [],
- thresholds = [];
+ return d3_scale_quantile([], []);
+};
+
+function d3_scale_quantile(domain, range) {
+ var thresholds;
function rescale() {
var k = 0,
n = domain.length,
q = range.length;
- thresholds.length = Math.max(0, q - 1);
+ thresholds = [];
while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
+ return scale;
}
function scale(x) {
@@ -2618,51 +2808,60 @@ d3.scale.quantile = function() {
scale.domain = function(x) {
if (!arguments.length) return domain;
domain = x.filter(function(d) { return !isNaN(d); }).sort(d3.ascending);
- rescale();
- return scale;
+ return rescale();
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
- rescale();
- return scale;
+ return rescale();
};
scale.quantiles = function() {
return thresholds;
};
- return scale;
+ scale.copy = function() {
+ return d3_scale_quantile(domain, range); // copy on write!
+ };
+
+ return rescale();
};
d3.scale.quantize = function() {
- var x0 = 0,
- x1 = 1,
- kx = 2,
- i = 1,
- range = [0, 1];
+ return d3_scale_quantize(0, 1, [0, 1]);
+};
+
+function d3_scale_quantize(x0, x1, range) {
+ var kx, i;
function scale(x) {
return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
}
- scale.domain = function(x) {
- if (!arguments.length) return [x0, x1];
- x0 = x[0];
- x1 = x[1];
+ function rescale() {
kx = range.length / (x1 - x0);
+ i = range.length - 1;
return scale;
+ }
+
+ scale.domain = function(x) {
+ if (!arguments.length) return [x0, x1];
+ x0 = +x[0];
+ x1 = +x[x.length - 1];
+ return rescale();
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
- kx = range.length / (x1 - x0);
- i = range.length - 1;
- return scale;
+ return rescale();
+ };
+
+ scale.copy = function() {
+ return d3_scale_quantize(x0, x1, range); // copy on write
};
- return scale;
+ return rescale();
};
d3.svg = {};
d3.svg.arc = function() {
@@ -2676,7 +2875,7 @@ d3.svg.arc = function() {
r1 = outerRadius.apply(this, arguments),
a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset,
a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset,
- da = a1 - a0,
+ da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0),
df = da < Math.PI ? "0" : "1",
c0 = Math.cos(a0),
s0 = Math.sin(a0),
@@ -2688,8 +2887,8 @@ d3.svg.arc = function() {
+ "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1)
+ "A" + r1 + "," + r1 + " 0 1,1 0," + r1
+ "M0," + r0
- + "A" + r0 + "," + r0 + " 0 1,1 0," + (-r0)
- + "A" + r0 + "," + r0 + " 0 1,1 0," + r0
+ + "A" + r0 + "," + r0 + " 0 1,0 0," + (-r0)
+ + "A" + r0 + "," + r0 + " 0 1,0 0," + r0
+ "Z"
: "M0," + r1
+ "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1)
@@ -2855,33 +3054,30 @@ var d3_svg_lineInterpolators = {
// Linear interpolation; generates "L" commands.
function d3_svg_lineLinear(points) {
- var path = [],
- i = 0,
+ var i = 0,
n = points.length,
- p = points[0];
- path.push(p[0], ",", p[1]);
+ p = points[0],
+ path = [p[0], ",", p[1]];
while (++i < n) path.push("L", (p = points[i])[0], ",", p[1]);
return path.join("");
}
// Step interpolation; generates "H" and "V" commands.
function d3_svg_lineStepBefore(points) {
- var path = [],
- i = 0,
+ var i = 0,
n = points.length,
- p = points[0];
- path.push(p[0], ",", p[1]);
+ p = points[0],
+ path = [p[0], ",", p[1]];
while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
return path.join("");
}
// Step interpolation; generates "H" and "V" commands.
function d3_svg_lineStepAfter(points) {
- var path = [],
- i = 0,
+ var i = 0,
n = points.length,
- p = points[0];
- path.push(p[0], ",", p[1]);
+ p = points[0],
+ path = [p[0], ",", p[1]];
while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
return path.join("");
}
@@ -2979,15 +3175,14 @@ function d3_svg_lineCardinalTangents(points, tension) {
// B-spline interpolation; generates "C" commands.
function d3_svg_lineBasis(points) {
if (points.length < 3) return d3_svg_lineLinear(points);
- var path = [],
- i = 1,
+ var i = 1,
n = points.length,
pi = points[0],
x0 = pi[0],
y0 = pi[1],
px = [x0, x0, x0, (pi = points[1])[0]],
- py = [y0, y0, y0, pi[1]];
- path.push(x0, ",", y0);
+ py = [y0, y0, y0, pi[1]],
+ path = [x0, ",", y0];
d3_svg_lineBasisBezier(path, px, py);
while (++i < n) {
pi = points[i];
@@ -3206,16 +3401,17 @@ function d3_svg_area(projection) {
x1 = d3_svg_lineX,
y0 = 0,
y1 = d3_svg_lineY,
- interpolate = "linear",
- interpolator = d3_svg_lineInterpolators[interpolate],
+ interpolate,
+ i0,
+ i1,
tension = .7;
function area(d) {
if (d.length < 1) return null;
var points0 = d3_svg_linePoints(this, d, x0, y0),
points1 = d3_svg_linePoints(this, d, x0 === x1 ? d3_svg_areaX(points0) : x1, y0 === y1 ? d3_svg_areaY(points0) : y1);
- return "M" + interpolator(projection(points1), tension)
- + "L" + interpolator(projection(points0.reverse()), tension)
+ return "M" + i0(projection(points1), tension)
+ + "L" + i1(projection(points0.reverse()), tension)
+ "Z";
}
@@ -3257,7 +3453,8 @@ function d3_svg_area(projection) {
area.interpolate = function(x) {
if (!arguments.length) return interpolate;
- interpolator = d3_svg_lineInterpolators[interpolate = x];
+ i0 = d3_svg_lineInterpolators[interpolate = x];
+ i1 = i0.reverse || i0;
return area;
};
@@ -3267,9 +3464,12 @@ function d3_svg_area(projection) {
return area;
};
- return area;
+ return area.interpolate("linear");
}
+d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
+d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
+
d3.svg.area = function() {
return d3_svg_area(Object);
};
@@ -3308,10 +3508,10 @@ d3.svg.chord = function() {
var s = subgroup(this, source, d, i),
t = subgroup(this, target, d, i);
return "M" + s.p0
- + arc(s.r, s.p1) + (equals(s, t)
+ + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t)
? curve(s.r, s.p1, s.r, s.p0)
: curve(s.r, s.p1, t.r, t.p0)
- + arc(t.r, t.p1)
+ + arc(t.r, t.p1, t.a1 - t.a0)
+ curve(t.r, t.p1, s.r, s.p0))
+ "Z";
}
@@ -3334,8 +3534,8 @@ d3.svg.chord = function() {
return a.a0 == b.a0 && a.a1 == b.a1;
}
- function arc(r, p) {
- return "A" + r + "," + r + " 0 0,1 " + p;
+ function arc(r, p, a) {
+ return "A" + r + "," + r + " 0 " + +(a > Math.PI) + ",1 " + p;
}
function curve(r0, p0, r1, p1) {
@@ -3465,7 +3665,7 @@ function d3_svg_mousePoint(container, e) {
var point = (container.ownerSVGElement || container).createSVGPoint();
if ((d3_mouse_bug44083 < 0) && (window.scrollX || window.scrollY)) {
var svg = d3.select(document.body)
- .append("svg:svg")
+ .append("svg")
.style("position", "absolute")
.style("top", 0)
.style("left", 0);
@@ -3483,8 +3683,9 @@ function d3_svg_mousePoint(container, e) {
point = point.matrixTransform(container.getScreenCTM().inverse());
return [point.x, point.y];
};
-d3.svg.touches = function(container) {
- var touches = d3.event.touches;
+d3.svg.touches = function(container, touches) {
+ if (arguments.length < 2) touches = d3.event.touches;
+
return touches ? d3_array(touches).map(function(touch) {
var point = d3_svg_mousePoint(container, touch);
point.identifier = touch.identifier;
@@ -3589,4 +3790,906 @@ d3.svg.symbolTypes = d3.keys(d3_svg_symbols);
var d3_svg_symbolSqrt3 = Math.sqrt(3),
d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180);
+d3.svg.axis = function() {
+ var scale = d3.scale.linear(),
+ orient = "bottom",
+ tickMajorSize = 6,
+ tickMinorSize = 6,
+ tickEndSize = 6,
+ tickPadding = 3,
+ tickArguments_ = [10],
+ tickFormat_,
+ tickSubdivide = 0;
+
+ function axis(selection) {
+ selection.each(function(d, i, j) {
+ var g = d3.select(this);
+
+ // If selection is a transition, create subtransitions.
+ var transition = selection.delay ? function(o) {
+ var id = d3_transitionInheritId;
+ try {
+ d3_transitionInheritId = selection.id;
+ return o.transition()
+ .delay(selection[j][i].delay)
+ .duration(selection[j][i].duration)
+ .ease(selection.ease());
+ } finally {
+ d3_transitionInheritId = id;
+ }
+ } : Object;
+
+ // Ticks, or domain values for ordinal scales.
+ var ticks = scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain(),
+ tickFormat = tickFormat_ == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String) : tickFormat_;
+
+ // Minor ticks.
+ var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide),
+ subtick = g.selectAll(".minor").data(subticks, String),
+ subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6),
+ subtickExit = transition(subtick.exit()).style("opacity", 1e-6).remove(),
+ subtickUpdate = transition(subtick).style("opacity", 1);
+
+ // Major ticks.
+ var tick = g.selectAll("g").data(ticks, String),
+ tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6),
+ tickExit = transition(tick.exit()).style("opacity", 1e-6).remove(),
+ tickUpdate = transition(tick).style("opacity", 1),
+ tickTransform;
+
+ // Domain.
+ var range = d3_scaleRange(scale),
+ path = g.selectAll(".domain").data([0]),
+ pathEnter = path.enter().append("path").attr("class", "domain"),
+ pathUpdate = transition(path);
+
+ // Stash a snapshot of the new scale, and retrieve the old snapshot.
+ var scale1 = scale.copy(),
+ scale0 = this.__chart__ || scale1;
+ this.__chart__ = scale1;
+
+ tickEnter.append("line").attr("class", "tick");
+ tickEnter.append("text");
+ tickUpdate.select("text").text(tickFormat);
+
+ switch (orient) {
+ case "bottom": {
+ tickTransform = d3_svg_axisX;
+ subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
+ tickUpdate.select("line").attr("x2", 0).attr("y2", tickMajorSize);
+ tickUpdate.select("text").attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding).attr("dy", ".71em").attr("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
+ break;
+ }
+ case "top": {
+ tickTransform = d3_svg_axisX;
+ subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
+ tickUpdate.select("line").attr("x2", 0).attr("y2", -tickMajorSize);
+ tickUpdate.select("text").attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("dy", "0em").attr("text-anchor", "middle");
+ pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
+ break;
+ }
+ case "left": {
+ tickTransform = d3_svg_axisY;
+ subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
+ tickUpdate.select("line").attr("x2", -tickMajorSize).attr("y2", 0);
+ tickUpdate.select("text").attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "end");
+ pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
+ break;
+ }
+ case "right": {
+ tickTransform = d3_svg_axisY;
+ subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
+ tickUpdate.select("line").attr("x2", tickMajorSize).attr("y2", 0);
+ tickUpdate.select("text").attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "start");
+ pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
+ break;
+ }
+ }
+
+ // For quantitative scales:
+ // - enter new ticks from the old scale
+ // - exit old ticks to the new scale
+ if (scale.ticks) {
+ tickEnter.call(tickTransform, scale0);
+ tickUpdate.call(tickTransform, scale1);
+ tickExit.call(tickTransform, scale1);
+ subtickEnter.call(tickTransform, scale0);
+ subtickUpdate.call(tickTransform, scale1);
+ subtickExit.call(tickTransform, scale1);
+ }
+
+ // For ordinal scales:
+ // - any entering ticks are undefined in the old scale
+ // - any exiting ticks are undefined in the new scale
+ // Therefore, we only need to transition updating ticks.
+ else {
+ var dx = scale1.rangeBand() / 2, x = function(d) { return scale1(d) + dx; };
+ tickEnter.call(tickTransform, x);
+ tickUpdate.call(tickTransform, x);
+ }
+ });
+ }
+
+ axis.scale = function(x) {
+ if (!arguments.length) return scale;
+ scale = x;
+ return axis;
+ };
+
+ axis.orient = function(x) {
+ if (!arguments.length) return orient;
+ orient = x;
+ return axis;
+ };
+
+ axis.ticks = function() {
+ if (!arguments.length) return tickArguments_;
+ tickArguments_ = arguments;
+ return axis;
+ };
+
+ axis.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat_;
+ tickFormat_ = x;
+ return axis;
+ };
+
+ axis.tickSize = function(x, y, z) {
+ if (!arguments.length) return tickMajorSize;
+ var n = arguments.length - 1;
+ tickMajorSize = +x;
+ tickMinorSize = n > 1 ? +y : tickMajorSize;
+ tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
+ return axis;
+ };
+
+ axis.tickPadding = function(x) {
+ if (!arguments.length) return tickPadding;
+ tickPadding = +x;
+ return axis;
+ };
+
+ axis.tickSubdivide = function(x) {
+ if (!arguments.length) return tickSubdivide;
+ tickSubdivide = +x;
+ return axis;
+ };
+
+ return axis;
+};
+
+function d3_svg_axisX(selection, x) {
+ selection.attr("transform", function(d) { return "translate(" + x(d) + ",0)"; });
+}
+
+function d3_svg_axisY(selection, y) {
+ selection.attr("transform", function(d) { return "translate(0," + y(d) + ")"; });
+}
+
+function d3_svg_axisSubdivide(scale, ticks, m) {
+ subticks = [];
+ if (m && ticks.length > 1) {
+ var extent = d3_scaleExtent(scale.domain()),
+ subticks,
+ i = -1,
+ n = ticks.length,
+ d = (ticks[1] - ticks[0]) / ++m,
+ j,
+ v;
+ while (++i < n) {
+ for (j = m; --j > 0;) {
+ if ((v = +ticks[i] - j * d) >= extent[0]) {
+ subticks.push(v);
+ }
+ }
+ }
+ for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
+ subticks.push(v);
+ }
+ }
+ return subticks;
+}
+d3.svg.brush = function() {
+ var event = d3.dispatch("brushstart", "brush", "brushend"),
+ x, // x-scale, optional
+ y, // y-scale, optional
+ extent = [[0, 0], [0, 0]]; // [x0, y0], [x1, y1]
+
+ function brush(g) {
+ var resizes = x && y ? ["n", "e", "s", "w", "nw", "ne", "se", "sw"]
+ : x ? ["e", "w"]
+ : y ? ["n", "s"]
+ : [];
+
+ g.each(function() {
+ var g = d3.select(this).on("mousedown.brush", down),
+ bg = g.selectAll(".background").data([,]),
+ fg = g.selectAll(".extent").data([,]),
+ tz = g.selectAll(".resize").data(resizes, String),
+ e;
+
+ // An invisible, mouseable area for starting a new brush.
+ bg.enter().append("rect")
+ .attr("class", "background")
+ .style("visibility", "hidden")
+ .style("pointer-events", "all")
+ .style("cursor", "crosshair");
+
+ // The visible brush extent; style this as you like!
+ fg.enter().append("rect")
+ .attr("class", "extent")
+ .style("cursor", "move");
+
+ // More invisible rects for resizing the extent.
+ tz.enter().append("rect")
+ .attr("class", function(d) { return "resize " + d; })
+ .attr("width", 6)
+ .attr("height", 6)
+ .style("visibility", "hidden")
+ .style("pointer-events", brush.empty() ? "none" : "all")
+ .style("cursor", function(d) { return d3_svg_brushCursor[d]; });
+
+ // Remove any superfluous resizers.
+ tz.exit().remove();
+
+ // Initialize the background to fill the defined range.
+ // If the range isn't defined, you can post-process.
+ if (x) {
+ e = d3_scaleRange(x);
+ bg.attr("x", e[0]).attr("width", e[1] - e[0]);
+ d3_svg_brushRedrawX(g, extent);
+ }
+ if (y) {
+ e = d3_scaleRange(y);
+ bg.attr("y", e[0]).attr("height", e[1] - e[0]);
+ d3_svg_brushRedrawY(g, extent);
+ }
+ });
+ }
+
+ function down() {
+ var target = d3.select(d3.event.target);
+
+ // Store some global state for the duration of the brush gesture.
+ d3_svg_brush = brush;
+ d3_svg_brushTarget = this;
+ d3_svg_brushExtent = extent;
+ d3_svg_brushOffset = d3.svg.mouse(d3_svg_brushTarget);
+
+ // If the extent was clicked on, drag rather than brush;
+ // store the offset between the mouse and extent origin instead.
+ if (d3_svg_brushDrag = target.classed("extent")) {
+ d3_svg_brushOffset[0] = extent[0][0] - d3_svg_brushOffset[0];
+ d3_svg_brushOffset[1] = extent[0][1] - d3_svg_brushOffset[1];
+ }
+
+ // If a resizer was clicked on, record which side is to be resized.
+ // Also, set the offset to the opposite side.
+ else if (target.classed("resize")) {
+ d3_svg_brushResize = d3.event.target.__data__;
+ d3_svg_brushOffset[0] = extent[+/w$/.test(d3_svg_brushResize)][0];
+ d3_svg_brushOffset[1] = extent[+/^n/.test(d3_svg_brushResize)][1];
+ }
+
+ // If the ALT key is down when starting a brush, the center is at the mouse.
+ else if (d3.event.altKey) {
+ d3_svg_brushCenter = d3_svg_brushOffset.slice();
+ }
+
+ // Restrict which dimensions are resized.
+ d3_svg_brushX = !/^(n|s)$/.test(d3_svg_brushResize) && x;
+ d3_svg_brushY = !/^(e|w)$/.test(d3_svg_brushResize) && y;
+
+ // Notify listeners.
+ d3_svg_brushDispatch = dispatcher(this, arguments);
+ d3_svg_brushDispatch("brushstart");
+ d3_svg_brushMove();
+ d3_eventCancel();
+ }
+
+ function dispatcher(that, argumentz) {
+ return function(type) {
+ var e = d3.event;
+ try {
+ d3.event = {type: type, target: brush};
+ event[type].apply(that, argumentz);
+ } finally {
+ d3.event = e;
+ }
+ };
+ }
+
+ brush.x = function(z) {
+ if (!arguments.length) return x;
+ x = z;
+ return brush;
+ };
+
+ brush.y = function(z) {
+ if (!arguments.length) return y;
+ y = z;
+ return brush;
+ };
+
+ brush.extent = function(z) {
+ var x0, x1, y0, y1, t;
+
+ // Invert the pixel extent to data-space.
+ if (!arguments.length) {
+ if (x) {
+ x0 = extent[0][0], x1 = extent[1][0];
+ if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ }
+ if (y) {
+ y0 = extent[0][1], y1 = extent[1][1];
+ if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ }
+ return x && y ? [[x0, y0], [x1, y1]] : x ? [x0, x1] : y && [y0, y1];
+ }
+
+ // Scale the data-space extent to pixels.
+ if (x) {
+ x0 = z[0], x1 = z[1];
+ if (y) x0 = x0[0], x1 = x1[0];
+ if (x.invert) x0 = x(x0), x1 = x(x1);
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
+ extent[0][0] = x0, extent[1][0] = x1;
+ }
+ if (y) {
+ y0 = z[0], y1 = z[1];
+ if (x) y0 = y0[1], y1 = y1[1];
+ if (y.invert) y0 = y(y0), y1 = y(y1);
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
+ extent[0][1] = y0, extent[1][1] = y1;
+ }
+
+ return brush;
+ };
+
+ brush.clear = function() {
+ extent[0][0] =
+ extent[0][1] =
+ extent[1][0] =
+ extent[1][1] = 0;
+ return brush;
+ };
+
+ brush.empty = function() {
+ return (x && extent[0][0] === extent[1][0])
+ || (y && extent[0][1] === extent[1][1]);
+ };
+
+ d3.select(window)
+ .on("mousemove.brush", d3_svg_brushMove)
+ .on("mouseup.brush", d3_svg_brushUp)
+ .on("keydown.brush", d3_svg_brushKeydown)
+ .on("keyup.brush", d3_svg_brushKeyup);
+
+ return d3.rebind(brush, event, "on");
+};
+
+var d3_svg_brush,
+ d3_svg_brushDispatch,
+ d3_svg_brushTarget,
+ d3_svg_brushX,
+ d3_svg_brushY,
+ d3_svg_brushExtent,
+ d3_svg_brushDrag,
+ d3_svg_brushResize,
+ d3_svg_brushCenter,
+ d3_svg_brushOffset;
+
+function d3_svg_brushRedrawX(g, extent) {
+ g.select(".extent").attr("x", extent[0][0]);
+ g.selectAll(".n,.s,.w,.nw,.sw").attr("x", extent[0][0] - 2);
+ g.selectAll(".e,.ne,.se").attr("x", extent[1][0] - 3);
+ g.selectAll(".extent,.n,.s").attr("width", extent[1][0] - extent[0][0]);
+}
+
+function d3_svg_brushRedrawY(g, extent) {
+ g.select(".extent").attr("y", extent[0][1]);
+ g.selectAll(".n,.e,.w,.nw,.ne").attr("y", extent[0][1] - 3);
+ g.selectAll(".s,.se,.sw").attr("y", extent[1][1] - 4);
+ g.selectAll(".extent,.e,.w").attr("height", extent[1][1] - extent[0][1]);
+}
+
+function d3_svg_brushKeydown() {
+ if (d3.event.keyCode == 32 && d3_svg_brushTarget && !d3_svg_brushDrag) {
+ d3_svg_brushCenter = null;
+ d3_svg_brushOffset[0] -= d3_svg_brushExtent[1][0];
+ d3_svg_brushOffset[1] -= d3_svg_brushExtent[1][1];
+ d3_svg_brushDrag = 2;
+ d3_eventCancel();
+ }
+}
+
+function d3_svg_brushKeyup() {
+ if (d3.event.keyCode == 32 && d3_svg_brushDrag == 2) {
+ d3_svg_brushOffset[0] += d3_svg_brushExtent[1][0];
+ d3_svg_brushOffset[1] += d3_svg_brushExtent[1][1];
+ d3_svg_brushDrag = 0;
+ d3_eventCancel();
+ }
+}
+
+function d3_svg_brushMove() {
+ if (d3_svg_brushOffset) {
+ var mouse = d3.svg.mouse(d3_svg_brushTarget),
+ g = d3.select(d3_svg_brushTarget);
+
+ if (!d3_svg_brushDrag) {
+
+ // If needed, determine the center from the current extent.
+ if (d3.event.altKey) {
+ if (!d3_svg_brushCenter) {
+ d3_svg_brushCenter = [
+ (d3_svg_brushExtent[0][0] + d3_svg_brushExtent[1][0]) / 2,
+ (d3_svg_brushExtent[0][1] + d3_svg_brushExtent[1][1]) / 2
+ ];
+ }
+
+ // Update the offset, for when the ALT key is released.
+ d3_svg_brushOffset[0] = d3_svg_brushExtent[+(mouse[0] < d3_svg_brushCenter[0])][0];
+ d3_svg_brushOffset[1] = d3_svg_brushExtent[+(mouse[1] < d3_svg_brushCenter[1])][1];
+ }
+
+ // When the ALT key is released, we clear the center.
+ else d3_svg_brushCenter = null;
+ }
+
+ // Update the brush extent for each dimension.
+ if (d3_svg_brushX) {
+ d3_svg_brushMove1(mouse, d3_svg_brushX, 0);
+ d3_svg_brushRedrawX(g, d3_svg_brushExtent);
+ }
+ if (d3_svg_brushY) {
+ d3_svg_brushMove1(mouse, d3_svg_brushY, 1);
+ d3_svg_brushRedrawY(g, d3_svg_brushExtent);
+ }
+
+ // Notify listeners.
+ d3_svg_brushDispatch("brush");
+ }
+}
+
+function d3_svg_brushMove1(mouse, scale, i) {
+ var range = d3_scaleRange(scale),
+ r0 = range[0],
+ r1 = range[1],
+ offset = d3_svg_brushOffset[i],
+ size = d3_svg_brushExtent[1][i] - d3_svg_brushExtent[0][i],
+ min,
+ max;
+
+ // When dragging, reduce the range by the extent size and offset.
+ if (d3_svg_brushDrag) {
+ r0 -= offset;
+ r1 -= size + offset;
+ }
+
+ // Clamp the mouse so that the extent fits within the range extent.
+ min = Math.max(r0, Math.min(r1, mouse[i]));
+
+ // Compute the new extent bounds.
+ if (d3_svg_brushDrag) {
+ max = (min += offset) + size;
+ } else {
+
+ // If the ALT key is pressed, then preserve the center of the extent.
+ if (d3_svg_brushCenter) offset = Math.max(r0, Math.min(r1, 2 * d3_svg_brushCenter[i] - min));
+
+ // Compute the min and max of the offset and mouse.
+ if (offset < min) {
+ max = min;
+ min = offset;
+ } else {
+ max = offset;
+ }
+ }
+
+ // Update the stored bounds.
+ d3_svg_brushExtent[0][i] = min;
+ d3_svg_brushExtent[1][i] = max;
+}
+
+function d3_svg_brushUp() {
+ if (d3_svg_brushOffset) {
+ d3_svg_brushMove();
+ d3.select(d3_svg_brushTarget).selectAll(".resize").style("pointer-events", d3_svg_brush.empty() ? "none" : "all");
+ d3_svg_brushDispatch("brushend");
+ d3_svg_brush =
+ d3_svg_brushDispatch =
+ d3_svg_brushTarget =
+ d3_svg_brushX =
+ d3_svg_brushY =
+ d3_svg_brushExtent =
+ d3_svg_brushDrag =
+ d3_svg_brushResize =
+ d3_svg_brushCenter =
+ d3_svg_brushOffset = null;
+ d3_eventCancel();
+ }
+}
+
+var d3_svg_brushCursor = {
+ n: "ns-resize",
+ e: "ew-resize",
+ s: "ns-resize",
+ w: "ew-resize",
+ nw: "nwse-resize",
+ ne: "nesw-resize",
+ se: "nwse-resize",
+ sw: "nesw-resize"
+};
+d3.behavior = {};
+// TODO Track touch points by identifier.
+
+d3.behavior.drag = function() {
+ var event = d3.dispatch("drag", "dragstart", "dragend"),
+ origin = null;
+
+ function drag() {
+ this
+ .on("mousedown.drag", mousedown)
+ .on("touchstart.drag", mousedown);
+
+ d3.select(window)
+ .on("mousemove.drag", d3_behavior_dragMove)
+ .on("touchmove.drag", d3_behavior_dragMove)
+ .on("mouseup.drag", d3_behavior_dragUp, true)
+ .on("touchend.drag", d3_behavior_dragUp, true)
+ .on("click.drag", d3_behavior_dragClick, true);
+ }
+
+ // snapshot the local context for subsequent dispatch
+ function start() {
+ d3_behavior_dragEvent = event;
+ d3_behavior_dragEventTarget = d3.event.target;
+ d3_behavior_dragTarget = this;
+ d3_behavior_dragArguments = arguments;
+ d3_behavior_dragOrigin = d3_behavior_dragPoint();
+ if (origin) {
+ d3_behavior_dragOffset = origin.apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
+ d3_behavior_dragOffset = [d3_behavior_dragOffset.x - d3_behavior_dragOrigin[0], d3_behavior_dragOffset.y - d3_behavior_dragOrigin[1]];
+ } else {
+ d3_behavior_dragOffset = [0, 0];
+ }
+ d3_behavior_dragMoved = 0;
+ }
+
+ function mousedown() {
+ start.apply(this, arguments);
+ d3_behavior_dragDispatch("dragstart");
+ }
+
+ drag.origin = function(x) {
+ if (!arguments.length) return origin;
+ origin = x;
+ return drag;
+ };
+
+ return d3.rebind(drag, event, "on");
+};
+
+var d3_behavior_dragEvent,
+ d3_behavior_dragEventTarget,
+ d3_behavior_dragTarget,
+ d3_behavior_dragArguments,
+ d3_behavior_dragOffset,
+ d3_behavior_dragOrigin,
+ d3_behavior_dragMoved;
+
+function d3_behavior_dragDispatch(type) {
+ var p = d3_behavior_dragPoint(),
+ o = d3.event,
+ e = d3.event = {type: type};
+
+ if (p) {
+ e.x = p[0] + d3_behavior_dragOffset[0];
+ e.y = p[1] + d3_behavior_dragOffset[1];
+ e.dx = p[0] - d3_behavior_dragOrigin[0];
+ e.dy = p[1] - d3_behavior_dragOrigin[1];
+ d3_behavior_dragMoved |= e.dx | e.dy;
+ d3_behavior_dragOrigin = p;
+ }
+
+ try {
+ d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
+ } finally {
+ d3.event = o;
+ }
+
+ o.stopPropagation();
+ o.preventDefault();
+}
+
+function d3_behavior_dragPoint() {
+ var p = d3_behavior_dragTarget.parentNode,
+ t = d3.event.changedTouches;
+ return p && (t
+ ? d3.svg.touches(p, t)[0]
+ : d3.svg.mouse(p));
+}
+
+function d3_behavior_dragMove() {
+ if (!d3_behavior_dragTarget) return;
+ var parent = d3_behavior_dragTarget.parentNode;
+
+ // O NOES! The drag element was removed from the DOM.
+ if (!parent) return d3_behavior_dragUp();
+
+ d3_behavior_dragDispatch("drag");
+ d3_eventCancel();
+}
+
+function d3_behavior_dragUp() {
+ if (!d3_behavior_dragTarget) return;
+ d3_behavior_dragDispatch("dragend");
+
+ // If the node was moved, prevent the mouseup from propagating.
+ // Also prevent the subsequent click from propagating (e.g., for anchors).
+ if (d3_behavior_dragMoved) {
+ d3_eventCancel();
+ d3_behavior_dragMoved = d3.event.target === d3_behavior_dragEventTarget;
+ }
+
+ d3_behavior_dragEvent =
+ d3_behavior_dragEventTarget =
+ d3_behavior_dragTarget =
+ d3_behavior_dragArguments =
+ d3_behavior_dragOffset =
+ d3_behavior_dragOrigin = null;
+}
+
+function d3_behavior_dragClick() {
+ if (d3_behavior_dragMoved) {
+ d3_eventCancel();
+ d3_behavior_dragMoved = 0;
+ }
+}
+// TODO unbind zoom behavior?
+d3.behavior.zoom = function() {
+ var xyz = [0, 0, 0],
+ event = d3.dispatch("zoom"),
+ extent = d3_behavior_zoomInfiniteExtent;
+
+ function zoom() {
+ this
+ .on("mousedown.zoom", mousedown)
+ .on("mousewheel.zoom", mousewheel)
+ .on("DOMMouseScroll.zoom", mousewheel)
+ .on("dblclick.zoom", dblclick)
+ .on("touchstart.zoom", touchstart);
+
+ d3.select(window)
+ .on("mousemove.zoom", d3_behavior_zoomMousemove)
+ .on("mouseup.zoom", d3_behavior_zoomMouseup)
+ .on("touchmove.zoom", d3_behavior_zoomTouchmove)
+ .on("touchend.zoom", d3_behavior_zoomTouchup)
+ .on("click.zoom", d3_behavior_zoomClick, true);
+ }
+
+ // snapshot the local context for subsequent dispatch
+ function start() {
+ d3_behavior_zoomXyz = xyz;
+ d3_behavior_zoomExtent = extent;
+ d3_behavior_zoomDispatch = event.zoom;
+ d3_behavior_zoomEventTarget = d3.event.target;
+ d3_behavior_zoomTarget = this;
+ d3_behavior_zoomArguments = arguments;
+ }
+
+ function mousedown() {
+ start.apply(this, arguments);
+ d3_behavior_zoomPanning = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
+ d3_behavior_zoomMoved = 0;
+ d3.event.preventDefault();
+ window.focus();
+ }
+
+ // store starting mouse location
+ function mousewheel() {
+ start.apply(this, arguments);
+ if (!d3_behavior_zoomZooming) d3_behavior_zoomZooming = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
+ d3_behavior_zoomTo(d3_behavior_zoomDelta() + xyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomZooming);
+ }
+
+ function dblclick() {
+ start.apply(this, arguments);
+ var mouse = d3.svg.mouse(d3_behavior_zoomTarget);
+ d3_behavior_zoomTo(d3.event.shiftKey ? Math.ceil(xyz[2] - 1) : Math.floor(xyz[2] + 1), mouse, d3_behavior_zoomLocation(mouse));
+ }
+
+ // doubletap detection
+ function touchstart() {
+ start.apply(this, arguments);
+ var touches = d3_behavior_zoomTouchup(),
+ touch,
+ now = Date.now();
+ if ((touches.length === 1) && (now - d3_behavior_zoomLast < 300)) {
+ d3_behavior_zoomTo(1 + Math.floor(xyz[2]), touch = touches[0], d3_behavior_zoomLocations[touch.identifier]);
+ }
+ d3_behavior_zoomLast = now;
+ }
+
+ zoom.extent = function(x) {
+ if (!arguments.length) return extent;
+ extent = x == null ? d3_behavior_zoomInfiniteExtent : x;
+ return zoom;
+ };
+
+ return d3.rebind(zoom, event, "on");
+};
+
+var d3_behavior_zoomDiv,
+ d3_behavior_zoomPanning,
+ d3_behavior_zoomZooming,
+ d3_behavior_zoomLocations = {}, // identifier -> location
+ d3_behavior_zoomLast = 0,
+ d3_behavior_zoomXyz,
+ d3_behavior_zoomExtent,
+ d3_behavior_zoomDispatch,
+ d3_behavior_zoomEventTarget,
+ d3_behavior_zoomTarget,
+ d3_behavior_zoomArguments,
+ d3_behavior_zoomMoved;
+
+function d3_behavior_zoomLocation(point) {
+ return [
+ point[0] - d3_behavior_zoomXyz[0],
+ point[1] - d3_behavior_zoomXyz[1],
+ d3_behavior_zoomXyz[2]
+ ];
+}
+
+// detect the pixels that would be scrolled by this wheel event
+function d3_behavior_zoomDelta() {
+
+ // mousewheel events are totally broken!
+ // https://bugs.webkit.org/show_bug.cgi?id=40441
+ // not only that, but Chrome and Safari differ in re. to acceleration!
+ if (!d3_behavior_zoomDiv) {
+ d3_behavior_zoomDiv = d3.select("body").append("div")
+ .style("visibility", "hidden")
+ .style("top", 0)
+ .style("height", 0)
+ .style("width", 0)
+ .style("overflow-y", "scroll")
+ .append("div")
+ .style("height", "2000px")
+ .node().parentNode;
+ }
+
+ var e = d3.event, delta;
+ try {
+ d3_behavior_zoomDiv.scrollTop = 1000;
+ d3_behavior_zoomDiv.dispatchEvent(e);
+ delta = 1000 - d3_behavior_zoomDiv.scrollTop;
+ } catch (error) {
+ delta = e.wheelDelta || (-e.detail * 5);
+ }
+
+ return delta * .005;
+}
+
+// Note: Since we don't rotate, it's possible for the touches to become
+// slightly detached from their original positions. Thus, we recompute the
+// touch points on touchend as well as touchstart!
+function d3_behavior_zoomTouchup() {
+ var touches = d3.svg.touches(d3_behavior_zoomTarget),
+ i = -1,
+ n = touches.length,
+ touch;
+ while (++i < n) d3_behavior_zoomLocations[(touch = touches[i]).identifier] = d3_behavior_zoomLocation(touch);
+ return touches;
+}
+
+function d3_behavior_zoomTouchmove() {
+ var touches = d3.svg.touches(d3_behavior_zoomTarget);
+ switch (touches.length) {
+
+ // single-touch pan
+ case 1: {
+ var touch = touches[0];
+ d3_behavior_zoomTo(d3_behavior_zoomXyz[2], touch, d3_behavior_zoomLocations[touch.identifier]);
+ break;
+ }
+
+ // double-touch pan + zoom
+ case 2: {
+ var p0 = touches[0],
+ p1 = touches[1],
+ p2 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2],
+ l0 = d3_behavior_zoomLocations[p0.identifier],
+ l1 = d3_behavior_zoomLocations[p1.identifier],
+ l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2, l0[2]];
+ d3_behavior_zoomTo(Math.log(d3.event.scale) / Math.LN2 + l0[2], p2, l2);
+ break;
+ }
+ }
+}
+
+function d3_behavior_zoomMousemove() {
+ d3_behavior_zoomZooming = null;
+ if (d3_behavior_zoomPanning) {
+ d3_behavior_zoomMoved = 1;
+ d3_behavior_zoomTo(d3_behavior_zoomXyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomPanning);
+ }
+}
+
+function d3_behavior_zoomMouseup() {
+ if (d3_behavior_zoomPanning) {
+ if (d3_behavior_zoomMoved) {
+ d3_eventCancel();
+ d3_behavior_zoomMoved = d3_behavior_zoomEventTarget === d3.event.target;
+ }
+
+ d3_behavior_zoomXyz =
+ d3_behavior_zoomExtent =
+ d3_behavior_zoomDispatch =
+ d3_behavior_zoomEventTarget =
+ d3_behavior_zoomTarget =
+ d3_behavior_zoomArguments =
+ d3_behavior_zoomPanning = null;
+ }
+}
+
+function d3_behavior_zoomClick() {
+ if (d3_behavior_zoomMoved) {
+ d3_eventCancel();
+ d3_behavior_zoomMoved = 0;
+ }
+}
+
+function d3_behavior_zoomTo(z, x0, x1) {
+ z = d3_behavior_zoomExtentClamp(z, 2);
+ var j = Math.pow(2, d3_behavior_zoomXyz[2]),
+ k = Math.pow(2, z),
+ K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
+ x_ = d3_behavior_zoomXyz[0],
+ y_ = d3_behavior_zoomXyz[1],
+ x = d3_behavior_zoomXyz[0] = d3_behavior_zoomExtentClamp((x0[0] - x1[0] * K), 0, k),
+ y = d3_behavior_zoomXyz[1] = d3_behavior_zoomExtentClamp((x0[1] - x1[1] * K), 1, k),
+ o = d3.event; // Events can be reentrant (e.g., focus).
+
+ d3.event = {
+ scale: k,
+ translate: [x, y],
+ transform: function(sx, sy) {
+ if (sx) transform(sx, x_, x);
+ if (sy) transform(sy, y_, y);
+ }
+ };
+
+ function transform(scale, a, b) {
+ scale.domain(scale.range().map(function(v) { return scale.invert(((v - b) * j) / k + a); }));
+ }
+
+ try {
+ d3_behavior_zoomDispatch.apply(d3_behavior_zoomTarget, d3_behavior_zoomArguments);
+ } finally {
+ d3.event = o;
+ }
+
+ o.preventDefault();
+}
+
+var d3_behavior_zoomInfiniteExtent = [
+ [-Infinity, Infinity],
+ [-Infinity, Infinity],
+ [-Infinity, Infinity]
+];
+
+function d3_behavior_zoomExtentClamp(x, i, k) {
+ var range = d3_behavior_zoomExtent[i],
+ r0 = range[0],
+ r1 = range[1];
+ return arguments.length === 3
+ ? Math.max(r1 * (r1 === Infinity ? -Infinity : 1 / k - 1),
+ Math.min(r0 === -Infinity ? Infinity : r0, x / k)) * k
+ : Math.max(r0, Math.min(r1, x));
+}
})();
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.layout.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.layout.js
index 76ddee0..24bcc42 100755
--- a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.layout.js
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.layout.js
@@ -113,16 +113,19 @@ d3.layout.chord = function() {
k = (2 * Math.PI - padding * n) / k;
// Compute the start and end angle for each group and subgroup.
+ // Note: Opera has a bug reordering object literal properties!
x = 0, i = -1; while (++i < n) {
x0 = x, j = -1; while (++j < n) {
var di = groupIndex[i],
- dj = subgroupIndex[i][j],
- v = matrix[di][dj];
+ dj = subgroupIndex[di][j],
+ v = matrix[di][dj],
+ a0 = x,
+ a1 = x += v * k;
subgroups[di + "-" + dj] = {
index: di,
subindex: dj,
- startAngle: x,
- endAngle: x += v * k,
+ startAngle: a0,
+ endAngle: a1,
value: v
};
}
@@ -143,7 +146,7 @@ d3.layout.chord = function() {
if (source.value || target.value) {
chords.push(source.value < target.value
? {source: target, target: source}
- : {source: source, target: target})
+ : {source: source, target: target});
}
}
}
@@ -153,7 +156,9 @@ d3.layout.chord = function() {
function resort() {
chords.sort(function(a, b) {
- return sortChords(a.target.value, b.target.value);
+ return sortChords(
+ (a.source.value + a.target.value) / 2,
+ (b.source.value + b.target.value) / 2);
});
}
@@ -209,6 +214,7 @@ d3.layout.force = function() {
var force = {},
event = d3.dispatch("tick"),
size = [1, 1],
+ drag,
alpha,
friction = .9,
linkDistance = d3_layout_forceLinkDistance,
@@ -220,9 +226,10 @@ d3.layout.force = function() {
nodes = [],
links = [],
distances,
- strengths;
+ strengths,
+ charges;
- function repulse(node, kc) {
+ function repulse(node) {
return function(quad, x1, y1, x2, y2) {
if (quad.point !== node) {
var dx = quad.cx - node.x,
@@ -231,30 +238,32 @@ d3.layout.force = function() {
/* Barnes-Hut criterion. */
if ((x2 - x1) * dn < theta) {
- var k = kc * quad.count * dn * dn;
- node.x += dx * k;
- node.y += dy * k;
+ var k = quad.charge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
return true;
}
if (quad.point && isFinite(dn)) {
- var k = kc * dn * dn;
- node.x += dx * k;
- node.y += dy * k;
+ var k = quad.pointCharge * dn * dn;
+ node.px -= dx * k;
+ node.py -= dy * k;
}
}
+ return !quad.charge;
};
}
function tick() {
var n = nodes.length,
m = links.length,
- q = d3.geom.quadtree(nodes),
+ q,
i, // current index
o, // current object
s, // current source
t, // current target
l, // current distance
+ k, // current force
x, // x-distance
y; // y-distance
@@ -269,30 +278,32 @@ d3.layout.force = function() {
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
x *= l;
y *= l;
- t.x -= x;
- t.y -= y;
- s.x += x;
- s.y += y;
+ t.x -= x * (k = s.weight / (t.weight + s.weight));
+ t.y -= y * k;
+ s.x += x * (k = 1 - k);
+ s.y += y * k;
}
}
// apply gravity forces
- var kg = alpha * gravity;
- x = size[0] / 2;
- y = size[1] / 2;
- i = -1; while (++i < n) {
- o = nodes[i];
- o.x += (x - o.x) * kg;
- o.y += (y - o.y) * kg;
+ if (k = alpha * gravity) {
+ x = size[0] / 2;
+ y = size[1] / 2;
+ i = -1; if (k) while (++i < n) {
+ o = nodes[i];
+ o.x += (x - o.x) * k;
+ o.y += (y - o.y) * k;
+ }
}
- // compute quadtree center of mass
- d3_layout_forceAccumulate(q);
-
- // apply charge forces
- var kc = alpha * charge;
- i = -1; while (++i < n) {
- q.visit(repulse(nodes[i], kc));
+ // compute quadtree center of mass and apply charge forces
+ if (charge) {
+ d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
+ i = -1; while (++i < n) {
+ if (!(o = nodes[i]).fixed) {
+ q.visit(repulse(o));
+ }
+ }
}
// position verlet integration
@@ -307,17 +318,12 @@ d3.layout.force = function() {
}
}
- event.tick.dispatch({type: "tick", alpha: alpha});
+ event.tick({type: "tick", alpha: alpha});
// simulated annealing, basically
return (alpha *= .99) < .005;
}
- force.on = function(type, listener) {
- event[type].add(listener);
- return force;
- };
-
force.nodes = function(x) {
if (!arguments.length) return nodes;
nodes = x;
@@ -359,7 +365,7 @@ d3.layout.force = function() {
force.charge = function(x) {
if (!arguments.length) return charge;
- charge = x;
+ charge = typeof x === "function" ? x : +x;
return force;
};
@@ -387,6 +393,7 @@ d3.layout.force = function() {
for (i = 0; i < n; ++i) {
(o = nodes[i]).index = i;
+ o.weight = 0;
}
distances = [];
@@ -397,6 +404,8 @@ d3.layout.force = function() {
if (typeof o.target == "number") o.target = nodes[o.target];
distances[i] = linkDistance.call(this, o, i);
strengths[i] = linkStrength.call(this, o, i);
+ ++o.source.weight;
+ ++o.target.weight;
}
for (i = 0; i < n; ++i) {
@@ -407,6 +416,17 @@ d3.layout.force = function() {
if (isNaN(o.py)) o.py = o.y;
}
+ charges = [];
+ if (typeof charge === "function") {
+ for (i = 0; i < n; ++i) {
+ charges[i] = +charge.call(this, nodes[i], i);
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ charges[i] = charge;
+ }
+ }
+
// initialize node position based on first neighbor
function position(dimension, size) {
var neighbors = neighbor(i),
@@ -449,116 +469,52 @@ d3.layout.force = function() {
// use `node.call(force.drag)` to make nodes draggable
force.drag = function() {
-
- this
- .on("mouseover.force", d3_layout_forceDragOver)
- .on("mouseout.force", d3_layout_forceDragOut)
- .on("mousedown.force", dragdown)
- .on("touchstart.force", dragdown);
-
- d3.select(window)
- .on("mousemove.force", d3_layout_forceDragMove)
- .on("touchmove.force", d3_layout_forceDragMove)
- .on("mouseup.force", d3_layout_forceDragUp, true)
- .on("touchend.force", d3_layout_forceDragUp, true)
- .on("click.force", d3_layout_forceDragClick, true);
-
- return force;
+ if (!drag) drag = d3.behavior.drag()
+ .origin(Object)
+ .on("dragstart", dragstart)
+ .on("drag", d3_layout_forceDrag)
+ .on("dragend", d3_layout_forceDragEnd);
+
+ this.on("mouseover.force", d3_layout_forceDragOver)
+ .on("mouseout.force", d3_layout_forceDragOut)
+ .call(drag);
};
- function dragdown(d, i) {
- var m = d3_layout_forcePoint(this.parentNode);
- (d3_layout_forceDragNode = d).fixed = true;
- d3_layout_forceDragMoved = false;
- d3_layout_forceDragElement = this;
+ function dragstart(d) {
+ d3_layout_forceDragOver(d3_layout_forceDragNode = d);
d3_layout_forceDragForce = force;
- d3_layout_forceDragOffset = [m[0] - d.x, m[1] - d.y];
- d3_layout_forceCancel();
}
- return force;
+ return d3.rebind(force, event, "on");
};
var d3_layout_forceDragForce,
- d3_layout_forceDragNode,
- d3_layout_forceDragMoved,
- d3_layout_forceDragOffset,
- d3_layout_forceStopClick,
- d3_layout_forceDragElement;
+ d3_layout_forceDragNode;
function d3_layout_forceDragOver(d) {
- d.fixed = true;
+ d.fixed |= 2;
}
function d3_layout_forceDragOut(d) {
- if (d !== d3_layout_forceDragNode) {
- d.fixed = false;
- }
+ if (d !== d3_layout_forceDragNode) d.fixed &= 1;
}
-function d3_layout_forcePoint(container) {
- return d3.event.touches
- ? d3.svg.touches(container)[0]
- : d3.svg.mouse(container);
+function d3_layout_forceDragEnd() {
+ d3_layout_forceDrag();
+ d3_layout_forceDragNode.fixed &= 1;
+ d3_layout_forceDragForce = d3_layout_forceDragNode = null;
}
-function d3_layout_forceDragMove() {
- if (!d3_layout_forceDragNode) return;
- var parent = d3_layout_forceDragElement.parentNode;
-
- // O NOES! The drag element was removed from the DOM.
- if (!parent) {
- d3_layout_forceDragNode.fixed = false;
- d3_layout_forceDragOffset = d3_layout_forceDragNode = d3_layout_forceDragElement = null;
- return;
- }
-
- var m = d3_layout_forcePoint(parent);
- d3_layout_forceDragMoved = true;
- d3_layout_forceDragNode.px = m[0] - d3_layout_forceDragOffset[0];
- d3_layout_forceDragNode.py = m[1] - d3_layout_forceDragOffset[1];
- d3_layout_forceCancel();
+function d3_layout_forceDrag() {
+ d3_layout_forceDragNode.px = d3.event.x;
+ d3_layout_forceDragNode.py = d3.event.y;
d3_layout_forceDragForce.resume(); // restart annealing
}
-function d3_layout_forceDragUp() {
- if (!d3_layout_forceDragNode) return;
-
- // If the node was moved, prevent the mouseup from propagating.
- // Also prevent the subsequent click from propagating (e.g., for anchors).
- if (d3_layout_forceDragMoved) {
- d3_layout_forceStopClick = true;
- d3_layout_forceCancel();
- }
-
- // Don't trigger this for touchend.
- if (d3.event.type === "mouseup") {
- d3_layout_forceDragMove();
- }
-
- d3_layout_forceDragNode.fixed = false;
- d3_layout_forceDragForce =
- d3_layout_forceDragOffset =
- d3_layout_forceDragNode =
- d3_layout_forceDragElement = null;
-}
-
-function d3_layout_forceDragClick() {
- if (d3_layout_forceStopClick) {
- d3_layout_forceCancel();
- d3_layout_forceStopClick = false;
- }
-}
-
-function d3_layout_forceCancel() {
- d3.event.stopPropagation();
- d3.event.preventDefault();
-}
-
-function d3_layout_forceAccumulate(quad) {
+function d3_layout_forceAccumulate(quad, alpha, charges) {
var cx = 0,
cy = 0;
- quad.count = 0;
+ quad.charge = 0;
if (!quad.leaf) {
var nodes = quad.nodes,
n = nodes.length,
@@ -567,10 +523,10 @@ function d3_layout_forceAccumulate(quad) {
while (++i < n) {
c = nodes[i];
if (c == null) continue;
- d3_layout_forceAccumulate(c);
- quad.count += c.count;
- cx += c.count * c.cx;
- cy += c.count * c.cy;
+ d3_layout_forceAccumulate(c, alpha, charges);
+ quad.charge += c.charge;
+ cx += c.charge * c.cx;
+ cy += c.charge * c.cy;
}
}
if (quad.point) {
@@ -579,12 +535,13 @@ function d3_layout_forceAccumulate(quad) {
quad.point.x += Math.random() - .5;
quad.point.y += Math.random() - .5;
}
- quad.count++;
- cx += quad.point.x;
- cy += quad.point.y;
+ var k = alpha * charges[quad.point.index];
+ quad.charge += quad.pointCharge = k;
+ cx += k * quad.point.x;
+ cy += k * quad.point.y;
}
- quad.cx = cx / quad.count;
- quad.cy = cy / quad.count;
+ quad.cx = cx / quad.charge;
+ quad.cy = cy / quad.charge;
}
function d3_layout_forceLinkDistance(link) {
@@ -604,12 +561,12 @@ d3.layout.partition = function() {
node.y = node.depth * dy;
node.dx = dx;
node.dy = dy;
- if (children) {
+ if (children && (n = children.length)) {
var i = -1,
- n = children.length,
+ n,
c,
d;
- dx /= node.value;
+ dx = node.value ? dx / node.value : 0;
while (++i < n) {
position(c = children[i], x, d = c.value * dx, dy);
x += d;
@@ -620,9 +577,9 @@ d3.layout.partition = function() {
function depth(node) {
var children = node.children,
d = 0;
- if (children) {
+ if (children && (n = children.length)) {
var i = -1,
- n = children.length;
+ n;
while (++i < n) d = Math.max(d, depth(children[i]));
}
return 1 + d;
@@ -644,48 +601,44 @@ d3.layout.partition = function() {
};
d3.layout.pie = function() {
var value = Number,
- sort = null,
+ sort = d3_layout_pieSortByValue,
startAngle = 0,
endAngle = 2 * Math.PI;
function pie(data, i) {
+ // Compute the numeric values for each data element.
+ var values = data.map(function(d, i) { return +value.call(pie, d, i); });
+
// Compute the start angle.
var a = +(typeof startAngle === "function"
? startAngle.apply(this, arguments)
: startAngle);
- // Compute the angular range (end - start).
- var k = (typeof endAngle === "function"
+ // Compute the angular scale factor: from value to radians.
+ var k = ((typeof endAngle === "function"
? endAngle.apply(this, arguments)
- : endAngle) - startAngle;
+ : endAngle) - startAngle)
+ / d3.sum(values);
// Optionally sort the data.
var index = d3.range(data.length);
- if (sort != null) index.sort(function(i, j) {
- return sort(data[i], data[j]);
- });
-
- // Compute the numeric values for each data element.
- var values = data.map(value);
-
- // Convert k into a scale factor from value to angle, using the sum.
- k /= values.reduce(function(p, d) { return p + d; }, 0);
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue
+ ? function(i, j) { return values[j] - values[i]; }
+ : function(i, j) { return sort(data[i], data[j]); });
// Compute the arcs!
- var arcs = index.map(function(i) {
- return {
+ // They are stored in the original data's order.
+ var arcs = [];
+ index.forEach(function(i) {
+ arcs[i] = {
data: data[i],
value: d = values[i],
startAngle: a,
endAngle: a += d * k
};
});
-
- // Return the arcs in the original data's order.
- return data.map(function(d, i) {
- return arcs[index[i]];
- });
+ return arcs;
}
/**
@@ -737,6 +690,8 @@ d3.layout.pie = function() {
return pie;
};
+
+var d3_layout_pieSortByValue = {};
// data is two-dimensional array of x,y; we populate y0
d3.layout.stack = function() {
var values = Object,
@@ -1088,9 +1043,9 @@ d3.layout.hierarchy = function() {
node = d3_layout_hierarchyInline ? data : {data: data};
node.depth = depth;
nodes.push(node);
- if (childs) {
+ if (childs && (n = childs.length)) {
var i = -1,
- n = childs.length,
+ n,
c = node.children = [],
v = 0,
j = depth + 1;
@@ -1103,7 +1058,7 @@ d3.layout.hierarchy = function() {
if (sort) c.sort(sort);
if (value) node.value = v;
} else if (value) {
- node.value = value.call(hierarchy, data, depth);
+ node.value = +value.call(hierarchy, data, depth) || 0;
}
return node;
}
@@ -1112,13 +1067,13 @@ d3.layout.hierarchy = function() {
function revalue(node, depth) {
var children = node.children,
v = 0;
- if (children) {
+ if (children && (n = children.length)) {
var i = -1,
- n = children.length,
+ n,
j = depth + 1;
while (++i < n) v += revalue(children[i], j);
} else if (value) {
- v = value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth);
+ v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0;
}
if (value) node.value = v;
return v;
@@ -1159,10 +1114,10 @@ d3.layout.hierarchy = function() {
// A method assignment helper for hierarchy subclasses.
function d3_layout_hierarchyRebind(object, hierarchy) {
- object.sort = d3.rebind(object, hierarchy.sort);
- object.children = d3.rebind(object, hierarchy.children);
+ d3.rebind(object, hierarchy, "sort", "children", "value");
+
+ // Add an alias for links, for convenience.
object.links = d3_layout_hierarchyLinks;
- object.value = d3.rebind(object, hierarchy.value);
// If the new API is used, enabling inlining.
object.nodes = function(d) {
@@ -1362,7 +1317,7 @@ function d3_layout_packUnlink(node) {
function d3_layout_packTree(node) {
var children = node.children;
- if (children) {
+ if (children && children.length) {
children.forEach(d3_layout_packTree);
node.r = d3_layout_packCircle(children);
} else {
@@ -1382,19 +1337,22 @@ function d3_layout_packTransform(node, x, y, k) {
}
function d3_layout_packPlace(a, b, c) {
- var da = b.r + c.r,
- db = a.r + c.r,
+ var db = a.r + c.r,
dx = b.x - a.x,
- dy = b.y - a.y,
- dc = Math.sqrt(dx * dx + dy * dy),
- cos = (db * db + dc * dc - da * da) / (2 * db * dc),
- theta = Math.acos(cos),
- x = cos * db,
- h = Math.sin(theta) * db;
- dx /= dc;
- dy /= dc;
- c.x = a.x + x * dx + h * dy;
- c.y = a.y + x * dy - h * dx;
+ dy = b.y - a.y;
+ if (db && (dx || dy)) {
+ var da = b.r + c.r,
+ dc = Math.sqrt(dx * dx + dy * dy),
+ cos = Math.max(-1, Math.min(1, (db * db + dc * dc - da * da) / (2 * db * dc))),
+ theta = Math.acos(cos),
+ x = cos * (db /= dc),
+ y = Math.sin(theta) * db;
+ c.x = a.x + x * dx + y * dy;
+ c.y = a.y + x * dy - y * dx;
+ } else {
+ c.x = a.x + db;
+ c.y = a.y;
+ }
}
// Implements a hierarchical layout using the cluster (or dendogram) algorithm.
d3.layout.cluster = function() {
@@ -1412,9 +1370,10 @@ d3.layout.cluster = function() {
// First walk, computing the initial x & y values.
d3_layout_treeVisitAfter(root, function(node) {
- if (node.children) {
- node.x = d3_layout_clusterX(node.children);
- node.y = d3_layout_clusterY(node.children);
+ var children = node.children;
+ if (children && children.length) {
+ node.x = d3_layout_clusterX(children);
+ node.y = d3_layout_clusterY(children);
} else {
node.x = previousNode ? x += separation(node, previousNode) : 0;
node.y = 0;
@@ -1431,7 +1390,7 @@ d3.layout.cluster = function() {
// Second walk, normalizing x & y to the desired size.
d3_layout_treeVisitAfter(root, function(node) {
node.x = (node.x - x0) / (x1 - x0) * size[0];
- node.y = (1 - node.y / root.y) * size[1];
+ node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
});
return nodes;
@@ -1466,12 +1425,12 @@ function d3_layout_clusterX(children) {
function d3_layout_clusterLeft(node) {
var children = node.children;
- return children ? d3_layout_clusterLeft(children[0]) : node;
+ return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
}
function d3_layout_clusterRight(node) {
- var children = node.children;
- return children ? d3_layout_clusterRight(children[children.length - 1]) : node;
+ var children = node.children, n;
+ return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
}
// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
d3.layout.tree = function() {
@@ -1486,8 +1445,8 @@ d3.layout.tree = function() {
function firstWalk(node, previousSibling) {
var children = node.children,
layout = node._tree;
- if (children && children.length) {
- var n = children.length,
+ if (children && (n = children.length)) {
+ var n,
firstChild = children[0],
previousChild,
ancestor = firstChild,
@@ -1517,9 +1476,9 @@ d3.layout.tree = function() {
function secondWalk(node, x) {
node.x = node._tree.prelim + x;
var children = node.children;
- if (children) {
+ if (children && (n = children.length)) {
var i = -1,
- n = children.length;
+ n;
x += node._tree.mod;
while (++i < n) {
secondWalk(children[i], x);
@@ -1624,18 +1583,21 @@ function d3_layout_treeSeparation(a, b) {
// }
function d3_layout_treeLeft(node) {
- return node.children ? node.children[0] : node._tree.thread;
+ var children = node.children;
+ return children && children.length ? children[0] : node._tree.thread;
}
function d3_layout_treeRight(node) {
- return node.children ? node.children[node.children.length - 1] : node._tree.thread;
+ var children = node.children,
+ n;
+ return children && (n = children.length) ? children[n - 1] : node._tree.thread;
}
function d3_layout_treeSearch(node, compare) {
var children = node.children;
- if (children) {
+ if (children && (n = children.length)) {
var child,
- n = children.length,
+ n,
i = -1;
while (++i < n) {
if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
@@ -1661,11 +1623,11 @@ function d3_layout_treeDeepest(a, b) {
function d3_layout_treeVisitAfter(node, callback) {
function visit(node, previousSibling) {
var children = node.children;
- if (children) {
+ if (children && (n = children.length)) {
var child,
previousChild = null,
i = -1,
- n = children.length;
+ n;
while (++i < n) {
child = children[i];
visit(child, previousChild);
@@ -1733,57 +1695,61 @@ d3.layout.treemap = function() {
// Recursively arranges the specified node's children into squarified rows.
function squarify(node) {
- if (!node.children) return;
- var rect = pad(node),
- row = [],
- children = node.children.slice(), // copy-on-write
- child,
- best = Infinity, // the best row score so far
- score, // the current row score
- u = Math.min(rect.dx, rect.dy), // initial orientation
- n;
- scale(children, rect.dx * rect.dy / node.value);
- row.area = 0;
- while ((n = children.length) > 0) {
- row.push(child = children[n - 1]);
- row.area += child.area;
- if ((score = worst(row, u)) <= best) { // continue with this orientation
- children.pop();
- best = score;
- } else { // abort, and try a different orientation
- row.area -= row.pop().area;
- position(row, u, rect, false);
- u = Math.min(rect.dx, rect.dy);
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node),
+ row = [],
+ remaining = children.slice(), // copy-on-write
+ child,
+ best = Infinity, // the best row score so far
+ score, // the current row score
+ u = Math.min(rect.dx, rect.dy), // initial orientation
+ n;
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while ((n = remaining.length) > 0) {
+ row.push(child = remaining[n - 1]);
+ row.area += child.area;
+ if ((score = worst(row, u)) <= best) { // continue with this orientation
+ remaining.pop();
+ best = score;
+ } else { // abort, and try a different orientation
+ row.area -= row.pop().area;
+ position(row, u, rect, false);
+ u = Math.min(rect.dx, rect.dy);
+ row.length = row.area = 0;
+ best = Infinity;
+ }
+ }
+ if (row.length) {
+ position(row, u, rect, true);
row.length = row.area = 0;
- best = Infinity;
}
+ children.forEach(squarify);
}
- if (row.length) {
- position(row, u, rect, true);
- row.length = row.area = 0;
- }
- node.children.forEach(squarify);
}
// Recursively resizes the specified node's children into existing rows.
// Preserves the existing layout!
function stickify(node) {
- if (!node.children) return;
- var rect = pad(node),
- children = node.children.slice(), // copy-on-write
- child,
- row = [];
- scale(children, rect.dx * rect.dy / node.value);
- row.area = 0;
- while (child = children.pop()) {
- row.push(child);
- row.area += child.area;
- if (child.z != null) {
- position(row, child.z ? rect.dx : rect.dy, rect, !children.length);
- row.length = row.area = 0;
+ var children = node.children;
+ if (children && children.length) {
+ var rect = pad(node),
+ remaining = children.slice(), // copy-on-write
+ child,
+ row = [];
+ scale(remaining, rect.dx * rect.dy / node.value);
+ row.area = 0;
+ while (child = remaining.pop()) {
+ row.push(child);
+ row.area += child.area;
+ if (child.z != null) {
+ position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
+ row.length = row.area = 0;
+ }
}
+ children.forEach(stickify);
}
- node.children.forEach(stickify);
}
// Computes the score for the specified row, as the worst aspect ratio.
@@ -1815,7 +1781,7 @@ d3.layout.treemap = function() {
v = u ? round(row.area / u) : 0,
o;
if (u == rect.dx) { // horizontal subdivision
- if (flush || v > rect.dy) v = rect.dy; // over+underflow
+ if (flush || v > rect.dy) v = v ? rect.dy : 0; // over+underflow
while (++i < n) {
o = row[i];
o.x = x;
@@ -1828,7 +1794,7 @@ d3.layout.treemap = function() {
rect.y += v;
rect.dy -= v;
} else { // vertical subdivision
- if (flush || v > rect.dx) v = rect.dx; // over+underflow
+ if (flush || v > rect.dx) v = v ? rect.dx : 0; // over+underflow
while (++i < n) {
o = row[i];
o.x = x;
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.time.js b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.time.js
index 3a3409f..4c1cda4 100755
--- a/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.time.js
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/js/d3.time.js
@@ -78,6 +78,7 @@ var d3_time_formats = {
H: function(d) { return d3_time_zfill2(d.getHours()); },
I: function(d) { return d3_time_zfill2(d.getHours() % 12 || 12); },
j: d3_time_dayOfYear,
+ L: function(d) { return d3_time_zfill3(d.getMilliseconds()); },
m: function(d) { return d3_time_zfill2(d.getMonth() + 1); },
M: function(d) { return d3_time_zfill2(d.getMinutes()); },
p: function(d) { return d.getHours() >= 12 ? "PM" : "AM"; },
@@ -104,6 +105,7 @@ var d3_time_parsers = {
H: d3_time_parseHour24,
I: d3_time_parseHour12,
// j: function(d, s, i) { /*TODO day of year [001,366] */ return i; },
+ L: d3_time_parseMilliseconds,
m: d3_time_parseMonthNumber,
M: d3_time_parseMinutes,
p: d3_time_parseAmPm,
@@ -277,6 +279,12 @@ function d3_time_parseSeconds(date, string, i) {
return n ? (date.setSeconds(+n[0]), i += n[0].length) : -1;
}
+function d3_time_parseMilliseconds(date, string, i) {
+ d3_time_numberRe.lastIndex = 0;
+ var n = d3_time_numberRe.exec(string.substring(i, i + 3));
+ return n ? (date.setMilliseconds(+n[0]), i += n[0].length) : -1;
+}
+
// Note: we don't look at the next directive.
var d3_time_numberRe = /\s*\d+/;
@@ -294,18 +302,22 @@ function d3_time_year(d) {
return new d3_time(d.getFullYear(), 0, 1);
}
+function d3_time_daysElapsed(d0, d1) {
+ return ~~((d1 - d0) / 864e5 - (d1.getTimezoneOffset() - d0.getTimezoneOffset()) / 1440);
+}
+
function d3_time_dayOfYear(d) {
- return d3_time_zfill3(1 + ~~((d - d3_time_year(d)) / 864e5));
+ return d3_time_zfill3(1 + d3_time_daysElapsed(d3_time_year(d), d));
}
function d3_time_weekNumberSunday(d) {
var d0 = d3_time_year(d);
- return d3_time_zfill2(~~(((d - d0) / 864e5 + d0.getDay()) / 7));
+ return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + d0.getDay()) / 7));
}
function d3_time_weekNumberMonday(d) {
var d0 = d3_time_year(d);
- return d3_time_zfill2(~~(((d - d0) / 864e5 + (d0.getDay() + 6) % 7) / 7));
+ return d3_time_zfill2(~~((d3_time_daysElapsed(d0, d) + (d0.getDay() + 6) % 7) / 7));
}
// TODO table of time zone offset names?
@@ -320,9 +332,14 @@ d3.time.format.utc = function(template) {
var local = d3.time.format(template);
function format(date) {
- var utc = new d3_time_format_utc();
- utc._ = date;
- return local(utc);
+ try {
+ d3_time = d3_time_format_utc;
+ var utc = new d3_time();
+ utc._ = date;
+ return local(utc);
+ } finally {
+ d3_time = Date;
+ }
}
format.parse = function(string) {
@@ -364,7 +381,19 @@ d3_time_format_utc.prototype = {
setMonth: function(x) { this._.setUTCMonth(x); },
setSeconds: function(x) { this._.setUTCSeconds(x); }
};
-d3.time.format.iso = d3.time.format.utc("%Y-%m-%dT%H:%M:%SZ");
+var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
+
+d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso;
+
+function d3_time_formatIsoNative(date) {
+ return date.toISOString();
+}
+
+d3_time_formatIsoNative.parse = function(string) {
+ return new Date(string);
+};
+
+d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
function d3_time_range(floor, step, number) {
return function(t0, t1, dt) {
var time = floor(t0), times = [];
@@ -502,8 +531,7 @@ d3.time.years.utc = d3_time_range(d3.time.year.utc, function(date) {
return date.getUTCFullYear();
});
// TODO nice
-function d3_time_scale(methods, format) {
- var linear = d3.scale.linear();
+function d3_time_scale(linear, methods, format) {
function scale(x) {
return linear(x);
@@ -537,13 +565,12 @@ function d3_time_scale(methods, format) {
return format;
};
- // TOOD expose d3_scale_linear_rebind?
- scale.range = d3.rebind(scale, linear.range);
- scale.rangeRound = d3.rebind(scale, linear.rangeRound);
- scale.interpolate = d3.rebind(scale, linear.interpolate);
- scale.clamp = d3.rebind(scale, linear.clamp);
+ scale.copy = function() {
+ return d3_time_scale(linear.copy(), methods, format);
+ };
- return scale;
+ // TOOD expose d3_scale_linear_rebind?
+ return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
}
// TODO expose d3_scaleExtent?
@@ -619,7 +646,7 @@ var d3_time_scaleLocalFormats = [
var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
d3.time.scale = function() {
- return d3_time_scale(d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
};
var d3_time_scaleUTCMethods = [
[d3.time.seconds.utc, 1],
@@ -655,6 +682,6 @@ var d3_time_scaleUTCFormats = [
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
d3.time.scale.utc = function() {
- return d3_time_scale(d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
+ return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
};
})();
commit 3f2e1dd08dfcfb38ef22aba22d6609c1a44b20da
Author: Stefan Negrea <snegrea(a)redhat.com>
Date: Fri Jan 6 16:18:07 2012 -0600
[BZ 765795] Removed the recursive call that was creating StackOverflowError and added the correct call to create a resource.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceFactoryManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceFactoryManagerBean.java
index 2395503..37131c2 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceFactoryManagerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/resource/ResourceFactoryManagerBean.java
@@ -521,9 +521,9 @@ public class ResourceFactoryManagerBean implements ResourceFactoryManagerLocal,
@XmlJavaTypeAdapter(value = ConfigurationAdapter.class)//
Configuration deploymentTimeConfiguration, byte[] packageBits, Integer timeout) {
- return createPackageBackedResource(subject, parentResourceId, newResourceTypeId, newResourceName,//
+ return createResource(subject, parentResourceId, newResourceTypeId, newResourceName,//
pluginConfiguration, packageName, packageVersionNumber, architectureId,//
- deploymentTimeConfiguration, packageBits, (Integer) null);
+ deploymentTimeConfiguration, new ByteArrayInputStream(packageBits), (Map<String, String>) null, timeout);
}
@Override
commit 38ca523ad95e2fdc3adec301fef5f88951c6dd2a
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Fri Jan 6 09:15:14 2012 -0500
[Bug 771201 - EPP 5.2 discovery fails with java.lang.StringIndexOutOfBoundsException]
EPP 5.2 has changed the format of its Implementation-Version string in the
manifest (5.1.1 was different). Add support for the new format. Also,
in general, fail more gracefully when encountering an unexpected version
string.
diff --git a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/helper/JBossInstallationInfo.java b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/helper/JBossInstallationInfo.java
index fe13a7a..cae73f3 100644
--- a/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/helper/JBossInstallationInfo.java
+++ b/modules/plugins/jboss-as-5/src/main/java/org/rhq/plugins/jbossas5/helper/JBossInstallationInfo.java
@@ -40,6 +40,7 @@ public class JBossInstallationInfo {
private static final String LOCALHOST_ADDRESS = "127.0.0.1";
private static final String SOA_IMPL_VERSION_PREFIX = "SOA-";
private static final String EAP_IMPL_VERSION_PREFIX = "EAP-";
+ private static final String EPP_IMPL_VERSION_PREFIX = "JBoss-EPP";
private static final ComparableVersion VERSION_4_2 = new ComparableVersion("4.2");
private final JBossProductType productType;
@@ -53,11 +54,15 @@ public class JBossInstallationInfo {
File runJar = new File(binDir, "run.jar");
if (!runJar.exists()) {
throw new RuntimeException(runJar + " does not exist - " + installationDir
- + " does not appear to be a JBoss installation/home directory.");
+ + " does not appear to be a JBoss installation/home directory.");
}
Attributes jarManifestAttributes = loadManifestAttributesFromJar(runJar);
this.productType = JBossProductType.determineJBossProductType(jarManifestAttributes);
this.version = getVersion(jarManifestAttributes);
+ int majorVersionIndex = version.indexOf('.');
+ if (-1 == majorVersionIndex) {
+ throw new RuntimeException("Unexpected run.jar implementation version, can't parse: " + this.version);
+ }
this.defaultBindAddress = getDefaultServerName(this.version);
this.isEap = determineEap(jarManifestAttributes);
this.majorVersion = version.substring(0, version.indexOf('.'));
@@ -112,6 +117,10 @@ public class JBossInstallationInfo {
String implementationVersion = jarManifestAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
// e.g. AS 5.1: "Implementation-Version: 5.1.0.GA (build: SVNTag=JBoss_5_1_0_GA date=200905221634)"
// e.g. EAP 5.0: "Implementation-Version: 5.0.0.Beta (build: SVNTag=JBPAPP_5_0_0_Beta date=200906191731)"
+ if (implementationVersion.startsWith(EPP_IMPL_VERSION_PREFIX)) {
+ implementationVersion = implementationVersion.substring(EPP_IMPL_VERSION_PREFIX.length()).trim();
+ }
+
int spaceIndex = validateImplementationVersion(implementationVersion);
String version = implementationVersion.substring(0, spaceIndex);
if (version.startsWith(SOA_IMPL_VERSION_PREFIX)) {
@@ -120,6 +129,7 @@ public class JBossInstallationInfo {
if (version.startsWith(EAP_IMPL_VERSION_PREFIX)) {
version = version.substring(EAP_IMPL_VERSION_PREFIX.length());
}
+
return version;
}
diff --git a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/helper/JBossInstallationInfo.java b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/helper/JBossInstallationInfo.java
index 20e7e81..13e1304 100644
--- a/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/helper/JBossInstallationInfo.java
+++ b/modules/plugins/jboss-as/src/main/java/org/rhq/plugins/jbossas/helper/JBossInstallationInfo.java
@@ -38,6 +38,7 @@ import org.apache.maven.artifact.versioning.ComparableVersion;
public class JBossInstallationInfo {
private static final String ANY_ADDRESS = "0.0.0.0";
private static final String LOCALHOST_ADDRESS = "127.0.0.1";
+ private static final String EPP_IMPL_VERSION_PREFIX = "JBoss-EPP";
private static final String SOA_IMPL_VERSION_PREFIX = "SOA-";
private static final ComparableVersion VERSION_4_2 = new ComparableVersion("4.2");
@@ -56,8 +57,12 @@ public class JBossInstallationInfo {
Attributes jarManifestAttributes = loadManifestAttributesFromJar(runJar);
this.productType = JBossProductType.determineJBossProductType(jarManifestAttributes);
this.version = getVersion(jarManifestAttributes);
+ int majorVersionIndex = version.indexOf('.');
+ if (-1 == majorVersionIndex) {
+ throw new RuntimeException("Unexpected run.jar implementation version, can't parse: " + this.version);
+ }
this.defaultBindAddress = getDefaultServerName(this.version);
- this.majorVersion = version.substring(0, version.indexOf('.'));
+ this.majorVersion = version.substring(0, majorVersionIndex);
}
public JBossProductType getProductType() {
@@ -103,15 +108,21 @@ public class JBossInstallationInfo {
throw new IllegalStateException("'" + Attributes.Name.IMPLEMENTATION_VERSION
+ "' MANIFEST.MF attribute not found.");
}
+ if (implementationVersion.startsWith(EPP_IMPL_VERSION_PREFIX)) {
+ implementationVersion = implementationVersion.substring(EPP_IMPL_VERSION_PREFIX.length()).trim();
+ }
+
int spaceIndex = implementationVersion.indexOf(' ');
if (spaceIndex == -1) {
throw new IllegalStateException("'" + Attributes.Name.IMPLEMENTATION_VERSION
+ "' MANIFEST.MF attribute has an invalid value: " + implementationVersion);
}
+
String version = implementationVersion.substring(0, spaceIndex);
if (version.startsWith(SOA_IMPL_VERSION_PREFIX)) {
version = version.substring(SOA_IMPL_VERSION_PREFIX.length());
}
+
return version;
}
commit 27f562a09d9334d5b0df1d81ae500ed304717481
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Jan 5 16:42:29 2012 -0500
Fix Calculate AutoBaselines Admin option (although it should be used with
great care as nothing stops it from running concurrently with the data
purge job)
diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/admin/test/control.jsp b/modules/enterprise/gui/portal-war/src/main/webapp/admin/test/control.jsp
index dd81dfb..0261703 100644
--- a/modules/enterprise/gui/portal-war/src/main/webapp/admin/test/control.jsp
+++ b/modules/enterprise/gui/portal-war/src/main/webapp/admin/test/control.jsp
@@ -155,11 +155,6 @@
}
else if ("calculateAutoBaselines".equals(mode))
{
- // for now, baselines aren't calculated until we hit our day limit, we force it here
- java.util.Properties props = systemManager.getSystemConfiguration(subjectManager.getOverlord());
- props.put("CAM_BASELINE_LASTTIME", "0");
- systemManager.setSystemConfiguration(subjectManager.getOverlord(), props,true);
-
measurementBaselineManager.calculateAutoBaselines();
}
else if ("calculateOOBs".equals(mode))
commit 723653fea5586b683fc8df76cdbeb81ecc65ca5d
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Thu Jan 5 16:40:55 2012 -0500
trivial, fix reference link in comments
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
index 3add80f..606eefe 100644
--- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
+++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
@@ -511,11 +511,8 @@ public class StartupServlet extends HttpServlet {
// Data Purge Job
try {
- // Let's leave this non-volatile - in case we fail to schedule any jobs above, then at least
- // our old schedule from a previous run will still be there - we want to be able to make sure we run
- // db maintenance when the server starts.
// TODO [mazz]: make the data purge job's cron string configurable via SystemManagerBean
- // For Quartz cron syntax, see: http://www.opensymphony.com/quartz/wikidocs/CronTriggers%20Tutorial.html
+ // For Quartz cron syntax, see: http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/cron...
String cronString = "0 0 * * * ?"; // every hour, on the hour
scheduler.scheduleSimpleCronJob(DataPurgeJob.class, true, false, cronString);
} catch (Exception e) {
commit afb9bfa4c6252f71fcf99343d92c892724592d79
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 5 15:24:34 2012 -0500
fix the user prefs test page so the buttons are re-enabled after clicking them
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/test/TestUserPreferencesView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/test/TestUserPreferencesView.java
index 3c1e768..42dfbbe 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/test/TestUserPreferencesView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/test/TestUserPreferencesView.java
@@ -97,6 +97,8 @@ public class TestUserPreferencesView extends Table {
new MessageWindow(extendLocatorId("csv"), "Export To CSV", "<pre>" + csv.toString() + "</pre>")
.show();
+
+ refreshTableInfo();
}
});
}
@@ -110,6 +112,7 @@ public class TestUserPreferencesView extends Table {
public void refresh() {
super.refresh();
getListGrid().setRecords(transform(this.prefs.getConfiguration()));
+ refreshTableInfo();
}
private ListGridRecord[] transform(Configuration configuration) {
commit 08a2a27a85319bf47e512780f678e532229381c8
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Jan 5 12:37:07 2012 -0500
fix the log message - we want to see the resource Ids so we need to convert the array to a string
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 e5df592..5b6b048 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
@@ -23,6 +23,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -1008,7 +1009,7 @@ public class MeasurementScheduleManagerBean implements MeasurementScheduleManage
}
}
} catch (Throwable t) {
- log.warn("problem creating schedules for resourceIds [" + resourceIds + "]", t);
+ log.warn("problem creating schedules for resourceIds [" + Arrays.toString(resourceIds) + "]", t);
}
return;
commit cf293cb3baf9e3d3447c16db0c181735d12c12e9
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Jan 5 13:58:08 2012 +0100
[BZ 746113] - increasing the maximum wait time for the tomcat start/stop
scripts from 1s to 120s.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerOperationsDelegate.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerOperationsDelegate.java
index f1e78f4..e9002f8 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerOperationsDelegate.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatServerOperationsDelegate.java
@@ -403,7 +403,7 @@ public class TomcatServerOperationsDelegate {
private void initProcessExecution(ProcessExecution processExecution) {
processExecution.setCaptureOutput(true);
- processExecution.setWaitForCompletion(1000L); // 1 second // TODO: Should we wait longer than one second?
+ processExecution.setWaitForCompletion(120000L); // 120 seconds - that should be safe? // TODO: make this configurable
processExecution.setKillOnTimeout(false);
}
commit aa4ec7d05bb38856a664ba6996255780db44f3d2
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Jan 4 21:56:48 2012 +0100
BZ 770967 - the port expression may now also have a ${} expression.
BZ 766284 - Detect managed AS7 in domain mode
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
index 78b1543..0e58078 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
@@ -158,7 +158,8 @@ public class AbstractBaseDiscovery {
if (portString!=null && !portString.isEmpty()) {
- hp.port = Integer.valueOf(portString);
+ String tmp = replaceDollarExpression(portString,commandLine);
+ hp.port = Integer.valueOf(tmp);
}
else
hp.port = 9990; // Fallback to default
@@ -197,15 +198,24 @@ public class AbstractBaseDiscovery {
* -D jboss.bind.address.management
* or
* -b management
- * to find the management port
+ * to find the management addresss
*/
String ret=null;
for (String line: commandLine) {
- if (line.contains("-bmanagement") || line.contains("jboss.bind.address.management")) {
- ret = line.substring(line.indexOf("=")+1);
- break;
+ if (expression.contains("address")) {
+ if (line.contains("-bmanagement") || line.contains("jboss.bind.address.management")) {
+ ret = line.substring(line.indexOf("=")+1);
+ break;
+ }
}
+ else if (expression.contains("port")) {
+ if (line.contains(expression)) {
+ ret = line.substring(line.indexOf("=")+1);
+ break;
+ }
+ }
+
}
if (ret==null)
ret = fallback;
@@ -269,12 +279,17 @@ public class AbstractBaseDiscovery {
if (hostXml==null)
throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
- // TODO make realm variable
String fileName = obtainXmlPropertyViaXPath("//security-realms/security-realm[@name='" + realm + "']/authentication/properties/@path");
String relDir = obtainXmlPropertyViaXPath("//security-realms/security-realm[@name='" + realm + "']/authentication/properties/@relative-to");
+ String dmode;
+ if (mode==AS7Mode.STANDALONE)
+ dmode="server";
+ else
+ dmode="domain";
+
String fullName ;
- if (relDir.equals("jboss.server.config.dir"))
+ if (relDir.equals("jboss." + dmode + ".config.dir"))
fullName = baseDir + File.separator + mode.getBaseDir() + File.separator + "configuration" + File.separator + fileName;
else
fullName = relDir + File.separator + fileName;
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
index 3e90588..53afe21 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
@@ -35,6 +35,7 @@ import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.event.log.LogFileEventResourceComponentHelper;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
import org.rhq.core.pluginapi.inventory.ProcessScanResult;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
import org.rhq.core.system.ProcessInfo;
import org.rhq.modules.plugins.jbossas7.json.Address;
@@ -49,7 +50,7 @@ import org.rhq.modules.plugins.jbossas7.json.ReadResource;
* @author Heiko W. Rupp
*/
@SuppressWarnings("unused")
-public class ManagedASDiscovery extends AbstractBaseDiscovery
+public class ManagedASDiscovery extends AbstractBaseDiscovery implements ResourceDiscoveryComponent
{
@@ -144,7 +145,7 @@ public class ManagedASDiscovery extends AbstractBaseDiscovery
Address theAddress = new Address("server-group", serverGroup);
Operation op = new ReadResource(theAddress);
ComplexResult res = (ComplexResult) dcConnection.execute(op, true);
- if (res.isSuccess()) {
+ if (res!=null && res.isSuccess()) {
if (res.getResult().containsKey("socket-binding-group")) {
String sbg = (String) res.getResult().get("socket-binding-group");
commit 51d8b4632a497bdbdfe2ae154aafbf2631411452
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Jan 4 15:32:40 2012 +0100
Allow to submit a 'now' value - otherwise the 7days case will always be served from the 1h table as the Handler's now is some ms earlier than the utilities now.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/util/MeasurementDataManagerUtility.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/util/MeasurementDataManagerUtility.java
index 0dfe0bb..f43820f 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/util/MeasurementDataManagerUtility.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/util/MeasurementDataManagerUtility.java
@@ -447,12 +447,12 @@ public class MeasurementDataManagerUtility {
return tables;
}
- /**
+ /**
* The raw tables starting at the specified index. Can be useful for getting the tables in a necessary time order (like
* oldest data first.
- *
- * @param startIndex >= 0. If >= TABLE_COUNT normalized via modulo.
- * @return Array of raw table names starting with the table with the specified index.
+ *
+ * @param startIndex >= 0. If >= TABLE_COUNT normalized via modulo.
+ * @return Array of raw table names starting with the table with the specified index.
*/
public static String[] getAllRawTables(int startIndex) {
String[] tables = new String[TABLE_COUNT];
@@ -465,9 +465,13 @@ public class MeasurementDataManagerUtility {
}
public static String[] getTables(long beginTime, long endTime) {
+ return getTables(beginTime, endTime, System.currentTimeMillis());
+ }
+
+ public static String[] getTables(long beginTime, long endTime, long now) {
List<String> tables = new ArrayList<String>();
- long now = System.currentTimeMillis();
+
if ((now - RAW_PURGE) < beginTime) {
int startIndex = getTableIndex(beginTime);
int endIndex = getTableIndex(endTime);
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index a772ab4..71a6a45 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -407,14 +407,15 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
+ long now = System.currentTimeMillis();
if (endTime==0)
- endTime = System.currentTimeMillis();
+ endTime = now;
if (startTime==0)
startTime = endTime - EIGHT_HOURS;
if (duration>0) // overrides start time
startTime = endTime - duration*1000L; // duration is in seconds
- if (startTime < System.currentTimeMillis()-7L*86400*1000)
+ if (startTime < now -7L*86400*1000)
throw new IllegalArgumentException("Start time is older than 7 days");
// Check if the schedule exists
@@ -425,6 +426,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
so.startTime = startTime;
so.endTime = endTime;
so.mediaType = mediaType;
+ so.now = now-1; // pass this so that the for the 7days case is still handled from raw tables.
return so;
@@ -484,12 +486,13 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
int scheduleId;
long startTime;
long endTime;
+ long now;
MediaType mediaType;
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
- String[] tables = MeasurementDataManagerUtility.getTables(startTime,endTime);
+ String[] tables = MeasurementDataManagerUtility.getTables(startTime,endTime,now);
StringBuilder sb = new StringBuilder();
for (int i = 0 ; i < tables.length ; i ++) {
sb.append("SELECT time_stamp,value FROM ");
commit d757cd72c10213f8888699095f7e5a1932427970
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Wed Jan 4 17:27:03 2012 -0500
[BZ 759481] fix the NPE that occurred when quick clicking between the template screens
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/templates/ResourceTypeTreeNodeBuilder.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/templates/ResourceTypeTreeNodeBuilder.java
index afb7b31..72563c2 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/templates/ResourceTypeTreeNodeBuilder.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/templates/ResourceTypeTreeNodeBuilder.java
@@ -25,6 +25,7 @@ import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridRecord;
+import com.smartgwt.client.widgets.tree.Tree;
import com.smartgwt.client.widgets.tree.TreeGrid;
import com.smartgwt.client.widgets.tree.TreeNode;
@@ -118,8 +119,7 @@ public abstract class ResourceTypeTreeNodeBuilder {
boolean isPlatform = (parentType.getCategory() == ResourceCategory.PLATFORM && isEmpty(parentType
.getParentResourceTypes()));
if (!isPlatform || !gotPlatform) {
- treeNodes
- .add(getTreeNodeInstance(composite, String.valueOf(parentType.getId())));
+ treeNodes.add(getTreeNodeInstance(composite, String.valueOf(parentType.getId())));
}
if (isPlatform) {
gotPlatform = true;
@@ -132,7 +132,11 @@ public abstract class ResourceTypeTreeNodeBuilder {
platformsGrid.setData(platformsRecords.toArray(new ListGridRecord[platformsRecords.size()]));
platformServicesGrid.setData(platformServicesRecords
.toArray(new ListGridRecord[platformServicesRecords.size()]));
- serversGrid.getTree().linkNodes(treeNodes.toArray(new TreeNode[treeNodes.size()]));
+ Tree tree = serversGrid.getTree();
+ if (tree != null) {
+ TreeNode[] treeNodeArray = treeNodes.toArray(new TreeNode[treeNodes.size()]);
+ tree.linkNodes(treeNodeArray);
+ }
}
@Override
commit 04000903b57864003ee41a86e013ddcc39ec4789
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jan 4 14:22:00 2012 -0500
[Bug 751778 - Upgrade from rhq4.1.0 to rhq4.2.0 fails with error : relation "rhq_drift_def_template" does not exist]
Fix query syntax for Oracle compatibility
diff --git a/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/DriftTemplateMapDatabaseUpgradeTask.java b/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/DriftTemplateMapDatabaseUpgradeTask.java
index 95d9ef7..386bd2a 100644
--- a/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/DriftTemplateMapDatabaseUpgradeTask.java
+++ b/modules/core/dbutils/src/main/java/org/rhq/core/db/upgrade/DriftTemplateMapDatabaseUpgradeTask.java
@@ -74,7 +74,7 @@ public class DriftTemplateMapDatabaseUpgradeTask implements DatabaseUpgradeTask
+ " from RHQ_DRIFT_DEF_TEMPLATE dt" //
+ " join RHQ_RESOURCE_TYPE rt on dt.RESOURCE_TYPE_ID = rt.ID" //
+ " join RHQ_RESOURCE res on rt.ID = res.RESOURCE_TYPE_ID" //
- + " and dd.RESOURCE_ID = res.ID" //
+ + " where dd.RESOURCE_ID = res.ID" //
+ " )" //
+ " where dd.DRIFT_DEF_TEMPLATE_ID is null";
commit 0db0f28f90897d71b3c992d802e58dc091ff2b7e
Author: Jay Shaughnessy <jshaughn(a)redhat.com>
Date: Wed Jan 4 10:31:51 2012 -0500
add jboss-sasl jar (as-7 plugin dep) to eclipse build path
diff --git a/.classpath b/.classpath
index 24fb54d..9eaf31b 100644
--- a/.classpath
+++ b/.classpath
@@ -124,6 +124,7 @@
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/resteasy-jaxrs/2.2.1.GA/resteasy-jaxrs-2.2.1.GA.jar"/>
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/resteasy-jettison-provider/2.2.1.GA/resteasy-jettison-provider-2.2.1.GA.jar"/>
<classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/resteasy/jaxrs-api/2.2.1.GA/jaxrs-api-2.2.1.GA.jar"/>
+ <classpathentry exported="true" kind="var" path="M2_REPO/org/jboss/sasl/jboss-sasl/1.0.0.Beta9/jboss-sasl-1.0.0.Beta9.jar"/>
<classpathentry kind="src" path="modules/common/ant-bundle/src/main/java"/>
<classpathentry kind="src" path="modules/enterprise/server/itests/src/test/java"/>
<classpathentry kind="src" path="modules/enterprise/server/plugins/drift-mongodb/src/main/java"/>
commit 51fbaef6a41e324118e069b7b5b8915526c2dc34
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Jan 4 14:15:57 2012 +0100
Adding support for Ldap, Dir, Event and EventDir contexts in addition to
the normal JNDI contexts in our JNDI security wrappers. This should unbreak
the LDAP support in the RHQ server.
Fixed enterprise/server/itests tests.
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java
deleted file mode 100644
index df42afe..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.util.List;
-
-import javax.naming.Binding;
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameParser;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-
-/**
- * This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
- * applied security checks in each method (lookups, (un)bindings, etc).
- * <p>
- * The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
- * <p>
- * This decorator applies the security check on any JNDI name without a scheme and
- * on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
- * in the constructor.
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingContextDecorator implements Context {
-
- private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
- private Context original;
- private List<String> checkedSchemes;
-
- public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
- this.original = original;
- this.checkedSchemes = Arrays.asList(checkedSchemes);
- }
-
- private static void check() {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) sm.checkPermission(PERM);
- }
-
- private void checkScheme(String scheme) {
- if (scheme == null || checkedSchemes.contains(scheme)) {
- check();
- }
- }
-
- private void check(String name) {
- checkScheme(getURLScheme(name));
- }
-
- private void check(Name name) {
- if (name.size() == 0) {
- check();
- } else {
- String first = name.get(0);
- checkScheme(getURLScheme(first));
- }
- }
-
- public Object lookup(Name name) throws NamingException {
- check(name);
- return original.lookup(name);
- }
-
- public Object lookup(String name) throws NamingException {
- check(name);
- return original.lookup(name);
- }
-
- public void bind(Name name, Object obj) throws NamingException {
- check(name);
- original.bind(name, obj);
- }
-
- public void bind(String name, Object obj) throws NamingException {
- check(name);
- original.bind(name, obj);
- }
-
- public void rebind(Name name, Object obj) throws NamingException {
- check(name);
- original.rebind(name, obj);
- }
-
- public void rebind(String name, Object obj) throws NamingException {
- check(name);
- original.rebind(name, obj);
- }
-
- public void unbind(Name name) throws NamingException {
- check(name);
- original.unbind(name);
- }
-
- public void unbind(String name) throws NamingException {
- check(name);
- original.unbind(name);
- }
-
- public void rename(Name oldName, Name newName) throws NamingException {
- check(oldName);
- check(newName);
- original.rename(oldName, newName);
- }
-
- public void rename(String oldName, String newName) throws NamingException {
- check(oldName);
- check(newName);
- original.rename(oldName, newName);
- }
-
- public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
- check(name);
- return original.list(name);
- }
-
- public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
- check(name);
- return original.list(name);
- }
-
- public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
- check(name);
- return original.listBindings(name);
- }
-
- public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
- check(name);
- return original.listBindings(name);
- }
-
- public void destroySubcontext(Name name) throws NamingException {
- check(name);
- original.destroySubcontext(name);
- }
-
- public void destroySubcontext(String name) throws NamingException {
- check(name);
- original.destroySubcontext(name);
- }
-
- public Context createSubcontext(Name name) throws NamingException {
- check(name);
- return original.createSubcontext(name);
- }
-
- public Context createSubcontext(String name) throws NamingException {
- check(name);
- return original.createSubcontext(name);
- }
-
- public Object lookupLink(Name name) throws NamingException {
- check(name);
- return original.lookupLink(name);
- }
-
- public Object lookupLink(String name) throws NamingException {
- check(name);
- return original.lookupLink(name);
- }
-
- public NameParser getNameParser(Name name) throws NamingException {
- check(name);
- return original.getNameParser(name);
- }
-
- public NameParser getNameParser(String name) throws NamingException {
- check(name);
- return original.getNameParser(name);
- }
-
- public Name composeName(Name name, Name prefix) throws NamingException {
- check(name);
- return original.composeName(name, prefix);
- }
-
- public String composeName(String name, String prefix) throws NamingException {
- check(name);
- return original.composeName(name, prefix);
- }
-
- public Object addToEnvironment(String propName, Object propVal) throws NamingException {
- check();
- return original.addToEnvironment(propName, propVal);
- }
-
- public Object removeFromEnvironment(String propName) throws NamingException {
- check();
- return original.removeFromEnvironment(propName);
- }
-
- public Hashtable<?, ?> getEnvironment() throws NamingException {
- check();
- return original.getEnvironment();
- }
-
- public void close() throws NamingException {
- check();
- original.close();
- }
-
- public String getNameInNamespace() throws NamingException {
- check();
- return original.getNameInNamespace();
- }
-
- //copied from InitialContext
- private static String getURLScheme(String str) {
- int colon_posn = str.indexOf(':');
- int slash_posn = str.indexOf('/');
-
- if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
- return str.substring(0, colon_posn);
- return null;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
index e529347..60e9bf6 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -27,6 +27,7 @@ import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -43,6 +44,18 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jnp.interfaces.NamingContextFactory;
+import org.rhq.jndi.context.AccessCheckingContextDecorator;
+import org.rhq.jndi.context.AccessCheckingDirContextDecorator;
+import org.rhq.jndi.context.AccessCheckingEventContextDecorator;
+import org.rhq.jndi.context.AccessCheckingEventDirContextDecorator;
+import org.rhq.jndi.context.AccessCheckingLdapContextDecorator;
+import org.rhq.jndi.context.ContextDecoratorPicker;
+import org.rhq.jndi.context.URLPreferringContextDecorator;
+import org.rhq.jndi.context.URLPreferringDirContextDecorator;
+import org.rhq.jndi.context.URLPreferringEventContextDecorator;
+import org.rhq.jndi.context.URLPreferringEventDirContextDecorator;
+import org.rhq.jndi.context.URLPreferringLdapContextDecorator;
+
/**
* This initial context factory builder is installed early on during the RHQ server startup
* and is later on used for obtaining the {@link Context}s for all JNDI lookups in the
@@ -67,7 +80,7 @@ import org.jnp.interfaces.NamingContextFactory;
*/
public class AccessCheckingInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
-
+
/**
* The list of JNDI name schemes that should be checked for security permissions
* (in addition to the names with no scheme).
@@ -79,14 +92,14 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
private static final Set<InetAddress> SERVER_BIND_IPS;
static {
SERVER_BIND_IPS = new HashSet<InetAddress>();
-
+
try {
String bindingAddressString = System.getProperty("jboss.bind.address");
InetAddress bindingAddress = InetAddress.getByName(bindingAddressString);
-
+
if (bindingAddress.isAnyLocalAddress()) {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
- while(ifaces.hasMoreElements()) {
+ while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
SERVER_BIND_IPS.addAll(Collections.list(iface.getInetAddresses()));
}
@@ -97,11 +110,12 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
LOG.error("Could not obtain the list of local IPs", e);
} catch (UnknownHostException e) {
LOG.error("Failed to get the binding address of the RHQ server.", e);
- }
+ }
}
-
- private static final int JNP_PORT = Integer.parseInt(System.getProperty("rhq.server.startup.namingservice.port", "2099"));
-
+
+ private static final int JNP_PORT = Integer.parseInt(System.getProperty("rhq.server.startup.namingservice.port",
+ "2099"));
+
/**
* This is the default initial context factory that is returned when no other is
* configured using the environment variables.
@@ -147,31 +161,72 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
});
}
- private static InitialContextFactory createSecureWrapper(InitialContextFactory factory, Hashtable<?, ?> environment) {
+ private static InitialContextFactory
+ createSecureWrapper(InitialContextFactory factory, Hashtable<?, ?> environment) {
String providerUrl = (String) environment.get(Context.PROVIDER_URL);
-
+
if (providerUrl == null) {
- return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ return getAccessCheckingFactory(factory);
} else {
try {
URI uri = new URI(providerUrl);
InetAddress providerHost = InetAddress.getByName(uri.getHost());
-
+
//check if we are accessing the RHQ server through some remoting
//interface.
- if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
- return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
+ return getAccessCheckingFactory(factory);
} else {
- return new URLPreferringInitialContextFactoryDecorator(factory);
+ return getURLPreferringFactory(factory);
}
} catch (URISyntaxException e) {
- return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ return getAccessCheckingFactory(factory);
} catch (UnknownHostException e) {
//let the factory deal with the unknown host...
//this most probably shouldn't be secured because localhost addresses
//should be resolvable.
- return new URLPreferringInitialContextFactoryDecorator(factory);
+ return getURLPreferringFactory(factory);
}
}
}
+
+ private static InitialContextFactory getAccessCheckingFactory(InitialContextFactory original) {
+ return new DecoratingInitialContextFactory(original, Arrays.asList(
+ getURLPreferringDecoratorPicker(), getAccessCheckingDecoratorPicker()));
+ }
+
+ private static InitialContextFactory getURLPreferringFactory(InitialContextFactory original) {
+ return new DecoratingInitialContextFactory(original, Arrays.asList(
+ getURLPreferringDecoratorPicker()));
+ }
+
+ private static ContextDecoratorPicker getAccessCheckingDecoratorPicker() {
+ ContextDecoratorPicker ret = new ContextDecoratorPicker();
+
+ ret.setConstructorParameters(new Object[] { CHECKED_SCHEMES });
+ ret.setConstructorParameterTypes(new Class<?>[] { String[].class });
+
+ ret.getPossibleDecorators().add(AccessCheckingContextDecorator.class);
+ ret.getPossibleDecorators().add(AccessCheckingDirContextDecorator.class);
+ ret.getPossibleDecorators().add(AccessCheckingEventContextDecorator.class);
+ ret.getPossibleDecorators().add(AccessCheckingEventDirContextDecorator.class);
+ ret.getPossibleDecorators().add(AccessCheckingLdapContextDecorator.class);
+
+ return ret;
+ }
+
+ private static ContextDecoratorPicker getURLPreferringDecoratorPicker() {
+ ContextDecoratorPicker ret = new ContextDecoratorPicker();
+
+ ret.setConstructorParameters(null);
+ ret.setConstructorParameterTypes(null);
+
+ ret.getPossibleDecorators().add(URLPreferringContextDecorator.class);
+ ret.getPossibleDecorators().add(URLPreferringDirContextDecorator.class);
+ ret.getPossibleDecorators().add(URLPreferringEventContextDecorator.class);
+ ret.getPossibleDecorators().add(URLPreferringEventDirContextDecorator.class);
+ ret.getPossibleDecorators().add(URLPreferringLdapContextDecorator.class);
+
+ return ret;
+ }
}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java
deleted file mode 100644
index b23935f..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
-
-/**
- * A decorator of an {@link InitialContextFactory} that adds the security checking
- * machinery to the returned initial contexts.
- *
- * @author Lukas Krejci
- */
-public class AccessCheckingInitialContextFactoryDecorator extends URLPreferringInitialContextFactoryDecorator {
-
- private final String[] checkedSchemes;
-
- /**
- * @param factory the factory to wrap
- * @param checkedSchemes the list of JNDI name schemes to check for permissions
- * @see AccessCheckingContextDecorator
- */
- public AccessCheckingInitialContextFactoryDecorator(InitialContextFactory factory, String... checkedSchemes) {
- super(factory);
- this.checkedSchemes = checkedSchemes;
- }
-
- /**
- * @param environment the environment variables for the return {@link Context} to use
- *
- * @return the initial context returned by the decorated factory wrapped in
- * {@link URLPreferringContext} and {@link AccessCheckingContextDecorator} in that
- * order.
- */
- @Override
- public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
- return new AccessCheckingContextDecorator(super.getInitialContext(environment), checkedSchemes);
- }
-
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
new file mode 100644
index 0000000..2414c98
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/DecoratingInitialContextFactory.java
@@ -0,0 +1,63 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.rhq.jndi.context.ContextDecoratorPicker;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class DecoratingInitialContextFactory implements InitialContextFactory {
+
+ private List<ContextDecoratorPicker> pickers;
+ private InitialContextFactory factory;
+
+ public DecoratingInitialContextFactory(InitialContextFactory factory, List<ContextDecoratorPicker> decoratorPickers) {
+ this.factory = factory;
+ this.pickers = decoratorPickers;
+ }
+
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ Context ctx = factory.getInitialContext(environment);
+
+ try {
+ for(ContextDecoratorPicker picker : pickers) {
+ ctx = picker.wrapInAppropriateDecorator(ctx);
+ }
+ } catch (IllegalArgumentException e) {
+ NamingException ex = new NamingException();
+ ex.initCause(ex);
+
+ throw e;
+ }
+
+ return ctx;
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
deleted file mode 100644
index c6456a2..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
-import javax.naming.spi.NamingManager;
-
-/**
- * This is a modification of the default {@link InitialContext} class that
- * ignores the initial context factory builder when constructing the default
- * context to use in lookups etc.
- * <p>
- * This is important because RHQ server has its own initial context factory
- * builder that creates factories that in turn create contexts. If the default
- * {@link InitialContext} implementation was used, we'd never be able to lookup
- * scheme-based names because the default implementation of the {@link InitialContext}
- * always uses the default context of the builder if one is installed no matter
- * the scheme in the name.
- * <p>
- * The {@link AccessCheckingInitialContextFactoryBuilder} wraps the context returned
- * by the factory in an instance of this class and thus is restoring the original
- * intended behavior of the {@link InitialContext}. It looks at the name being looked
- * up (bound or whatever) and prefers to use the URL context factories if the name
- * contains the scheme (as does the {@link InitialContext} if no builder is installed).
- * If the name doesn't contain a scheme, the provided default context factory is used to
- * look up the name.
- *
- * @author Lukas Krejci
- */
-public class URLPreferringContext extends InitialContext {
-
- public URLPreferringContext(InitialContextFactory defaultContextFactory) throws NamingException {
- super(true);
- this.defaultInitCtx = defaultContextFactory.getInitialContext(null);
- this.gotDefault = true;
- init(null);
- }
-
- public URLPreferringContext(Hashtable<?, ?> environment, InitialContextFactory defaultContextFactory) throws NamingException {
- super(true);
- this.defaultInitCtx = defaultContextFactory.getInitialContext(environment);
- this.gotDefault = true;
- init(environment);
- }
-
- @Override
- protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
- if (name.size() > 0) {
- String first = name.get(0);
- String scheme = getURLScheme(first);
- if (scheme != null) {
- Context ctx = NamingManager.getURLContext(scheme, myProps);
- if (ctx != null) {
- return ctx;
- }
- }
- }
- return getDefaultInitCtx();
- }
-
- @Override
- protected Context getURLOrDefaultInitCtx(String name) throws NamingException {
- String scheme = getURLScheme(name);
- if (scheme != null) {
- Context ctx = NamingManager.getURLContext(scheme, myProps);
- if (ctx != null) {
- return ctx;
- }
- }
- return getDefaultInitCtx();
- }
-
- //copied from InitialContext
- private static String getURLScheme(String str) {
- int colon_posn = str.indexOf(':');
- int slash_posn = str.indexOf('/');
-
- if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
- return str.substring(0, colon_posn);
- return null;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
deleted file mode 100644
index 609e98c..0000000
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.jndi;
-
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.spi.InitialContextFactory;
-
-/**
- * A decorator of an {@link InitialContextFactory} that returns an {@link URLPreferringContext}
- * backed by the wrapped initial context factory.
- * <p>
- * This is to support contexts that don't need to be secured, yet we need to make sure to
- * re-enable lookup of scheme-based names.
- *
- * @author Lukas Krejci
- */
-public class URLPreferringInitialContextFactoryDecorator implements InitialContextFactory {
-
- private final InitialContextFactory factory;
-
- public URLPreferringInitialContextFactoryDecorator(InitialContextFactory factory) {
- this.factory = factory;
- }
-
- public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
- return new URLPreferringContext(environment, getFactory());
- }
-
- protected InitialContextFactory getFactory() {
- return factory;
- }
-}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
new file mode 100644
index 0000000..6bfec7e
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingContextDecorator.java
@@ -0,0 +1,254 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ * This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
+ * applied security checks in each method (lookups, (un)bindings, etc).
+ * <p>
+ * The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
+ * <p>
+ * This decorator applies the security check on any JNDI name without a scheme and
+ * on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
+ * in the constructor.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingContextDecorator implements Context, ContextDecorator, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
+ private Context original;
+ private List<String> checkedSchemes;
+
+ public AccessCheckingContextDecorator(String... checkedSchemes) {
+ this.checkedSchemes = Arrays.asList(checkedSchemes);
+ }
+
+ public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
+ this.original = original;
+ this.checkedSchemes = Arrays.asList(checkedSchemes);
+ }
+
+ public void init(Context ctx) {
+ this.original = ctx;
+ }
+
+ protected Context getOriginal() {
+ return original;
+ }
+
+ protected static void check() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(PERM);
+ }
+
+ private void checkScheme(String scheme) {
+ if (scheme == null || checkedSchemes.contains(scheme)) {
+ check();
+ }
+ }
+
+ protected void check(String name) {
+ checkScheme(getURLScheme(name));
+ }
+
+ protected void check(Name name) {
+ if (name.size() == 0) {
+ check();
+ } else {
+ String first = name.get(0);
+ checkScheme(getURLScheme(first));
+ }
+ }
+
+ public Object lookup(Name name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public void bind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+ check();
+ return original.addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ check();
+ return original.removeFromEnvironment(propName);
+ }
+
+ public Hashtable<?, ?> getEnvironment() throws NamingException {
+ check();
+ return original.getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ check();
+ original.close();
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ check();
+ return original.getNameInNamespace();
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
new file mode 100644
index 0000000..1614180
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingDirContextDecorator.java
@@ -0,0 +1,187 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+/**
+ * A decorator of {@link DirContext}.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingDirContextDecorator extends AccessCheckingContextDecorator implements DirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingDirContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingDirContextDecorator(DirContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected DirContext getOriginal() {
+ return (DirContext) super.getOriginal();
+ }
+
+ public Attributes getAttributes(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name);
+ }
+
+ public Attributes getAttributes(String name) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name);
+ }
+
+ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name, attrIds);
+ }
+
+ public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
+ check(name);
+ return getOriginal().getAttributes(name, attrIds);
+ }
+
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mods);
+ }
+
+ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
+ check(name);
+ getOriginal().modifyAttributes(name, mods);
+ }
+
+ public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().bind(name, obj, attrs);
+ }
+
+ public void bind(String name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().bind(name, obj, attrs);
+ }
+
+ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().rebind(name, obj, attrs);
+ }
+
+ public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
+ check(name);
+ getOriginal().rebind(name, obj, attrs);
+ }
+
+ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
+ check(name);
+ return getOriginal().createSubcontext(name, attrs);
+ }
+
+ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
+ check(name);
+ return getOriginal().createSubcontext(name, attrs);
+ }
+
+ public DirContext getSchema(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public DirContext getSchema(String name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public DirContext getSchemaClassDefinition(Name name) throws NamingException {
+ check(name);
+ return getOriginal().getSchemaClassDefinition(name);
+ }
+
+ public DirContext getSchemaClassDefinition(String name) throws NamingException {
+ check(name);
+ return getOriginal().getSchema(name);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
+ check(name);
+ return getOriginal().search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
+ throws NamingException {
+ check(name);
+ return getOriginal().search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filterExpr, filterArgs, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
+ SearchControls cons) throws NamingException {
+ check(name);
+ return getOriginal().search(name, filterExpr, filterArgs, cons);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
new file mode 100644
index 0000000..67a9527
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventContextDecorator.java
@@ -0,0 +1,69 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingEventContextDecorator extends AccessCheckingContextDecorator implements EventContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingEventContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingEventContextDecorator(EventContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected EventContext getOriginal() {
+ return (EventContext) super.getOriginal();
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ check();
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ check();
+ return getOriginal().targetMustExist();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
new file mode 100644
index 0000000..ed7a848
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingEventDirContextDecorator.java
@@ -0,0 +1,96 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.SearchControls;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingEventDirContextDecorator extends AccessCheckingDirContextDecorator implements
+ EventDirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingEventDirContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingEventDirContextDecorator(EventDirContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected EventDirContext getOriginal() {
+ return (EventDirContext) super.getOriginal();
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ check();
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ check();
+ return getOriginal().targetMustExist();
+ }
+
+ public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void
+ addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
+ NamingListener l) throws NamingException {
+ check(target);
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
new file mode 100644
index 0000000..e361db8
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/AccessCheckingLdapContextDecorator.java
@@ -0,0 +1,85 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.NamingException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingLdapContextDecorator extends AccessCheckingDirContextDecorator implements LdapContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public AccessCheckingLdapContextDecorator(String... checkedSchemes) {
+ super(checkedSchemes);
+ }
+
+ public AccessCheckingLdapContextDecorator(LdapContext original, String... checkedSchemes) {
+ super(original, checkedSchemes);
+ }
+
+ @Override
+ protected LdapContext getOriginal() {
+ return (LdapContext) super.getOriginal();
+ }
+
+ public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
+ check();
+ return getOriginal().extendedOperation(request);
+ }
+
+ public LdapContext newInstance(Control[] requestControls) throws NamingException {
+ check();
+ return getOriginal().newInstance(requestControls);
+ }
+
+ public void reconnect(Control[] connCtls) throws NamingException {
+ check();
+ getOriginal().reconnect(connCtls);
+ }
+
+ public Control[] getConnectControls() throws NamingException {
+ check();
+ return getOriginal().getConnectControls();
+ }
+
+ public void setRequestControls(Control[] requestControls) throws NamingException {
+ check();
+ getOriginal().setRequestControls(requestControls);
+ }
+
+ public Control[] getRequestControls() throws NamingException {
+ check();
+ return getOriginal().getRequestControls();
+ }
+
+ public Control[] getResponseControls() throws NamingException {
+ check();
+ return getOriginal().getResponseControls();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
new file mode 100644
index 0000000..5755ebd
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecorator.java
@@ -0,0 +1,33 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public interface ContextDecorator extends Context {
+
+ void init(Context context) throws NamingException;
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java
new file mode 100644
index 0000000..a088aa2
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/ContextDecoratorPicker.java
@@ -0,0 +1,162 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+/**
+ * @author Lukas Krejci
+ */
+public class ContextDecoratorPicker {
+
+ private Set<Class<? extends ContextDecorator>> possibleDecorators = new HashSet<Class<? extends ContextDecorator>>();
+ private Class<?>[] constructorParameterTypes;
+ private Object[] constructorParameters;
+
+ public ContextDecoratorPicker() {
+ }
+
+ public ContextDecoratorPicker(Collection<? extends Class<? extends ContextDecorator>> c) {
+ possibleDecorators.addAll(c);
+ }
+
+ public Set<Class<? extends ContextDecorator>> getPossibleDecorators() {
+ return possibleDecorators;
+ }
+
+ public Class<?>[] getConstructorParameterTypes() {
+ return constructorParameterTypes;
+ }
+
+ public void setConstructorParameterTypes(Class<?>[] constructorParameterTypes) {
+ this.constructorParameterTypes = constructorParameterTypes;
+ }
+
+ public Object[] getConstructorParameters() {
+ return constructorParameters;
+ }
+
+ public void setConstructorParameters(Object[] constructorParameters) {
+ this.constructorParameters = constructorParameters;
+ }
+
+ public Context wrapInAppropriateDecorator(Context context) throws NamingException {
+ Class<? extends ContextDecorator> cls = getMatchByInterfaces(context, possibleDecorators);
+
+ if (cls == null) {
+ throw new IllegalArgumentException("Could not find a matching context decorator for " + context.getClass() + " in " + this);
+ }
+
+ Constructor<? extends ContextDecorator> ctor = null;
+ try {
+ ctor = cls.getConstructor(constructorParameterTypes);
+ ContextDecorator ctx = ctor.newInstance(constructorParameters);
+
+ ctx.init(context);
+
+ return ctx;
+ } catch (SecurityException e) {
+ throw new IllegalStateException("Could not instantiate a class through reflection.", e);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException(
+ "Could not construct a context decorator - unable to find a constructor with parameters "
+ + (constructorParameterTypes == null ? "[no parameters]" : Arrays.asList(constructorParameterTypes)) + " on class " + cls.getName(), e);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException("Could not instantiate a context decorator " + cls + " using constructor " + ctor, e);
+ }
+ }
+
+ private static <T> Class<? extends T> getMatchByInterfaces(Object obj, Set<Class<? extends T>> classes) {
+ Set<Class<?>> ifaces = getAllImplementedInterfaces(obj.getClass());
+
+ Class<? extends T> match = null;
+ int maxMatchCnt = Integer.MIN_VALUE;
+
+ for(Class<? extends T> cls : classes) {
+ int cnt = getBestMatchByIfaces(cls, ifaces);
+ if (cnt > maxMatchCnt) {
+ maxMatchCnt = cnt;
+ match = cls;
+ }
+ }
+
+ return match;
+ }
+
+ private static int getBestMatchByIfaces(Class<?> cls, Set<Class<?>> ifaces) {
+ int ret = 0;
+
+ //count how many interfaces from the supplied array the class implements
+ for(Class<?> iface : ifaces) {
+ if (iface.isAssignableFrom(cls)) {
+ ++ret;
+ } else {
+ --ret;
+ }
+ }
+
+ //that's not all - to get the best possible match, we need to take into account
+ //the fact that the class might implement more than just the interfaces provided
+ Set<Class<?>> clsIfaces = getAllImplementedInterfaces(cls);
+
+ for(Class<?> clsIface : clsIfaces) {
+ if (!(ifaces.contains(clsIface))) {
+ --ret;
+ }
+ }
+
+ return ret;
+ }
+
+ private static Set<Class<?>> getAllImplementedInterfaces(Class<?> cls) {
+ HashSet<Class<?>> ret = new HashSet<Class<?>>();
+ getAllImplementedInterfaces(cls, ret);
+
+ return ret;
+ }
+
+ private static void getAllImplementedInterfaces(Class<?> cls, Set<Class<?>> output) {
+ Class<?>[] ifaces = cls.getInterfaces();
+
+ for(Class<?> iface : Arrays.asList(ifaces)) {
+ output.add(iface);
+ getAllImplementedInterfaces(iface, output);
+ }
+
+ if (cls.getSuperclass() != null) {
+ getAllImplementedInterfaces(cls.getSuperclass(), output);
+ }
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
new file mode 100644
index 0000000..20077de
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecorator.java
@@ -0,0 +1,212 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.io.Serializable;
+import java.util.Hashtable;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ * This is a wrapper class around another {@link Context} implementation that
+ * prefers to use an URL context for some operation if the JNDI name contains
+ * a scheme rather than the original. This is the behavior of {@link InitialContext}
+ * which we need to restore in the contexts created by the {@link AccessCheckingInitialContextFactoryBuilder}
+ * (which an {@link InitialContext} uses exclusively if the builder is set).
+ * <p>
+ * This is important because RHQ server has its own initial context factory
+ * builder that creates factories that in turn create contexts. If the default
+ * {@link InitialContext} implementation was used, we'd never be able to lookup
+ * scheme-based names because the default implementation of the {@link InitialContext}
+ * always uses the default context of the builder if one is installed no matter
+ * the scheme in the name.
+ * <p>
+ * The {@link AccessCheckingInitialContextFactoryBuilder} wraps the context returned
+ * by the factory in an instance of this class and thus is restoring the original
+ * intended behavior of the {@link InitialContext}. It looks at the name being looked
+ * up (bound or whatever) and prefers to use the URL context factories if the name
+ * contains the scheme (as does the {@link InitialContext} if no builder is installed).
+ * If the name doesn't contain a scheme, the provided default context factory is used to
+ * look up the name.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecorator implements Context, ContextDecorator, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private Context original;
+
+ public URLPreferringContextDecorator() {
+
+ }
+
+ public URLPreferringContextDecorator(Context ctx) {
+ original = ctx;
+ }
+
+ public void init(Context context) {
+ original = context;
+ }
+
+ protected Context getOriginal() throws NamingException {
+ return original;
+ }
+
+ protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
+ @SuppressWarnings("unchecked")
+ Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
+ return urlContext == null ? getOriginal() : urlContext;
+ }
+
+ protected Context getURLOrDefaultInitCtx(String name) throws NamingException {
+ @SuppressWarnings("unchecked")
+ Context urlContext = URLPreferringContextDecoratorHelper.getURLContext(name, (Hashtable<Object, Object>) getEnvironment());
+ return urlContext == null ? getOriginal() : urlContext;
+ }
+
+ public Object lookup(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookup(name);
+ }
+
+ public void bind(Name name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ getURLOrDefaultInitCtx(name).unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ getURLOrDefaultInitCtx(name).unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
+ }
+
+ public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).list(name);
+ }
+
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).list(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).listBindings(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ getURLOrDefaultInitCtx(name).destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ getURLOrDefaultInitCtx(name).destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ return getOriginal().composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix) throws NamingException {
+ return getOriginal().composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+ return getOriginal().addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ return getOriginal().removeFromEnvironment(propName);
+ }
+
+ public Hashtable<?, ?> getEnvironment() throws NamingException {
+ return getOriginal().getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ if (getOriginal() != null) {
+ getOriginal().close();
+ original = null;
+ }
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ return getOriginal().getNameInNamespace();
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
new file mode 100644
index 0000000..6e7debc
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringContextDecoratorHelper.java
@@ -0,0 +1,76 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.spi.NamingManager;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContextDecoratorHelper {
+
+ private URLPreferringContextDecoratorHelper() {
+
+ }
+
+ public static Context getURLContext(String name, Hashtable<Object, Object> env) throws NamingException {
+ String scheme = getURLScheme(name);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, env);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+
+ return null;
+ }
+
+ public static Context getURLContext(Name name, Hashtable<Object, Object> env) throws NamingException {
+ if (name.size() > 0) {
+ String first = name.get(0);
+ String scheme = getURLScheme(first);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, env);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
new file mode 100644
index 0000000..6a49942
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringDirContextDecorator.java
@@ -0,0 +1,185 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+
+/**
+ * Akin to {@link URLPreferringContextDecorator} this class implements the similar logic
+ * for {@link DirContext}s.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringDirContextDecorator extends URLPreferringContextDecorator implements DirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringDirContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringDirContextDecorator(DirContext ctx) {
+ super(ctx);
+ }
+
+ protected DirContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof DirContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of DirContext");
+ }
+ }
+
+ return (DirContext) ctx;
+ }
+
+ @Override
+ protected DirContext getURLOrDefaultInitCtx(Name name) throws NamingException {
+ Context ctx = super.getURLOrDefaultInitCtx(name);
+ return checkAndCast(ctx);
+ }
+
+ @Override
+ protected DirContext getURLOrDefaultInitCtx(String name) throws NamingException {
+ Context ctx = super.getURLOrDefaultInitCtx(name);
+ return checkAndCast(ctx);
+ }
+
+ public Attributes getAttributes(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name);
+ }
+
+ public Attributes getAttributes(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name);
+ }
+
+ public Attributes getAttributes(Name name, String[] attrIds) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
+ }
+
+ public Attributes getAttributes(String name, String[] attrIds) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getAttributes(name, attrIds);
+ }
+
+ public void modifyAttributes(Name name, int mod_op, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(String name, int mod_op, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mod_op, attrs);
+ }
+
+ public void modifyAttributes(Name name, ModificationItem[] mods) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
+ }
+
+ public void modifyAttributes(String name, ModificationItem[] mods) throws NamingException {
+ getURLOrDefaultInitCtx(name).modifyAttributes(name, mods);
+ }
+
+ public void bind(Name name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
+ }
+
+ public void bind(String name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).bind(name, obj, attrs);
+ }
+
+ public void rebind(Name name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
+ }
+
+ public void rebind(String name, Object obj, Attributes attrs) throws NamingException {
+ getURLOrDefaultInitCtx(name).rebind(name, obj, attrs);
+ }
+
+ public DirContext createSubcontext(Name name, Attributes attrs) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
+ }
+
+ public DirContext createSubcontext(String name, Attributes attrs) throws NamingException {
+ return getURLOrDefaultInitCtx(name).createSubcontext(name, attrs);
+ }
+
+ public DirContext getSchema(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchema(name);
+ }
+
+ public DirContext getSchema(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchema(name);
+ }
+
+ public DirContext getSchemaClassDefinition(Name name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
+ }
+
+ public DirContext getSchemaClassDefinition(String name) throws NamingException {
+ return getURLOrDefaultInitCtx(name).getSchemaClassDefinition(name);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, Attributes matchingAttributes, String[] attributesToReturn) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes,
+ String[] attributesToReturn) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes, attributesToReturn);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, Attributes matchingAttributes) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, Attributes matchingAttributes) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, matchingAttributes);
+ }
+
+ public NamingEnumeration<SearchResult> search(Name name, String filter, SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filter, SearchControls cons)
+ throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filter, cons);
+ }
+
+ public NamingEnumeration<SearchResult>
+ search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
+ }
+
+ public NamingEnumeration<SearchResult> search(String name, String filterExpr, Object[] filterArgs,
+ SearchControls cons) throws NamingException {
+ return getURLOrDefaultInitCtx(name).search(name, filterExpr, filterArgs, cons);
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
new file mode 100644
index 0000000..e3298a0
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventContextDecorator.java
@@ -0,0 +1,81 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.event.EventContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringEventContextDecorator extends URLPreferringContextDecorator implements EventContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringEventContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringEventContextDecorator(EventContext ctx) {
+ super(ctx);
+ }
+
+ protected EventContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof EventContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of EventContext");
+ }
+ }
+
+ return (EventContext) ctx;
+ }
+
+ @Override
+ protected EventContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return getOriginal().targetMustExist();
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
new file mode 100644
index 0000000..4925297
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringEventDirContextDecorator.java
@@ -0,0 +1,104 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.directory.SearchControls;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamingListener;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringEventDirContextDecorator extends URLPreferringDirContextDecorator implements EventDirContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringEventDirContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringEventDirContextDecorator(EventDirContext ctx) {
+ super(ctx);
+ }
+
+ @Override
+ protected EventDirContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof EventDirContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException(
+ "Not an instance of EventDirContext");
+ }
+ }
+
+ return (EventDirContext) ctx;
+ }
+
+ @Override
+ protected EventDirContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public void addNamingListener(Name target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void addNamingListener(String target, int scope, NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, scope, l);
+ }
+
+ public void removeNamingListener(NamingListener l) throws NamingException {
+ getOriginal().removeNamingListener(l);
+ }
+
+ public boolean targetMustExist() throws NamingException {
+ return getOriginal().targetMustExist();
+ }
+
+ public void addNamingListener(Name target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, ctls, l);
+ }
+
+ public void
+ addNamingListener(Name target, String filter, Object[] filterArgs, SearchControls ctls, NamingListener l)
+ throws NamingException {
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+ public void addNamingListener(String target, String filter, Object[] filterArgs, SearchControls ctls,
+ NamingListener l) throws NamingException {
+ getOriginal().addNamingListener(target, filter, filterArgs, ctls, l);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
new file mode 100644
index 0000000..c74df39
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/context/URLPreferringLdapContextDecorator.java
@@ -0,0 +1,94 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.context;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.NotContextException;
+import javax.naming.ldap.Control;
+import javax.naming.ldap.ExtendedRequest;
+import javax.naming.ldap.ExtendedResponse;
+import javax.naming.ldap.LdapContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringLdapContextDecorator extends URLPreferringDirContextDecorator implements LdapContext {
+
+ private static final long serialVersionUID = 1L;
+
+ public URLPreferringLdapContextDecorator() {
+ super(null);
+ }
+
+ public URLPreferringLdapContextDecorator(LdapContext original) {
+ super(original);
+ }
+
+ @Override
+ protected LdapContext checkAndCast(Context ctx) throws NamingException {
+ if (!(ctx instanceof LdapContext)) {
+ if (ctx == null) {
+ throw new NoInitialContextException();
+ } else {
+ throw new NotContextException("Not an instance of LdapContext");
+ }
+ }
+
+ return (LdapContext) ctx;
+ }
+
+ @Override
+ protected LdapContext getOriginal() throws NamingException {
+ return checkAndCast(super.getOriginal());
+ }
+
+ public ExtendedResponse extendedOperation(ExtendedRequest request) throws NamingException {
+ return getOriginal().extendedOperation(request);
+ }
+
+ public LdapContext newInstance(Control[] requestControls) throws NamingException {
+ return new URLPreferringLdapContextDecorator(getOriginal().newInstance(requestControls));
+ }
+
+ public void reconnect(Control[] connCtls) throws NamingException {
+ getOriginal().reconnect(connCtls);
+ }
+
+ public Control[] getConnectControls() throws NamingException {
+ return getOriginal().getConnectControls();
+ }
+
+ public void setRequestControls(Control[] requestControls) throws NamingException {
+ getOriginal().setRequestControls(requestControls);
+ }
+
+ public Control[] getRequestControls() throws NamingException {
+ return getOriginal().getRequestControls();
+ }
+
+ public Control[] getResponseControls() throws NamingException {
+ return getOriginal().getResponseControls();
+ }
+
+}
diff --git a/modules/enterprise/server/itests/pom.xml b/modules/enterprise/server/itests/pom.xml
index 8753e6f..6898621 100644
--- a/modules/enterprise/server/itests/pom.xml
+++ b/modules/enterprise/server/itests/pom.xml
@@ -56,6 +56,12 @@
<dependency>
<groupId>org.rhq</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
<artifactId>rhq-enterprise-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
commit d1d18876b9f22a681e7243ef54aa649d066e8656
Author: Larry O'Leary <loleary(a)redhat.com>
Date: Tue Jan 3 16:37:31 2012 -0600
[Bug 769470] TomcatWarDiscoveryComponent excludes valid WAR deployments due to eager host name regular expression
Changed regular expression used to extract host name from context name to stop at first slash instead of last slash.
diff --git a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarDiscoveryComponent.java b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarDiscoveryComponent.java
index f6fa791..7605749 100644
--- a/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarDiscoveryComponent.java
+++ b/modules/plugins/tomcat/src/main/java/org/jboss/on/plugins/tomcat/TomcatWarDiscoveryComponent.java
@@ -1,5 +1,5 @@
/** Jopr Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
+ * Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@ public class TomcatWarDiscoveryComponent extends MBeanResourceDiscoveryComponent
private static final List<String> EMS_ATTRIBUTE_DOC_BASE = Arrays.asList(new String[] { "docBase" });
private static final List<String> EMS_ATTRIBUTE_PATH = Arrays.asList(new String[] { "path" });
/** The name MBean attribute for each application is of the form "Tomcat WAR (//vHost/contextRoot)". */
- private static final Pattern PATTERN_NAME = Pattern.compile("//(.*)(/.*)");
+ private static final Pattern PATTERN_NAME = Pattern.compile("^//([^/]+)(.*)$");
private static final String RT_LOG_FILE_NAME_SUFFIX = "_rt.log";
private final Log log = LogFactory.getLog(this.getClass());
commit caff389ecc3e3f6c53e9880f840c1995241a92a4
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 3 15:19:18 2012 +0100
Some cleanup, return location for PUT metric, allow to expose raw metrics as xml too.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index 77e36a4..a772ab4 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -123,30 +123,8 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
List<List<MeasurementDataNumericHighLowComposite>> listList = dataManager.findDataForResource(caller,
schedule.getResource().getId(), new int[]{definitionId}, startTime, endTime, dataPoints);
-/*
- long minTime=Long.MAX_VALUE;
- long maxTime=0;
-*/
-
if (!listList.isEmpty()) {
List<MeasurementDataNumericHighLowComposite> list = listList.get(0);
-/*
- for (MeasurementDataNumericHighLowComposite c : list) {
- long timestamp = c.getTimestamp();
- if (!Double.isNaN(c.getValue()) || !hideEmpty) {
- MetricAggregate.DataPoint dp = new MetricAggregate.DataPoint(timestamp,c.getValue(),c.getHighValue(),c.getLowValue());
- res.addDataPoint(dp);
- }
- if (timestamp <minTime)
- minTime= timestamp;
- if (timestamp >maxTime)
- maxTime= timestamp;
- }
- res.setNumDataPoints(list.size());
- }
- res.setMaxTimeStamp(maxTime);
- res.setMinTimeStamp(minTime);
-*/
fill(res, list,scheduleId,hideEmpty);
}
@@ -156,7 +134,6 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
cc.setPrivate(false);
cc.setNoCache(false);
-
Response.ResponseBuilder builder;
MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
if (mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
@@ -224,6 +201,8 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
@QueryParam("hideEmpty") boolean hideEmpty, @Context Request request,
@Context HttpHeaders headers) {
+ MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
+
if (startTime==0) {
endTime = System.currentTimeMillis();
startTime = endTime - EIGHT_HOURS;
@@ -259,7 +238,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
GenericEntity<List<MetricAggregate>> metAgg = new GenericEntity<List<MetricAggregate>>(resList) {};
- return Response.ok(metAgg).build();
+ return Response.ok(metAgg,mediaType).build();
}
@@ -275,8 +254,10 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
*/
public Response getSchedule(int scheduleId, Request request, HttpHeaders headers, UriInfo uriInfo) {
- MeasurementSchedule schedule=null;
- Response.ResponseBuilder builder=null;
+ MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
+
+ MeasurementSchedule schedule;
+ Response.ResponseBuilder builder;
// Create a cache control
CacheControl cc = new CacheControl();
@@ -351,9 +332,6 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
Link updateLink = new Link("edit",uri.toString());
metricSchedule.addLink(updateLink);
- // What media type does the user request?
- MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
-
if (mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
builder = Response.ok(renderTemplate("metricSchedule", metricSchedule), mediaType);
}
@@ -427,6 +405,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
Request request,
HttpHeaders headers) {
+ MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
if (endTime==0)
endTime = System.currentTimeMillis();
@@ -441,10 +420,11 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
// Check if the schedule exists
obtainSchedule(scheduleId);
- RawNumericJsonStreamingOutput so = new RawNumericJsonStreamingOutput();
+ RawNumericStreamingOutput so = new RawNumericStreamingOutput();
so.scheduleId = scheduleId;
so.startTime = startTime;
so.endTime = endTime;
+ so.mediaType = mediaType;
return so;
@@ -456,8 +436,9 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Path("data/{scheduleId}/raw/{timeStamp}")
public Response putMetricValue(@PathParam("scheduleId") int scheduleId, @PathParam("timeStamp") long timestamp,
- NumericDataPoint point, @Context HttpHeaders headers) {
+ NumericDataPoint point, @Context HttpHeaders headers, UriInfo uriInfo) {
+ MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
MeasurementSchedule schedule = obtainSchedule(scheduleId);
Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>(1);
@@ -465,7 +446,13 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
dataManager.addNumericData(data);
- return Response.ok().build(); // TODO correct code?
+ UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
+ uriBuilder.path("/metric/data/{scheduleId}/raw");
+ uriBuilder.queryParam("startTime",timestamp);
+ uriBuilder.queryParam("endTime",timestamp);
+ URI uri = uriBuilder.build(scheduleId);
+
+ return Response.created(uri).type(mediaType).build();
}
@@ -475,6 +462,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response postMetricValues(Collection<NumericDataPoint> points, @Context HttpHeaders headers) {
+ MediaType mediaType = headers.getAcceptableMediaTypes().get(0);
Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>(points.size());
for (NumericDataPoint point : points) {
data.add(new MeasurementDataNumeric(point.getTimeStamp(), point.getScheduleId(),point.getValue()));
@@ -482,7 +470,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
dataManager.addNumericData(data);
- return Response.ok().build();
+ return Response.noContent().type(mediaType).build();
}
@@ -491,11 +479,12 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
* without creating tons of objects in the middle to have them marshalled
* by JAX-RS
*/
- private class RawNumericJsonStreamingOutput implements StreamingOutput {
+ private class RawNumericStreamingOutput implements StreamingOutput {
int scheduleId;
long startTime;
long endTime;
+ MediaType mediaType;
@Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
@@ -528,22 +517,38 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
rs = ps.executeQuery();
PrintWriter pw = new PrintWriter(outputStream);
- pw.println("[");
- while (rs.next()) {
- pw.print("{");
- pw.print("\"scheduleId\":");
- pw.print(scheduleId);
- pw.print(", ");
- pw.print("\"timeStamp\":");
- pw.print(rs.getLong(1));
- pw.print(", ");
- pw.print("\"value\":");
- pw.print(rs.getLong(2));
- pw.print("}");
- if (!rs.isLast())
- pw.print(",\n");
+
+ if (mediaType.equals(MediaType.APPLICATION_JSON_TYPE)) {
+ pw.println("[");
+ while (rs.next()) {
+ pw.print("{");
+ pw.print("\"scheduleId\":");
+ pw.print(scheduleId);
+ pw.print(", ");
+ pw.print("\"timeStamp\":");
+ pw.print(rs.getLong(1));
+ pw.print(", ");
+ pw.print("\"value\":");
+ pw.print(rs.getDouble(2));
+ pw.print("}");
+ if (!rs.isLast())
+ pw.print(",\n");
+ }
+ pw.println("]");
+ }
+ else if (mediaType.equals(MediaType.APPLICATION_XML_TYPE)) {
+ pw.println("<collection>");
+ while(rs.next()) {
+ pw.print(" <numericDataPoint scheduleId=\"");
+ pw.print(scheduleId);
+ pw.print("\" timeStamp=\"");
+ pw.print(rs.getLong(1));
+ pw.print("\" value=\"");
+ pw.print(rs.getDouble(2));
+ pw.println("\"/>");
+ }
+ pw.println("</collection>");
}
- pw.println("]");
pw.flush();
pw.close();
} catch (SQLException e) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
index 2c75a55..6f76bce 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
@@ -119,7 +119,7 @@ public interface MetricHandlerLocal {
*/
@GET
@Path("data/{scheduleId}/raw")
- @Produces({MediaType.APPLICATION_JSON})
+ @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
StreamingOutput getMetricDataRaw(@PathParam("scheduleId") int scheduleId,
@QueryParam("startTime") long startTime,
@QueryParam("endTime") long endTime,
@@ -133,15 +133,17 @@ public interface MetricHandlerLocal {
* @param timestamp Timestamp of the entry
* @param point Datapoint of class NumericDataPoint
* @param headers Injected HTTP headers
+ * @param uriInfo Injected info about the uri
* @return
*/
@PUT
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@Path("data/{scheduleId}/raw/{timeStamp}")
- Response putMetricValue(@PathParam("scheduleId")int scheduleId,
- @PathParam("timeStamp")long timestamp, NumericDataPoint point,
- @Context HttpHeaders headers);
+ Response putMetricValue(@PathParam("scheduleId") int scheduleId,
+ @PathParam("timeStamp") long timestamp, NumericDataPoint point,
+ @Context HttpHeaders headers,
+ @Context UriInfo uriInfo);
/**
* Submit a series of (numerical) metric values to the server
commit 6945397a12e96fcaa7c92161e5f474abd98f7cad
Merge: 89027fe eb92c16
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 3 15:26:38 2012 +0100
Merge branch 'lkrejci/dissalow-alert-scripts-from-accessing-local-slsbs'
commit eb92c16f4ac8151e1984406af677f950f9984af4
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 3 15:07:13 2012 +0100
updating the javadocs to correctly explain the purpose of the URLPreferringContext
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
index b291c3e..c6456a2 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
@@ -35,17 +35,18 @@ import javax.naming.spi.NamingManager;
* <p>
* This is important because RHQ server has its own initial context factory
* builder that creates factories that in turn create contexts. If the default
- * {@link InitialContext} implementation was used, we'd end up with a stack overflow
- * error caused by the callchain loop when the {@link InitialContext} would ask
- * the builder for a factory that would create another context that would ask the
- * builder for the factory, etc. ad infinitum.
+ * {@link InitialContext} implementation was used, we'd never be able to lookup
+ * scheme-based names because the default implementation of the {@link InitialContext}
+ * always uses the default context of the builder if one is installed no matter
+ * the scheme in the name.
* <p>
- * This class prevents that by acting exactly like the InitialContext would if
- * the initial context factory builder wasn't installed. This enables the callers
- * to still use the standard InitialContext when doing lookups etc. This standard
- * initial context will ask our initial context factory builder which will then
- * in chain create this {@link URLPreferringContext} that behaves like the original
- * InitialContext would if the builder wasn't there.
+ * The {@link AccessCheckingInitialContextFactoryBuilder} wraps the context returned
+ * by the factory in an instance of this class and thus is restoring the original
+ * intended behavior of the {@link InitialContext}. It looks at the name being looked
+ * up (bound or whatever) and prefers to use the URL context factories if the name
+ * contains the scheme (as does the {@link InitialContext} if no builder is installed).
+ * If the name doesn't contain a scheme, the provided default context factory is used to
+ * look up the name.
*
* @author Lukas Krejci
*/
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
index 6c311c7..609e98c 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
@@ -22,7 +22,6 @@ package org.rhq.jndi;
import java.util.Hashtable;
import javax.naming.Context;
-import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
@@ -31,8 +30,7 @@ import javax.naming.spi.InitialContextFactory;
* backed by the wrapped initial context factory.
* <p>
* This is to support contexts that don't need to be secured, yet we need to make sure to
- * break the call-chain loop caused by the {@link InitialContext} asking the RHQ's {@link AccessCheckingInitialContextFactoryBuilder} for
- * default contexts.
+ * re-enable lookup of scheme-based names.
*
* @author Lukas Krejci
*/
commit 0dcc5c33c0cc9ca03a32bd17dd8e188ca27b243d
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Tue Jan 3 14:47:12 2012 +0100
Adding integration tests for the ability of serverside scripts to access remote JNDI servers (unlike the JNDI directory of the RHQ server itself).
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/pom.xml b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
new file mode 100644
index 0000000..1991e0e
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/pom.xml
@@ -0,0 +1,315 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-test</artifactId>
+ <packaging>jar</packaging>
+
+ <name>JNDI access integration test</name>
+ <description>Tests for local and remote JNDI access from within serverside scripts.</description>
+
+ <properties>
+ <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
+ <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
+ <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
+ <jnp.port>54987</jnp.port>
+ <jnp.rmiPort>54988</jnp.rmiPort>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <!--================ Test Deps ================ -->
+
+ <!-- Note, the test deps are intentionally placed above the other
+ scoped deps because of classpath reasons. Maven orders the [test] classpath
+ in the order listed in the pom. We specifically need the embeddable-ejb3
+ jar above the standard ejb3 jars because we need the embeddble packages loaded
+ when testing. -->
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-core-domain</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-core-client-api</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-server-client-api</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-remote-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss.jboss-embeddable-ejb3</groupId>
+ <artifactId>jboss-ejb3-all</artifactId>
+ <version>${jboss-embeddable-ejb3.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- NOTE: The remaining test deps correspond to the classes contained
+ in hibernate-all.jar and thirdparty-all.jar. -->
+
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- needed by embedded ejb container -->
+ <dependency>
+ <groupId>trove</groupId>
+ <artifactId>trove</artifactId>
+ <version>1.0.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- needed by embedded ejb container -->
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- 3rd Party Deps -->
+
+ <!-- required by RHQ server classes, as well as EJB3 Embedded -->
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1-jboss</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate</groupId>
+ <artifactId>hibernate3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-annotations</groupId>
+ <artifactId>hibernate-annotations</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-entitymanager</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-annotations-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed
+ by the PoolClass annotation used on some of our SLSB's -->
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <!-- for the transaction interrupt EJB3 interceptor -->
+ <dependency>
+ <groupId>org.jboss.transaction</groupId>
+ <artifactId>jboss-jta</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz-oracle</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
+ section. -->
+ <scope>provided</scope> <!-- by JBossAS itself, which the container build has packaged with 1.6.5 -->
+ </dependency>
+
+ <!-- This is needed cglib which is in turn needed by hibernate -->
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.18</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <!-- in order to get JMS to work properly in embedded
+ test container, extract jms-rs.rar classes -->
+ <execution>
+ <id>Extract JMS classes from RAR needed for JMS tests</id>
+ <phase>process-classes</phase>
+ <configuration>
+ <tasks>
+ <unzip src="src/test/resources/jms-ra.rar"
+ dest="target">
+ <patternset>
+ <include name="jms-ra.jar" />
+ </patternset>
+ </unzip>
+ <unzip src="target/jms-ra.jar"
+ dest="target/test-classes">
+ <patternset>
+ <include name="org/**" />
+ </patternset>
+ </unzip>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <!-- Everything but the web service tests, this is the standard
+ test execution -->
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <groups>${rhq.testng.includedGroups}</groups>
+ <systemPropertyVariables>
+ <embeddedDeployment>true</embeddedDeployment>
+ <deploymentDirectory>target/test-classes</deploymentDirectory>
+ <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
+ <clean.db>${clean.db}</clean.db>
+ <test.server.jar.path>${settings.localRepository}/org/rhq/jndi-access-remote-server/${project.version}/jndi-access-remote-server-${project.version}.jar</test.server.jar.path>
+ <jnp.port>${jnp.port}</jnp.port>
+ <jnp.rmiPort>${jnp.rmiPort}</jnp.rmiPort>
+ </systemPropertyVariables>
+ <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
+ <additionalClasspathElements>
+ <!-- The below is required for tests to run against
+ Oracle. -->
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
new file mode 100644
index 0000000..f20d4f1
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/java/org/rhq/jndi/test/JndiAccessTest.java
@@ -0,0 +1,193 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.SerializablePermission;
+import java.security.PermissionCollection;
+import java.util.Collections;
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Parameters;
+import org.testng.annotations.Test;
+
+import org.rhq.bindings.SandboxedScriptEngine;
+import org.rhq.bindings.ScriptEngineFactory;
+import org.rhq.bindings.StandardBindings;
+import org.rhq.bindings.StandardScriptPermissions;
+import org.rhq.bindings.util.PackageFinder;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class JndiAccessTest extends AbstractEJB3Test {
+ private static final Log JNP_SERVER_LOG = LogFactory.getLog("Test JNP Server");
+
+ private Process testServerProcess;
+ private Thread testServerStdErrReader;
+ private Thread testServerStdOutReader;
+
+ @BeforeClass
+ @Parameters({"test.server.jar.path", "jnp.port", "jnp.rmiPort"})
+ public void startTestJnpServer(String testServerJar, int jnpPort, int rmiPort) throws Exception {
+ ProcessBuilder bld = new ProcessBuilder("java", "-Djnp.port=" + jnpPort, "-Djnp.rmiPort=" + rmiPort, "-jar", testServerJar);
+
+ testServerProcess = bld.start();
+
+ testServerStdErrReader = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getErrorStream()));
+ try {
+ String line;
+ while((line = rdr.readLine()) != null) {
+ JNP_SERVER_LOG.warn(line);
+ }
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Reading test JNP server error output failed.", e);
+ } finally {
+ try {
+ rdr.close();
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Failed to close the test server error stream.", e);
+ }
+ }
+ }
+ });
+ testServerStdErrReader.start();
+
+ testServerStdOutReader = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(testServerProcess.getInputStream()));
+ try {
+ String line;
+ while((line = rdr.readLine()) != null) {
+ JNP_SERVER_LOG.debug(line);
+ }
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Reading test JNP server standard output failed.", e);
+ } finally {
+ try {
+ rdr.close();
+ } catch (IOException e) {
+ JNP_SERVER_LOG.error("Failed to close the test server standard output stream.", e);
+ }
+ }
+ }
+ });
+ testServerStdOutReader.start();
+
+ //give the JNP server some time to start up
+ Thread.sleep(5000);
+ }
+
+ @AfterClass
+ public void stopTestJnpServer() throws Exception {
+ testServerProcess.destroy();
+ testServerStdErrReader.join();
+ testServerStdOutReader.join();
+ }
+
+ @Parameters("jnp.port")
+ public void testRemoteConnectionWorkingFromJava(int jnpPort) throws Exception {
+ Properties env = new Properties();
+ env.put("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory");
+ env.put("java.naming.provider.url", "jnp://localhost:" + jnpPort);
+ InitialContext ctx = new InitialContext(env);
+ Object kachny = ctx.lookup("kachny");
+
+ assert kachny != null;
+ }
+
+ public void testLocalJNDILookupFailsFromScripts() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ @Parameters("jnp.port")
+ public void testRemoteJNDILookupWorksFromScripts(int jnpPort) throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "env = new java.util.Hashtable();"
+ + "env.put('java.naming.factory.initial', 'org.jboss.naming.NamingContextFactory');"
+ + "env.put('java.naming.provider.url', 'jnp://localhost:" + jnpPort + "');"
+ + "context = new javax.naming.InitialContext(env);\n"
+ + "kachny = context.lookup('kachny');\n"
+ + "assertNotNull(kachny);\n");
+ } catch (ScriptException e) {
+ Assert.fail("The script should have been able to access a remote JNDI server.", e);
+ }
+ }
+
+ private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
+ StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
+ ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
+
+ PermissionCollection perms = new StandardScriptPermissions();
+
+ return new SandboxedScriptEngine(engine, perms);
+ }
+
+ private static void checkIsDesiredSecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
+ }
+}
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
new file mode 100644
index 0000000..1951b84
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/hibernate.properties
@@ -0,0 +1,26 @@
+# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
+# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
+# WORK IN THIS MODULE.
+
+hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
+#hibernate.connection.release_mode=after_statement
+#hibernate.transaction.flush_before_completion=false
+#hibernate.transaction.auto_close_session=false
+#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
+#hibernate.hbm2ddl.auto=create-drop
+#hibernate.hbm2ddl.auto=create
+hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
+# Clustered cache with TreeCache
+#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
+#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
+#hibernate.dialect=org.hibernate.dialect.HSQLDialect
+hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+hibernate.bytecode.use_reflection_optimizer=false
+# I don't think this is honored, but EJB3Deployer uses it
+hibernate.bytecode.provider=javassist
+hibernate.jdbc.use_streams_for_binary=true
+hibernate.show_sql=false
+hibernate.format_sql=true
+hibernate.default_batch_fetch_size=16
+hibernate.jdbc.batch_size=20
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/jms-ra.rar b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/jms-ra.rar
new file mode 100644
index 0000000..c4807c6
Binary files /dev/null and b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/jms-ra.rar differ
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
new file mode 100644
index 0000000..ec09ed7
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/log4j.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<!-- $Id: log4j.xml 39945 2006-01-12 02:44:07Z bill $ -->
+
+<!--
+ | For more configuration infromation and examples see the Jakarta Log4j
+ | owebsite: http://jakarta.apache.org/log4j
+ -->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
+ <param name="Target" value="System.out"/>
+ <param name="Threshold" value="WARN"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <!-- The default pattern: Date Priority [Category] Messagen -->
+ <!--
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+ -->
+ <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
+ </layout>
+ </appender>
+
+ <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
+ <param name="File" value="target/server-jar-test.log"/>
+ <param name="Threshold" value="WARN"/>
+ <param name="Append" value="false"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <!-- The default pattern: Date Priority [Category] Messagen -->
+ <!--
+ <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+ -->
+ <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} [%c] (%F:%M:%L) -%m%n"/>
+ </layout>
+ </appender>
+
+ <category name="Test JNP Server">
+ <priority value="DEBUG"/>
+ </category>
+
+ <!-- Hibernate logs WARNINGS frequent from this class, in test envs. -->
+ <category name="org.hibernate.hql.ast.QueryTranslatorImpl">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- hides the TIMER SERVICE IS NOT INSTALLED warning - we know embedded EJB3 container doesn't support timers -->
+ <category name="org.jboss.ejb3.timerservice.jboss.JBossTimerServiceFactory">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- hides the shutdown warnings - for some reason, the container spits out some warnings when shutting down -->
+ <category name="org.jboss.kernel.plugins.dependency.StartStopLifecycleAction">
+ <priority value="ERROR"/>
+ </category>
+
+ <!-- Hibernate SQL logs -->
+ <!--
+ <category name="org.hibernate.SQL">
+ <priority value="DEBUG"/>
+ </category>
+ -->
+
+ <root>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ </root>
+
+</log4j:configuration>
diff --git a/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
new file mode 100644
index 0000000..8860b47
--- /dev/null
+++ b/modules/integration-tests/jndi-access/jndi-access-test/src/test/resources/security.policy
@@ -0,0 +1,10 @@
+// We need the SecurityManager installed to enable sandboxing of CLI scripts
+// but we don't define any other security measures on the RHQ server itself.
+//
+// Granting all permissions allows us to run the RHQ server as if no security
+// manager was in place (which is assumed by default by JBoss AS) but be able
+// to use it when we need it for our own purposes.
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/modules/integration-tests/jndi-access/pom.xml b/modules/integration-tests/jndi-access/pom.xml
new file mode 100644
index 0000000..6e9c673
--- /dev/null
+++ b/modules/integration-tests/jndi-access/pom.xml
@@ -0,0 +1,21 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>rhq-integration-tests</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <packaging>pom</packaging>
+
+ <name>JNDI access tests</name>
+ <description>Tests for the secured JNDI access tests</description>
+
+ <modules>
+ <module>remote-server</module>
+ <module>jndi-access-test</module>
+ </modules>
+</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/pom.xml b/modules/integration-tests/jndi-access/remote-server/pom.xml
new file mode 100644
index 0000000..9046e6f
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/pom.xml
@@ -0,0 +1,72 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>jndi-access-test-parent</artifactId>
+ <groupId>org.rhq</groupId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>jndi-access-remote-server</artifactId>
+ <packaging>jar</packaging>
+
+ <name>Test JNDI-enabled remote server</name>
+ <description>
+ A testing JNDI-enabled server to test the ability to connect to remote servers without security
+ checks from within the scripts running inside the RHQ server.
+ </description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jnpserver</artifactId>
+ <version>4.2.2.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-common</artifactId>
+ <version>4.2.2.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>oswego-concurrent</groupId>
+ <artifactId>concurrent</artifactId>
+ <version>1.3.4-jboss</version>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package</id>
+ <phase>package</phase>
+ <goals><goal>single</goal></goals>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>org.rhq.jndi.test.Server</mainClass>
+ </manifest>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java b/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
new file mode 100644
index 0000000..7bfb8e8
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/java/org/rhq/jndi/test/Server.java
@@ -0,0 +1,79 @@
+package org.rhq.jndi.test;
+import java.util.Properties;
+
+import javax.naming.CompoundName;
+
+import org.jnp.server.Main;
+import org.jnp.server.NamingBeanImpl;
+
+import org.jboss.logging.Logger;
+
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2012 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class Server {
+ private static final Logger LOG = Logger.getLogger(Server.class);
+
+ private static Server INSTANCE;
+
+ private Main jnpServer;
+
+ public static void main(String[] args) throws Exception {
+ LOG.debug("System properties: " + System.getProperties());
+ Server.start();
+ }
+
+ private Server() {
+ jnpServer = new Main("org.rhq.jndi.access.test.server");
+ }
+
+ public static synchronized Server getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new Server();
+ }
+
+ return INSTANCE;
+ }
+
+ public static void start() throws Exception {
+ LOG.debug("Initializing the JNP server");
+
+ NamingBeanImpl nbi = new NamingBeanImpl();
+ getInstance().jnpServer.setNamingInfo(nbi);
+ nbi.start();
+
+ LOG.debug("Binding kachny");
+
+ nbi.getNamingInstance().bind(new CompoundName("kachny", new Properties()), "KACHNY!", String.class.getName());
+
+ LOG.debug("Starting the JNP server");
+
+ getInstance().jnpServer.start();
+ }
+
+ public static void stop() {
+ LOG.debug("Stopping the JNP server");
+ getInstance().jnpServer.stop();
+ }
+}
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
new file mode 100644
index 0000000..a45f2ce
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/resources/jndi.properties
@@ -0,0 +1,2 @@
+java.naming.factory.initial=org.jboss.naming.NamingContextFactory
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
\ No newline at end of file
diff --git a/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties b/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
new file mode 100644
index 0000000..2d41f83
--- /dev/null
+++ b/modules/integration-tests/jndi-access/remote-server/src/main/resources/log4j.properties
@@ -0,0 +1,5 @@
+log4j.rootCategory=TRACE, CONSOLE
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c] %m%n
diff --git a/modules/integration-tests/pom.xml b/modules/integration-tests/pom.xml
index 0290729..969b94a 100644
--- a/modules/integration-tests/pom.xml
+++ b/modules/integration-tests/pom.xml
@@ -62,6 +62,7 @@
<id>integration-tests</id>
<modules>
<module>apache-plugin-test</module>
+ <module>jndi-access</module>
<!--<module>mod_cluster-plugin-test</module>-->
</modules>
</profile>
commit 89027fe4e28299fbe408617ff830701c63ec00e5
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Tue Jan 3 14:01:32 2012 +0100
BZ 771216 - return messages accompanying error codes with the return type the client has requested.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
index 58ccf30..fe23ad2 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
@@ -18,12 +18,16 @@
*/
package org.rhq.enterprise.server.rest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.rhq.enterprise.server.authz.PermissionException;
import org.rhq.enterprise.server.resource.ResourceNotFoundException;
+import org.rhq.enterprise.server.rest.domain.RHQErrorWrapper;
/**
* Map a NotFoundException to a HTTP response with respective error message
@@ -32,10 +36,14 @@ import org.rhq.enterprise.server.resource.ResourceNotFoundException;
@Provider
public class CustomExceptionMapper implements ExceptionMapper<Exception> {
+ @Context
+ HttpHeaders httpHeaders;
@Override
public Response toResponse(Exception e) {
+
+
Throwable cause = e.getCause();
Response.ResponseBuilder builder;
if (cause !=null) {
@@ -52,7 +60,8 @@ public class CustomExceptionMapper implements ExceptionMapper<Exception> {
status = Response.Status.SERVICE_UNAVAILABLE;
builder = Response.status(status);
- builder.entity(cause.getMessage());
+ String message = cause.getMessage();
+ wrapMessage(builder, message);
}
else {
if (e instanceof PermissionException) {
@@ -60,9 +69,30 @@ public class CustomExceptionMapper implements ExceptionMapper<Exception> {
} else {
builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
}
- if (e.getMessage()!=null)
- builder.entity(e.getMessage());
+ if (e.getMessage()!=null) {
+ wrapMessage(builder,e.getMessage());
+ }
}
return builder.build();
}
+
+ /**
+ * Wrap the passed message according to the mediaType from the HttpHeader
+ * @param builder
+ * @param message
+ */
+ private void wrapMessage(Response.ResponseBuilder builder, String message) {
+
+ MediaType mediaType = httpHeaders.getAcceptableMediaTypes().get(0);
+
+ if (mediaType.equals(MediaType.TEXT_PLAIN_TYPE)) {
+ builder.entity(message);
+ } else if (mediaType.equals(MediaType.TEXT_HTML_TYPE)) {
+ builder.entity("<html><body><h1>Error</h1><h2>" + message + "</h2></body></html>");
+ } else {
+ RHQErrorWrapper error = new RHQErrorWrapper(message);
+ builder.entity(error);
+ }
+ builder.type(mediaType);
+ }
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/RHQErrorWrapper.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/RHQErrorWrapper.java
new file mode 100644
index 0000000..f62b1bc
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/RHQErrorWrapper.java
@@ -0,0 +1,28 @@
+package org.rhq.enterprise.server.rest.domain;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Wrapper for Exceptions
+ * @author Heiko W. Rupp
+ */
+@XmlRootElement
+public class RHQErrorWrapper {
+
+ private String message;
+
+ public RHQErrorWrapper(String message) {
+ this.message = message;
+ }
+
+ public RHQErrorWrapper() {
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
commit 3fea0b257d0598b7beeaa2bc3982b2d07def1887
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 2 22:05:49 2012 +0100
Mention RHQ samples project.
diff --git a/modules/enterprise/gui/rest-war/src/main/webapp/index.html b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
index 76aa220..9e96d76 100644
--- a/modules/enterprise/gui/rest-war/src/main/webapp/index.html
+++ b/modules/enterprise/gui/rest-war/src/main/webapp/index.html
@@ -5,7 +5,9 @@
Join us in making it great by providing feedback and contributions of code and examples
that use the api.
-See also <a href="http://rhq-project.org/display/RHQ/Design-REST">the RHQ wiki</a> and
+See also <a href="http://rhq-project.org/display/RHQ/Design-REST">the RHQ wiki</a> on REST.
+Check out the <a href="https://github.com/rhq-project/samples/tree/master/rest-api">RHQ samples project</a>
+for samples in various programming languages and
<a href="https://github.com/pilhuhn/RHQpocket">RHQpocket</a> as an example of a
mobile client (Android) of the API.
<ul>
commit 09dee7d811bfed40ff6b4606242c4aa89f8225c6
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Mon Jan 2 13:08:00 2012 +0100
sort retrieved values by timestamp, as some clients don't cope well with out of order data.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index ba9785c..77e36a4 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -510,6 +510,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
sb.append(" UNION ALL ");
}
+ sb.append(" ORDER BY time_stamp ASC");
commit 14fc3e1c71e67517449dcbe6543327cee9ffddcb
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sat Dec 31 15:21:30 2011 +0100
Rollback jackson to 1.7.4, as 1.9.3 has a bug (JACKSON-744)
diff --git a/modules/plugins/jboss-as-7/pom.xml b/modules/plugins/jboss-as-7/pom.xml
index f39c296..8220355 100644
--- a/modules/plugins/jboss-as-7/pom.xml
+++ b/modules/plugins/jboss-as-7/pom.xml
@@ -16,7 +16,7 @@
<properties>
<json.version>${project.json.version}</json.version>
- <jackson.version>1.9.3</jackson.version>
+ <jackson.version>1.7.4</jackson.version>
<jboss.sasl.version>1.0.0.Beta9</jboss.sasl.version>
</properties>
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
index 11f823d..e895dd4 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
@@ -21,6 +21,7 @@ package org.rhq.modules.plugins.jbossas7;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -430,7 +431,8 @@ public class ConfigurationLoadingTest extends AbstractConfigurationHandlingTest
ConfigurationLoadDelegate delegate = new ConfigurationLoadDelegate(definition,connection,null);
Configuration config = delegate.loadResourceConfiguration();
assert config!=null;
- assert config.getProperties().size()==5 : "Got " + config.getProperties().size() + " props instead of 5: " + config.getProperties().toString();
+ Collection<Property> properties = config.getProperties();
+ assert properties.size()==6 : "Got " + properties.size() + " props instead of 6: " + properties.toString();
PropertySimple simple = config.getSimple("check-interval");
assert simple !=null;
Integer integerValue = simple.getIntegerValue();
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
index 67f2243..2dcd49f 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
@@ -59,6 +59,7 @@ public class OperationJsonTest {
assert op!=null;
assert op.getOperation()!=null : "op.operation was null!";
assert op.getOperation().equals(operation.getOperation()) : "Operation is " + op.getOperation();
+ assert op.getName()!=null : "op.getName is null";
assert op.getName().equals("socket-binding") : "attribute name is " + op.getName() + " and not 'socket-binding'";
assert op.getValue().equals("jndi") : "attribute value is " + op.getValue();
assert op.getAddress().size()==2 : "Address did not contain 2 parts, but " + op.getAddress().size();
commit 685a93c8b98e796173e5830159b33aa8350676a0
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Dec 30 17:02:00 2011 +0100
Support submission of (numerical) metrics into the server and retrieval of raw numeric values.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementData.java b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementData.java
index d0d26ab..d22689f 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementData.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementData.java
@@ -82,6 +82,10 @@ public abstract class MeasurementData implements Serializable {
this.setName(request.getName());
}
+ protected MeasurementData(long timestamp, int scheduleId) {
+ this(new MeasurementDataPK(timestamp,scheduleId));
+ }
+
public int getScheduleId() {
return id.scheduleId;
}
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementDataNumeric.java b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementDataNumeric.java
index 4e82c43..d0bf41f 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementDataNumeric.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/measurement/MeasurementDataNumeric.java
@@ -59,6 +59,11 @@ public class MeasurementDataNumeric extends MeasurementData implements Serializa
this.rawNumericType = request.getRawNumericType();
}
+ public MeasurementDataNumeric(long collectionTime, int scheduleId,Double value) {
+ super(collectionTime,scheduleId);
+ this.value = value;
+ }
+
@Deprecated
// Have to make this protected so that people only use the constructor taking a request (so the name can be set for live values)
public MeasurementDataNumeric(MeasurementDataPK md, Double value) {
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 7ffb8e1..7bb7c8f 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
@@ -20,6 +20,7 @@ package org.rhq.enterprise.server.measurement;
import java.sql.Connection;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
@@ -176,9 +177,9 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
long start = System.currentTimeMillis();
// TODO GH: Deal with offset (this is only for situations where the clock doesn't match on the agent)
- /*
+ /*
* even if these methods check for null/empty collections, they cross the EJB boundary and so unnecessarily
- * start transactions. by checking the null/emptiness of a collection here, by only create transactions
+ * start transactions. by checking the null/emptiness of a collection here, by only create transactions
* when real work will be done;
*/
if (report.getNumericData() != null && !report.getNumericData().isEmpty()) {
@@ -799,6 +800,37 @@ public class MeasurementDataManagerBean implements MeasurementDataManagerLocal,
return values;
}
+ @Override
+ public List<MeasurementDataNumeric> findRawData(Subject subject, int scheduleId, long startTime, long endTime) {
+
+ List<MeasurementDataNumeric> result = new ArrayList<MeasurementDataNumeric>();
+ String table = MeasurementDataManagerUtility.getCurrentRawTable();
+ Connection connection = null;
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ connection = rhqDs.getConnection();
+ ps = connection.prepareStatement( // TODO supply real impl that spans multiple tables
+ "SELECT time_stamp,value FROM " + table + " WHERE schedule_id= ? AND time_stamp BETWEEN ? AND ?");
+ ps.setLong(1,scheduleId);
+ ps.setLong(2,startTime);
+ ps.setLong(3,endTime);
+ rs = ps.executeQuery();
+
+ while (rs.next()) {
+ MeasurementDataNumeric point = new MeasurementDataNumeric(rs.getLong(1),scheduleId,rs.getDouble(2));
+ result.add(point);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace(); // TODO: Customise this generated block
+ } finally {
+ JDBCUtil.safeClose(connection, ps, rs);
+ }
+
+
+ return result;
+ }
+
private List<MeasurementDataRequest> createRequests(List<MeasurementDefinition> definitions) {
List<MeasurementDataRequest> requests = new ArrayList<MeasurementDataRequest>();
for (MeasurementDefinition definition : definitions) {
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerLocal.java
index e80f16a..4ea8302 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/measurement/MeasurementDataManagerLocal.java
@@ -189,4 +189,6 @@ public interface MeasurementDataManagerLocal {
List<List<MeasurementDataNumericHighLowComposite>> findDataForResource(Subject subject, int resourceId,
int[] definitionIds, long beginTime, long endTime, int numPoints);
+
+ List<MeasurementDataNumeric> findRawData(Subject subject, int scheduleId, long startTime, long endTime);
}
\ No newline at end of file
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index 99dd6fe..ba9785c 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -18,18 +18,34 @@
*/
package org.rhq.enterprise.server.rest;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
import java.net.URI;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
+import javax.sql.DataSource;
+import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
@@ -38,6 +54,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@@ -45,9 +62,13 @@ import org.jboss.cache.Fqn;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.measurement.DataType;
+import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.MeasurementSchedule;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
+import org.rhq.core.util.jdbc.JDBCUtil;
+import org.rhq.enterprise.server.RHQConstants;
+import org.rhq.enterprise.server.measurement.util.MeasurementDataManagerUtility;
import org.rhq.enterprise.server.resource.ResourceManagerLocal;
import org.rhq.enterprise.server.rest.domain.Link;
import org.rhq.enterprise.server.rest.domain.MetricAggregate;
@@ -55,6 +76,7 @@ import org.rhq.enterprise.server.measurement.MeasurementAggregate;
import org.rhq.enterprise.server.measurement.MeasurementDataManagerLocal;
import org.rhq.enterprise.server.measurement.MeasurementScheduleManagerLocal;
import org.rhq.enterprise.server.rest.domain.MetricSchedule;
+import org.rhq.enterprise.server.rest.domain.NumericDataPoint;
/**
* Deal with metrics
@@ -62,6 +84,7 @@ import org.rhq.enterprise.server.rest.domain.MetricSchedule;
*/
@Interceptors(SetCallerInterceptor.class)
@Stateless
+(a)javax.annotation.Resource(name = "RHQ_DS", mappedName = RHQConstants.DATASOURCE_JNDI_NAME)
public class MetricHandlerBean extends AbstractRestBean implements MetricHandlerLocal {
@EJB
@@ -71,6 +94,10 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
@EJB
ResourceManagerLocal resMgr;
+ @javax.annotation.Resource(name = "RHQ_DS")
+ private DataSource rhqDs;
+
+
private static final long EIGHT_HOURS = 8 * 3600L * 1000L;
@Override
@@ -87,20 +114,7 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
startTime = endTime - EIGHT_HOURS;
}
-
- MeasurementSchedule schedule;
- schedule = getFromCache(scheduleId,MeasurementSchedule.class);
- if (schedule==null) {
- schedule = scheduleManager.getScheduleById(caller,scheduleId);
- if (schedule==null) {
- throw new StuffNotFoundException("Schedule with id " + scheduleId);
- }
- else
- putToCache(scheduleId,MeasurementSchedule.class,schedule);
- }
-
- if (schedule.getDefinition().getDataType()!= DataType.MEASUREMENT)
- throw new IllegalArgumentException("Schedule [" + scheduleId + "] is not a (numerical) metric");
+ MeasurementSchedule schedule = obtainSchedule(scheduleId);
MeasurementAggregate aggr = dataManager.getAggregate(caller, scheduleId, startTime, endTime);
MetricAggregate res = new MetricAggregate(scheduleId, aggr.getMin(),aggr.getAvg(),aggr.getMax());
@@ -156,6 +170,28 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
return builder.build();
}
+ /**
+ * Get the schedule for the passed schedule id
+ * @param scheduleId id to look up
+ * @return schedule
+ * @throws StuffNotFoundException if there is no schedule with the passed id
+ */
+ private MeasurementSchedule obtainSchedule(int scheduleId) {
+ MeasurementSchedule schedule;
+ schedule = getFromCache(scheduleId,MeasurementSchedule.class);
+ if (schedule==null) {
+ schedule = scheduleManager.getScheduleById(caller,scheduleId);
+ if (schedule==null) {
+ throw new StuffNotFoundException("Schedule with id " + scheduleId);
+ }
+ else
+ putToCache(scheduleId,MeasurementSchedule.class,schedule);
+ }
+
+ if (schedule.getDefinition().getDataType()!= DataType.MEASUREMENT)
+ throw new IllegalArgumentException("Schedule [" + scheduleId + "] is not a (numerical) metric");
+ return schedule;
+ }
private MetricAggregate fill(MetricAggregate res, List<MeasurementDataNumericHighLowComposite> list, int scheduleId,
boolean hideEmpty) {
long minTime=Long.MAX_VALUE;
@@ -180,7 +216,6 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
return res;
}
- @Override
@GET
@Path("data")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_HTML})
@@ -382,4 +417,139 @@ public class MetricHandlerBean extends AbstractRestBean implements MetricHandle
return Response.ok(ret,httpHeaders.getAcceptableMediaTypes().get(0)).build();
}
+
+ @GET
+ @Path("data/{scheduleId}/raw")
+ public StreamingOutput getMetricDataRaw(@PathParam("scheduleId") int scheduleId,
+ @QueryParam("startTime") long startTime,
+ @QueryParam("endTime") long endTime,
+ long duration,
+ Request request,
+ HttpHeaders headers) {
+
+
+ if (endTime==0)
+ endTime = System.currentTimeMillis();
+ if (startTime==0)
+ startTime = endTime - EIGHT_HOURS;
+ if (duration>0) // overrides start time
+ startTime = endTime - duration*1000L; // duration is in seconds
+
+ if (startTime < System.currentTimeMillis()-7L*86400*1000)
+ throw new IllegalArgumentException("Start time is older than 7 days");
+
+ // Check if the schedule exists
+ obtainSchedule(scheduleId);
+
+ RawNumericJsonStreamingOutput so = new RawNumericJsonStreamingOutput();
+ so.scheduleId = scheduleId;
+ so.startTime = startTime;
+ so.endTime = endTime;
+
+
+ return so;
+ }
+
+ @Override
+ @PUT
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Path("data/{scheduleId}/raw/{timeStamp}")
+ public Response putMetricValue(@PathParam("scheduleId") int scheduleId, @PathParam("timeStamp") long timestamp,
+ NumericDataPoint point, @Context HttpHeaders headers) {
+
+ MeasurementSchedule schedule = obtainSchedule(scheduleId);
+
+ Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>(1);
+ data.add(new MeasurementDataNumeric(point.getTimeStamp(),scheduleId,point.getValue()));
+
+ dataManager.addNumericData(data);
+
+ return Response.ok().build(); // TODO correct code?
+ }
+
+
+ @Override
+ @POST
+ @Path("data/raw")
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ public Response postMetricValues(Collection<NumericDataPoint> points, @Context HttpHeaders headers) {
+
+ Set<MeasurementDataNumeric> data = new HashSet<MeasurementDataNumeric>(points.size());
+ for (NumericDataPoint point : points) {
+ data.add(new MeasurementDataNumeric(point.getTimeStamp(), point.getScheduleId(),point.getValue()));
+ }
+
+ dataManager.addNumericData(data);
+
+ return Response.ok().build();
+
+ }
+
+ /**
+ * Write the numeric data points to the output stream in JSON encoding
+ * without creating tons of objects in the middle to have them marshalled
+ * by JAX-RS
+ */
+ private class RawNumericJsonStreamingOutput implements StreamingOutput {
+
+ int scheduleId;
+ long startTime;
+ long endTime;
+
+ @Override
+ public void write(OutputStream outputStream) throws IOException, WebApplicationException {
+
+ String[] tables = MeasurementDataManagerUtility.getTables(startTime,endTime);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0 ; i < tables.length ; i ++) {
+ sb.append("SELECT time_stamp,value FROM ");
+ sb.append(tables[i]);
+ sb.append(" WHERE schedule_id = ? AND time_stamp BETWEEN ? AND ?");
+ if (i < tables.length-1)
+ sb.append(" UNION ALL ");
+ }
+
+
+
+
+ Connection connection = null;
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ try {
+ connection = rhqDs.getConnection();
+ ps = connection.prepareStatement( sb.toString() );
+ for (int i = 0; i < tables.length ; i++) {
+ ps.setInt(i * 3 + 1, scheduleId);
+ ps.setLong(i*3+2,startTime);
+ ps.setLong(i*3+3,endTime);
+ }
+ rs = ps.executeQuery();
+
+ PrintWriter pw = new PrintWriter(outputStream);
+ pw.println("[");
+ while (rs.next()) {
+ pw.print("{");
+ pw.print("\"scheduleId\":");
+ pw.print(scheduleId);
+ pw.print(", ");
+ pw.print("\"timeStamp\":");
+ pw.print(rs.getLong(1));
+ pw.print(", ");
+ pw.print("\"value\":");
+ pw.print(rs.getLong(2));
+ pw.print("}");
+ if (!rs.isLast())
+ pw.print(",\n");
+ }
+ pw.println("]");
+ pw.flush();
+ pw.close();
+ } catch (SQLException e) {
+ log.error(e);
+ } finally {
+ JDBCUtil.safeClose(connection, ps, rs);
+ }
+ }
+ }
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
index 6631ef4..2c75a55 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
@@ -18,12 +18,14 @@
*/
package org.rhq.enterprise.server.rest;
+import java.util.Collection;
import java.util.List;
import javax.ejb.Local;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@@ -34,10 +36,12 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
import org.rhq.enterprise.server.rest.domain.MetricAggregate;
import org.rhq.enterprise.server.rest.domain.MetricSchedule;
+import org.rhq.enterprise.server.rest.domain.NumericDataPoint;
/**
* Deal with metrics
@@ -76,16 +80,77 @@ public interface MetricHandlerLocal {
@Path("data/resource/{resourceId}")
List<MetricAggregate> getAggregatesForResource(@PathParam("resourceId") int resourceId);
+ /**
+ * Get information about the schedule
+ * @param scheduleId id of the schedule
+ * @param request Injected request
+ * @param headers Injected http headers
+ * @param uriInfo Injected Uri
+ * @return the schedule
+ */
@GET
@Path("/schedule/{id}")
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML,MediaType.TEXT_HTML})
Response getSchedule(@PathParam("id") int scheduleId, @Context Request request, @Context HttpHeaders headers,
@Context UriInfo uriInfo);
+ /**
+ * Update a schedule. Currently change of collection interval and enabled/disabled state are supported.
+ * @param scheduleId Id of the schedule to update
+ * @param in Modified schedule object
+ * @param headers Injected http headers
+ * @return Result of updating
+ */
@PUT
@Path("/schedule/{id}")
@Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
Response updateSchedule(@PathParam("id") int scheduleId, MetricSchedule in,@Context HttpHeaders headers);
+ /**
+ * Expose the raw metrics for the given schedule
+ * @param scheduleId Schedule id
+ * @param startTime Start time, if 0 and duration=, start time = 8h before endTime
+ * @param endTime End time. If 0, now is used
+ * @param duration Duration in seconds. If duration=0, startTime is used
+ * @param request Injected Request headers
+ * @param headers Injected HttpHeaders
+ * @return a JSON encoded stream of numerical values
+ */
+ @GET
+ @Path("data/{scheduleId}/raw")
+ @Produces({MediaType.APPLICATION_JSON})
+ StreamingOutput getMetricDataRaw(@PathParam("scheduleId") int scheduleId,
+ @QueryParam("startTime") long startTime,
+ @QueryParam("endTime") long endTime,
+ @QueryParam("duration") long duration,
+ @Context Request request,
+ @Context HttpHeaders headers);
+
+ /**
+ * Submit a single (numerical) metric value to the server.
+ * @param scheduleId Id of the schedule to submit to
+ * @param timestamp Timestamp of the entry
+ * @param point Datapoint of class NumericDataPoint
+ * @param headers Injected HTTP headers
+ * @return
+ */
+ @PUT
+ @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
+ @Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
+ @Path("data/{scheduleId}/raw/{timeStamp}")
+ Response putMetricValue(@PathParam("scheduleId")int scheduleId,
+ @PathParam("timeStamp")long timestamp, NumericDataPoint point,
+ @Context HttpHeaders headers);
+
+ /**
+ * Submit a series of (numerical) metric values to the server
+ * @param points Collection of NumericDataPoint entries
+ * @param headers Injected HTTP headers
+ * @return
+ */
+ @POST
+ @Path("data/raw")
+ @Consumes({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
+ Response postMetricValues(Collection<NumericDataPoint> points, @Context HttpHeaders headers);
}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/NumericDataPoint.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/NumericDataPoint.java
new file mode 100644
index 0000000..e1ef904
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/NumericDataPoint.java
@@ -0,0 +1,65 @@
+package org.rhq.enterprise.server.rest.domain;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * One numerical data point of a schedule.
+ * This point does not contain the schedule id, as it is expected
+ * to be used to return lists of data points for a schedule.
+ *
+ * Xml names for the item and the attributes are shortened to
+ * conserve space when transferring to clients
+ *
+ * @author Heiko W. Rupp
+ */
+@XmlRootElement
+public class NumericDataPoint {
+
+ long timeStamp;
+ Double value;
+ private int scheduleId;
+
+ @SuppressWarnings("unused")
+ public NumericDataPoint() {
+ // Needed for JAXB
+ }
+
+ public NumericDataPoint(long timeStamp, Double value) {
+ this.timeStamp = timeStamp;
+ this.value = value;
+ }
+
+ public NumericDataPoint(long timeStamp, int scheduleId, Double value) {
+ this.timeStamp = timeStamp;
+ this.scheduleId = scheduleId;
+ this.value = value;
+ }
+
+ @XmlAttribute
+ public long getTimeStamp() {
+ return timeStamp;
+ }
+
+ @XmlAttribute
+ public Double getValue() {
+ return value;
+ }
+
+ @XmlAttribute
+ public int getScheduleId() {
+ return scheduleId;
+ }
+
+ public void setScheduleId(int scheduleId) {
+ this.scheduleId = scheduleId;
+ }
+
+ public void setTimeStamp(long timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ public void setValue(Double value) {
+ this.value = value;
+ }
+}
commit 14b81e5036bbbc47bb09fac2dc86b7166b1846fd
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Sun Dec 25 11:42:47 2011 +0100
Initialize additionalProperties; give more debug output when assert fails.
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Operation.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Operation.java
index 0517ee1..23df1a5 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Operation.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Operation.java
@@ -47,10 +47,12 @@ public class Operation {
this.operation = operation;
this.address = new Address(addressKey,addressValue);
this._address = address.path;
+ additionalProperties = new HashMap<String, Object>();
}
public Operation(String operation, Address address) {
this.operation = operation;
+ additionalProperties = new HashMap<String, Object>();
if (address!=null && address.path!=null) {
this.address = address;
this._address = address.path;
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
index ef58967..11f823d 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
@@ -430,7 +430,7 @@ public class ConfigurationLoadingTest extends AbstractConfigurationHandlingTest
ConfigurationLoadDelegate delegate = new ConfigurationLoadDelegate(definition,connection,null);
Configuration config = delegate.loadResourceConfiguration();
assert config!=null;
- assert config.getProperties().size()==5 : "Got " + config.getProperties().size() + " props instead of 5";
+ assert config.getProperties().size()==5 : "Got " + config.getProperties().size() + " props instead of 5: " + config.getProperties().toString();
PropertySimple simple = config.getSimple("check-interval");
assert simple !=null;
Integer integerValue = simple.getIntegerValue();
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
index 354ab8d..67f2243 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/OperationJsonTest.java
@@ -59,7 +59,7 @@ public class OperationJsonTest {
assert op!=null;
assert op.getOperation()!=null : "op.operation was null!";
assert op.getOperation().equals(operation.getOperation()) : "Operation is " + op.getOperation();
- assert op.getName().equals("socket-binding") : "attribute name is " + op.getName();
+ assert op.getName().equals("socket-binding") : "attribute name is " + op.getName() + " and not 'socket-binding'";
assert op.getValue().equals("jndi") : "attribute value is " + op.getValue();
assert op.getAddress().size()==2 : "Address did not contain 2 parts, but " + op.getAddress().size();
commit 894c2ec182b75d50ab0238a3a211966e517f939b
Author: Simeon Pinder <spinder(a)redhat.com>
Date: Thu Dec 22 17:57:02 2011 -0500
[BZ 767734] conditionally disabling remaining tags references from Bundles.
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
index 5ac460c..bbc4175 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/deployment/BundleDeploymentView.java
@@ -124,7 +124,11 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
+ deployment.getDestination().getName(), LinkManager.getBundleDestinationLink(version.getBundle().getId(),
deployment.getDestination().getId())));
addMember(new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleDeployment_24.png"), deployment.getName()));
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
addMemberDeploymentsTable();
@@ -219,8 +223,8 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
// deployment represents content on the remote machines, showing purge only for live
// deployments makes sense).
if (deployment.isLive()) {
- IButton revertButton = new LocatableIButton(actionLayout.extendLocatorId("Revert"), MSG
- .view_bundle_revert());
+ IButton revertButton = new LocatableIButton(actionLayout.extendLocatorId("Revert"),
+ MSG.view_bundle_revert());
revertButton.setIcon("subsystems/bundle/BundleAction_Revert_16.png");
revertButton.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {
public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
@@ -252,8 +256,9 @@ public class BundleDeploymentView extends LocatableVLayout implements Bookmarkab
new Message(MSG.view_bundle_dest_purgeSuccessful(destinationName),
Message.Severity.Info));
// Bundle destination is purged, go back to bundle deployment view - it is not live anymore
- CoreGUI.goToView(LinkManager.getBundleDeploymentLink(bundle.getId(), deployment
- .getId()), true);
+ CoreGUI.goToView(
+ LinkManager.getBundleDeploymentLink(bundle.getId(), deployment.getId()),
+ true);
}
});
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
index 1e47427..d0966f2 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/destination/BundleDestinationView.java
@@ -101,7 +101,12 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka
addMember(backButton);
addMember(header);
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
+
addMember(createSummaryForm());
addMember(createDeploymentsTable());
addMember(detail);
@@ -223,8 +228,8 @@ public class BundleDestinationView extends LocatableVLayout implements Bookmarka
new Message(MSG.view_bundle_dest_purgeSuccessful(destination.getName()),
Message.Severity.Info));
// Bundle destination is purged, go back to bundle destination view
- CoreGUI.goToView(LinkManager.getBundleDestinationLink(bundle.getId(), destination
- .getId()), true);
+ CoreGUI.goToView(
+ LinkManager.getBundleDestinationLink(bundle.getId(), destination.getId()), true);
}
});
}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
index e8eabfa..7a39e5a 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/list/BundleView.java
@@ -108,7 +108,11 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
addMember(backButton);
addMember(headerLabel);
- addMember(createTagEditor());
+
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
addMember(tabs);
@@ -184,8 +188,8 @@ public class BundleView extends LocatableVLayout implements BookmarkableView {
StaticTextItem versionCountItem = new StaticTextItem("versionCount", MSG.view_bundle_list_versionsCount());
versionCountItem.setValue(bundle.getBundleVersions() != null ? bundle.getBundleVersions().size() : 0);
- StaticTextItem destinationsCountItem = new StaticTextItem("destinationsCount", MSG
- .view_bundle_list_destinationsCount());
+ StaticTextItem destinationsCountItem = new StaticTextItem("destinationsCount",
+ MSG.view_bundle_list_destinationsCount());
destinationsCountItem.setValue(bundle.getDestinations() != null ? bundle.getDestinations().size() : 0);
StaticTextItem descriptionItem = new StaticTextItem("description", MSG.common_title_description());
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
index 19116bb..5737a9c 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/BundleVersionView.java
@@ -93,7 +93,10 @@ public class BundleVersionView extends LocatableVLayout implements BookmarkableV
addMember(new HeaderLabel(Canvas.getImgURL("subsystems/bundle/BundleVersion_24.png"), version.getName() + ": "
+ version.getVersion()));
- addMember(createTagEditor());
+ //conditionally add tags. Defaults to true, not available in JON builds.
+ if (CoreGUI.isTagsEnabledForUI()) {
+ addMember(createTagEditor());
+ }
addMember(createSummaryForm());
@@ -268,16 +271,17 @@ public class BundleVersionView extends LocatableVLayout implements BookmarkableV
criteria.fetchConfigurationDefinition(true);
criteria.fetchTags(true);
- bundleManager.findBundleVersionsByCriteriaWithDestinationFilter(criteria, new AsyncCallback<PageList<BundleVersion>>() {
- public void onFailure(Throwable caught) {
- CoreGUI.getErrorHandler().handleError(MSG.view_bundle_version_loadFailure(), caught);
- }
+ bundleManager.findBundleVersionsByCriteriaWithDestinationFilter(criteria,
+ new AsyncCallback<PageList<BundleVersion>>() {
+ public void onFailure(Throwable caught) {
+ CoreGUI.getErrorHandler().handleError(MSG.view_bundle_version_loadFailure(), caught);
+ }
- public void onSuccess(PageList<BundleVersion> result) {
- BundleVersion version = result.get(0);
- ViewId nextPath = viewPath.next().getCurrent();
- viewBundleVersion(version, nextPath);
- }
- });
+ public void onSuccess(PageList<BundleVersion> result) {
+ BundleVersion version = result.get(0);
+ ViewId nextPath = viewPath.next().getCurrent();
+ viewBundleVersion(version, nextPath);
+ }
+ });
}
}
commit ca7c3763fd627f0c26a8f6cfd48f3e929f64e2be
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Thu Dec 22 15:58:36 2011 -0500
[BZ 759640] this also appears related to BZ 765670 - have the installer ping the startup servlet to know if the server is fully installed and ready
diff --git a/modules/enterprise/gui/installer-war/src/main/webapp/header.jsp b/modules/enterprise/gui/installer-war/src/main/webapp/header.jsp
index 673b018..7c04d9d 100644
--- a/modules/enterprise/gui/installer-war/src/main/webapp/header.jsp
+++ b/modules/enterprise/gui/installer-war/src/main/webapp/header.jsp
@@ -20,7 +20,7 @@
<c:if test="<%= new ServerInformation().isFullyDeployed() && request.getRequestURI().indexOf("installer/start") == -1 %>">
<script type="text/javascript" language="JavaScript">
- var startPage = '/Dashboard.do';
+ var startPage = '/startupstatus';
var xmlRequest = false;
function doLoad()
@@ -49,7 +49,7 @@
}
xmlRequest.onreadystatechange = processStateChange;
- xmlRequest.open('GET', startPage, true);
+ xmlRequest.open('HEAD', startPage, true);
xmlRequest.send(null);
}
diff --git a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
index bc3942a..3add80f 100644
--- a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
+++ b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
@@ -18,6 +18,7 @@
*/
package org.rhq.enterprise.gui.startup;
+import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Connection;
@@ -31,6 +32,8 @@ import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
@@ -44,7 +47,6 @@ import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.cloud.Server;
import org.rhq.core.domain.cloud.Server.OperationMode;
import org.rhq.core.domain.common.ProductInfo;
-import org.rhq.core.domain.common.ServerDetails;
import org.rhq.core.domain.configuration.PropertyDynamicType;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.gui.configuration.helper.PropertyRenderingUtility;
@@ -65,7 +67,17 @@ import org.rhq.enterprise.server.plugin.pc.MasterServerPluginContainer;
import org.rhq.enterprise.server.plugin.pc.ServerPluginServiceManagement;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
-import org.rhq.enterprise.server.scheduler.jobs.*;
+import org.rhq.enterprise.server.scheduler.jobs.AsyncResourceDeleteJob;
+import org.rhq.enterprise.server.scheduler.jobs.CheckForSuspectedAgentsJob;
+import org.rhq.enterprise.server.scheduler.jobs.CheckForTimedOutConfigUpdatesJob;
+import org.rhq.enterprise.server.scheduler.jobs.CheckForTimedOutContentRequestsJob;
+import org.rhq.enterprise.server.scheduler.jobs.CheckForTimedOutOperationsJob;
+import org.rhq.enterprise.server.scheduler.jobs.CloudManagerJob;
+import org.rhq.enterprise.server.scheduler.jobs.DataPurgeJob;
+import org.rhq.enterprise.server.scheduler.jobs.DynaGroupAutoRecalculationJob;
+import org.rhq.enterprise.server.scheduler.jobs.PurgePluginsJob;
+import org.rhq.enterprise.server.scheduler.jobs.PurgeResourceTypesJob;
+import org.rhq.enterprise.server.scheduler.jobs.SavedSearchResultCountRecalculationJob;
import org.rhq.enterprise.server.util.LookupUtil;
import org.rhq.enterprise.server.util.concurrent.AlertSerializer;
import org.rhq.enterprise.server.util.concurrent.AvailabilityReportSerializer;
@@ -73,6 +85,8 @@ import org.rhq.enterprise.server.util.concurrent.AvailabilityReportSerializer;
/**
* This servlet is ensured to be initialized after the rest of the RHQ Server has been deployed and started.
* Specifically, we know that at {@link #init()} time, all EJBs have been deployed and available.
+ *
+ * This also accepts requests and responds with information regarding the state of the startup.
*/
public class StartupServlet extends HttpServlet {
@@ -80,6 +94,20 @@ public class StartupServlet extends HttpServlet {
private Log log = LogFactory.getLog(this.getClass());
+ private boolean initialized = false;
+
+ /**
+ * This merely returns an HTTP status code to indicate the status of the startup.
+ * Under normal conditions, this will always return a 200 status code.
+ */
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setHeader("Cache-Control", "no-cache, no-store");
+ resp.setHeader("Expires", "-1");
+ resp.setHeader("Pragma", "no-cache");
+ resp.setStatus(initialized ? HttpServletResponse.SC_OK : HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ }
+
/**
* Performs the final RHQ Server initialization work that needs to talk place. EJBs are available in this method.
*
@@ -87,6 +115,8 @@ public class StartupServlet extends HttpServlet {
*/
@Override
public void init() throws ServletException {
+ initialized = false;
+
log.info("All business tier deployments are complete - finishing the startup...");
// As a security measure, make sure the installer has been undeployed
@@ -138,6 +168,7 @@ public class StartupServlet extends HttpServlet {
logServerStartedMessage();
+ initialized = true;
return;
}
@@ -339,8 +370,12 @@ public class StartupServlet extends HttpServlet {
try {
ServerCommunicationsServiceUtil.getService().startCommunicationServices();
- ServerCommunicationsServiceUtil.getService().getServiceContainer().addCommandListener(
- new ExternalizableStrategyCommandListener(org.rhq.core.server.ExternalizableStrategy.Subsystem.AGENT));
+ ServerCommunicationsServiceUtil
+ .getService()
+ .getServiceContainer()
+ .addCommandListener(
+ new ExternalizableStrategyCommandListener(
+ org.rhq.core.server.ExternalizableStrategy.Subsystem.AGENT));
} catch (Exception e) {
throw new ServletException("Cannot start the server-side communications services.", e);
}
@@ -574,19 +609,19 @@ public class StartupServlet extends HttpServlet {
Server server = LookupUtil.getServerManager().getServer();
if (agentAddress == null || agentAddress.trim().equals("")) {
- overrides.setProperty(ServiceContainerConfigurationConstants.CONNECTOR_BIND_ADDRESS, server
- .getAddress());
+ overrides.setProperty(ServiceContainerConfigurationConstants.CONNECTOR_BIND_ADDRESS,
+ server.getAddress());
}
if (serverAddress == null || serverAddress.trim().equals("")) {
overrides.setProperty(AgentConfigurationConstants_SERVER_BIND_ADDRESS, server.getAddress());
}
if (serverPort == null || serverPort.trim().equals("")) {
if (SecurityUtil.isTransportSecure(serverTransport)) {
- overrides.setProperty(AgentConfigurationConstants_SERVER_BIND_PORT, Integer.toString(server
- .getSecurePort()));
+ overrides.setProperty(AgentConfigurationConstants_SERVER_BIND_PORT,
+ Integer.toString(server.getSecurePort()));
} else {
- overrides.setProperty(AgentConfigurationConstants_SERVER_BIND_PORT, Integer.toString(server
- .getPort()));
+ overrides.setProperty(AgentConfigurationConstants_SERVER_BIND_PORT,
+ Integer.toString(server.getPort()));
}
}
@@ -684,7 +719,8 @@ public class StartupServlet extends HttpServlet {
Subject overlord = LookupUtil.getSubjectManager().getOverlord();
ProductInfo productInfo = LookupUtil.getSystemManager().getProductInfo(overlord);
log.info("--------------------------------------------------"); // 50 dashes
- log.info(productInfo.getFullName() + " " + productInfo.getVersion() + " (build " + productInfo.getBuildNumber() + ") Server started.");
+ log.info(productInfo.getFullName() + " " + productInfo.getVersion() + " (build " + productInfo.getBuildNumber()
+ + ") Server started.");
log.info("--------------------------------------------------"); // 50 dashes
}
diff --git a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/web.xml b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/web.xml
index 1beef97..7528dd9 100644
--- a/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/web.xml
+++ b/modules/enterprise/gui/portal-war/src/main/webapp/WEB-INF/web.xml
@@ -457,13 +457,18 @@
<url-pattern>/client/download</url-pattern>
</servlet-mapping>
+ <!-- provides startup progress information (mainly for the installer) -->
+ <servlet-mapping>
+ <servlet-name>initializer</servlet-name>
+ <url-pattern>/startupstatus</url-pattern>
+ </servlet-mapping>
+
+ <!-- TODO what is this for? -->
<servlet-mapping>
<servlet-name>sessionAccess</servlet-name>
<url-pattern>/sessionAccess</url-pattern>
</servlet-mapping>
-
-
<!-- The download servlet; this URI /downloads will effectively look like its pointing to rhq-downloads -->
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
commit 14141686e5d0c9cac395a13ceb52f2817287ce7b
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Thu Dec 22 15:31:49 2011 +0100
Jnp port is now detected from system properties rather than hardcoded.
jnpserver is declared as a provided dep.
diff --git a/modules/enterprise/server/container-lib/pom.xml b/modules/enterprise/server/container-lib/pom.xml
index 9d7d603..0974431 100644
--- a/modules/enterprise/server/container-lib/pom.xml
+++ b/modules/enterprise/server/container-lib/pom.xml
@@ -43,6 +43,7 @@
<groupId>jboss</groupId>
<artifactId>jnpserver</artifactId>
<version>4.2.2.GA</version>
+ <scope>provided</scope>
</dependency>
</dependencies>
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
index 1a9562a..e529347 100644
--- a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -77,7 +77,6 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
private static final String[] CHECKED_SCHEMES = { "java" };
private static final Set<InetAddress> SERVER_BIND_IPS;
-
static {
SERVER_BIND_IPS = new HashSet<InetAddress>();
@@ -98,10 +97,11 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
LOG.error("Could not obtain the list of local IPs", e);
} catch (UnknownHostException e) {
LOG.error("Failed to get the binding address of the RHQ server.", e);
- }
-
+ }
}
+ private static final int JNP_PORT = Integer.parseInt(System.getProperty("rhq.server.startup.namingservice.port", "2099"));
+
/**
* This is the default initial context factory that is returned when no other is
* configured using the environment variables.
@@ -159,10 +159,7 @@ public class AccessCheckingInitialContextFactoryBuilder implements InitialContex
//check if we are accessing the RHQ server through some remoting
//interface.
- //I just can't find where to read the magic number 1099 from.
- //it is defined in the jboss config files, but in the code
- //it seems hardcoded - see JDBCLoginModule.
- if (uri.getPort() == 1099 && SERVER_BIND_IPS.contains(providerHost)) {
+ if (uri.getPort() == JNP_PORT && SERVER_BIND_IPS.contains(providerHost)) {
return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
} else {
return new URLPreferringInitialContextFactoryDecorator(factory);
commit 41c87d1c7ed3f0719cee76067afb3e84c7644481
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Dec 21 21:29:45 2011 +0100
Fix compile errors.
diff --git a/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/AbstractIntegrationTest.java b/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/AbstractIntegrationTest.java
index fbf81b5..6714c40 100644
--- a/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/AbstractIntegrationTest.java
+++ b/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/AbstractIntegrationTest.java
@@ -57,9 +57,11 @@ import org.rhq.modules.plugins.jbossas7.json.PROPERTY_VALUE;
public abstract class AbstractIntegrationTest {
protected static final String DC_HOST = "localhost";
protected static final int DC_HTTP_PORT = 9990;
+ protected static final String DC_USER = "rhqadmin";
+ protected static final String DC_PASS = "rhqadmin";
String uploadToAs(String deploymentName) throws IOException {
- ASUploadConnection conn = new ASUploadConnection(DC_HOST, DC_HTTP_PORT);
+ ASUploadConnection conn = new ASUploadConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
OutputStream os = conn.getOutputStream(deploymentName);
@@ -92,7 +94,7 @@ public abstract class AbstractIntegrationTest {
}
ASConnection getASConnection() {
- ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT);
+ ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
return connection;
}
diff --git a/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/UploadAndDeployTest.java b/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/UploadAndDeployTest.java
index 9b35471..cc55f1c 100644
--- a/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/UploadAndDeployTest.java
+++ b/modules/integration-tests/jboss-as-7-plugin-test/src/test/java/org/rhq/modules/integrationTests/jbossas7plugin/UploadAndDeployTest.java
@@ -90,7 +90,7 @@ public class UploadAndDeployTest extends AbstractIntegrationTest {
System.out.println("sha: " + bytes_value);
System.out.println();
- ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT);
+ ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
Address deploymentsAddress = new Address("deployment", TEST_WAR);
Operation op = new Operation("add",deploymentsAddress);
@@ -168,7 +168,7 @@ public class UploadAndDeployTest extends AbstractIntegrationTest {
System.out.println("sha: " + bytes_value);
System.out.println();
- ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT);
+ ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
/*
Address deploymentsAddress = new Address();
@@ -275,7 +275,7 @@ public class UploadAndDeployTest extends AbstractIntegrationTest {
cop.addStep(step2a);
- ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT);
+ ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
JsonNode ret = connection.executeRaw(cop);
System.out.println(ret);
System.out.flush();
@@ -326,7 +326,7 @@ public class UploadAndDeployTest extends AbstractIntegrationTest {
cop.addStep(step1);
- ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT);
+ ASConnection connection = new ASConnection(DC_HOST, DC_HTTP_PORT,DC_USER,DC_PASS);
JsonNode ret = connection.executeRaw(cop);
System.out.println(ret);
System.out.flush();
commit 47086c02a2ed841262811c5a9ac1b92e22e7368d
Author: Mohamed Hamza Ben Mansour <>
Date: Wed Dec 21 18:19:37 2011 +0100
BZ 744262 - add resource lineage to SNMP traps.
diff --git a/modules/enterprise/server/container/src/main/resources/etc/RHQ-mib.txt b/modules/enterprise/server/container/src/main/resources/etc/RHQ-mib.txt
index 61fdb09..20bb110 100644
--- a/modules/enterprise/server/container/src/main/resources/etc/RHQ-mib.txt
+++ b/modules/enterprise/server/container/src/main/resources/etc/RHQ-mib.txt
@@ -11,14 +11,14 @@ IMPORTS
FROM SNMPv2-TC;
rhqMIB MODULE-IDENTITY
- LAST-UPDATED "201010180000Z"
+ LAST-UPDATED "201112200000Z"
ORGANIZATION "RHQ-Project"
CONTACT-INFO "http://www.rhq-project.org/"
DESCRIPTION
"The MIB module for RHQ alerts.
This file is part of the RHQ management platform
- Copyright (C) 2005-2010 Red Hat, Inc.
+ Copyright (C) 2005-2011 Red Hat, Inc.
All rights reserved.
"
@@ -26,6 +26,8 @@ rhqMIB MODULE-IDENTITY
DESCRIPTION "Initial version"
REVISION "201010180000Z"
DESCRIPTION "Better trap support"
+ REVISION "201112200000Z"
+ DESCRIPTION "Also emit resource lineage"
::= { snmpModules 1 }
jboss OBJECT IDENTIFIER ::= {enterprises 18016 }
@@ -85,6 +87,14 @@ alertUrl OBJECT-TYPE
"The url of the individual alert"
::= { alert 6 }
+alertHierarchy OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..1024))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The hierarchy of the resource that triggered the alert"
+ ::= { alert 6 }
+
-- conformance information
snmpMIBConformance
@@ -110,7 +120,8 @@ alertGroup OBJECT-GROUP
alertPlatformName,
alertCondition,
alertSeverity,
- alertUrl }
+ alertUrl,
+ alertHierarchy }
STATUS current
DESCRIPTION "A collection of objects providing information about an alert"
::= { snmpMIBGroups 1 }
diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceManagerBeanTest.java
index 664be6d..3e753f0 100644
--- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceManagerBeanTest.java
+++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/resource/test/ResourceManagerBeanTest.java
@@ -22,6 +22,8 @@ import java.util.List;
import java.util.Random;
import javax.persistence.EntityManager;
+import javax.transaction.NotSupportedException;
+import javax.transaction.SystemException;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
@@ -110,6 +112,95 @@ public class ResourceManagerBeanTest extends UpdatePluginMetadataTestBase {
assert errors.size() == 0;
}
+
+ public void testResourceLineage() throws Exception {
+ // given a resource id for the leaf resource in a resource hierachy
+ int leafResourceId = givenASampleResourceHierarchy();
+
+ // when
+ List<Resource> resourceLineage = resourceManager.getResourceLineage(leafResourceId);
+
+ // then
+ StringBuilder stringBuilder = new StringBuilder();
+ for (Resource resource : resourceLineage) {
+ stringBuilder.append(resource.getName());
+ if (resourceLineage.indexOf(resource) != resourceLineage.size() - 1) {
+ stringBuilder.append("::");
+ }
+ }
+ System.err.println(stringBuilder.toString());
+
+ }
+
+ private int givenASampleResourceHierarchy() throws NotSupportedException,
+ SystemException {
+ getTransactionManager().begin();
+ EntityManager em = getEntityManager();
+ int leafResoureId = 0;
+ try {
+ ResourceType platformType = createResourceType(em, "platform"
+ + System.currentTimeMillis(), "test", null,
+ ResourceCategory.PLATFORM);
+ ResourceType appserverType = createResourceType(em, "jboss AS 5"
+ + System.currentTimeMillis(), "jbossas5", platformType,
+ ResourceCategory.SERVER);
+ ResourceType jvmType = createResourceType(em,
+ "JVM" + System.currentTimeMillis(), "jbossas5",
+ appserverType, ResourceCategory.SERVICE);
+ ResourceType memType = createResourceType(em, "Memory Subsystem"
+ + System.currentTimeMillis(), "jbossas5", jvmType,
+ ResourceCategory.SERVICE);
+ Agent agent = new Agent("hamza007", "hamzahost", 1, "", "hamzatoken");
+ em.persist(agent);
+ em.flush();
+
+ Resource platform = createResource(em, platformType, agent,
+ "platformKey" + System.currentTimeMillis(),
+ "host.dev.corp", null);
+ Resource appserver = createResource(em, appserverType, agent,
+ "JEAP" + System.currentTimeMillis(), "JBOSS EAP 5.1.1",
+ platform);
+ Resource jvm = createResource(em, memType, agent, "jvm"
+ + System.currentTimeMillis(), "JBoss AS JVM", appserver);
+ Resource memSubystem = createResource(em, appserverType, agent,
+ "mem" + System.currentTimeMillis(), "Memory Subsystem", jvm);
+ leafResoureId = memSubystem.getId();
+ getTransactionManager().commit();
+ } catch (Exception e) {
+ try {
+ System.out.println("CANNOT Prepare TEST: Cause: " + e);
+ getTransactionManager().rollback();
+ } catch (Exception ignore) {
+ }
+ } finally {
+ em.close();
+ }
+ return leafResoureId;
+ }
+
+ private Resource createResource(EntityManager em, ResourceType platformType,
+ Agent agent, String resourceKey, String resourceName,
+ Resource parent) {
+ Resource resource = new Resource(resourceKey, resourceName, platformType);
+ resource.setUuid("" + new Random().nextInt());
+ resource.setAgent(agent);
+ resource.setParentResource(parent);
+ em.persist(resource);
+ return resource;
+ }
+
+
+ private ResourceType createResourceType(EntityManager em, String name,
+ String pluginName, ResourceType parentResourceType,
+ ResourceCategory resourceCategory) {
+ ResourceType platformType = new ResourceType(name, pluginName,
+ resourceCategory, parentResourceType);
+ ResourceType resourceType = platformType;
+ em.persist(resourceType);
+ return resourceType;
+ }
+
+
private Resource createNewResourceWithNewType() throws Exception {
getTransactionManager().begin();
EntityManager em = getEntityManager();
@@ -173,4 +264,4 @@ public class ResourceManagerBeanTest extends UpdatePluginMetadataTestBase {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpSender.java b/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpSender.java
index 627e23d..1ea5e0b 100644
--- a/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpSender.java
+++ b/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpSender.java
@@ -60,16 +60,30 @@ public class SnmpSender extends AlertSender {
String platformName = lineage.get(0).getName();
String conditions = alertManager.prettyPrintAlertConditions(alert, false);
String alertUrl = alertManager.prettyPrintAlertURL(alert);
+
+
+ String hierarchy = getResourceHierarchyAsString(lineage);
Date bootTime = new Date(); // TODO: want to use LookupUtil.getCoreServer().getBootTime() but ServiceMBean is not visible
String result = snmpTrapSender.sendSnmpTrap(alert, alertParameters, platformName, conditions, bootTime,
- alertUrl);
+ alertUrl, hierarchy);
return SenderResult.getSimpleSuccess(result);
} catch (Throwable t) {
return SenderResult.getSimpleFailure("failed - cause: " + t);
}
}
+ private String getResourceHierarchyAsString(List<Resource> lineage) {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (Resource resource : lineage) {
+ stringBuilder.append(resource.getName());
+ if (lineage.indexOf(resource) != lineage.size() - 1) {
+ stringBuilder.append("::");
+ }
+ }
+ return stringBuilder.toString();
+ }
+
@Override
public String previewConfiguration() {
SnmpInfo info = SnmpInfo.load(alertParameters);
diff --git a/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpTrapSender.java b/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpTrapSender.java
index ba4bf84..53bfd85 100644
--- a/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpTrapSender.java
+++ b/modules/enterprise/server/plugins/alert-snmp/src/main/java/org/rhq/enterprise/server/plugins/alertSnmp/SnmpTrapSender.java
@@ -464,7 +464,7 @@ public class SnmpTrapSender implements PDUFactory {
* @return 'Error code' of the operation
*/
public String sendSnmpTrap(Alert alert, Configuration alertParameters, String platformName, String conditions,
- Date bootTime, String alertUrl) {
+ Date bootTime, String alertUrl, String hierarchy) {
if (!this.snmpEnabled) {
return "SNMP is not enabled.";
}
@@ -486,6 +486,8 @@ public class SnmpTrapSender implements PDUFactory {
getVariableBindings(baseOid + ".5" + "={s}" + alert.getAlertDefinition().getPriority().toString().toLowerCase());
// url of the alert detail
getVariableBindings(baseOid + ".6" + "={s}" + alertUrl);
+ // hierarchy of the resource on alert
+ getVariableBindings(baseOid + ".7" + "={s}" + hierarchy);
setSysUpTimeFromBootTime(bootTime); // needs to be called before checkTrapVariables();
checkTrapVariables(this.vbs);
commit 470dc5a6f40012d3632fef4f07c3b3c6f5951016
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Dec 21 12:10:54 2011 +0100
Add tests for child:key=value groups in config. Also update Jackson.
diff --git a/modules/plugins/jboss-as-7/pom.xml b/modules/plugins/jboss-as-7/pom.xml
index 8220355..f39c296 100644
--- a/modules/plugins/jboss-as-7/pom.xml
+++ b/modules/plugins/jboss-as-7/pom.xml
@@ -16,7 +16,7 @@
<properties>
<json.version>${project.json.version}</json.version>
- <jackson.version>1.7.4</jackson.version>
+ <jackson.version>1.9.3</jackson.version>
<jboss.sasl.version>1.0.0.Beta9</jboss.sasl.version>
</properties>
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 ee6b902..7e88906 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
@@ -765,7 +765,7 @@
<c:simple-property name="mapped-file" required="false" type="boolean" defaultValue="true"
description="Map to the JSP source."/>
<c:simple-property name="check-interval" required="false" type="integer" defaultValue="60"
- description="Check interval for JSP updates using a background thread."/> <!-- TODO revisit default when https://issues.jboss.org/browse/AS7-3098 is fixed -->
+ description="Check interval in seconds for JSP updates using a background thread."/> <!-- TODO revisit default when https://issues.jboss.org/browse/AS7-3098 is fixed -->
<c:simple-property name="modification-test-interval" required="false" type="integer" defaultValue="4"
description="Minimum amount of time between two tests for updates, in seconds."/>
<c:simple-property name="recompile-on-fail" required="false" type="boolean" defaultValue="false"
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 0266071..e1627e3 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
@@ -28,6 +28,8 @@ 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.map.ObjectMapper;
+import org.codehaus.jackson.node.ObjectNode;
import org.rhq.core.clientapi.agent.metadata.ConfigurationMetadataParser;
import org.rhq.core.clientapi.agent.metadata.InvalidPluginDescriptorException;
@@ -35,6 +37,7 @@ import org.rhq.core.clientapi.descriptor.DescriptorPackages;
import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ServerDescriptor;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.Operation;
/**
@@ -107,6 +110,30 @@ public class AbstractConfigurationHandlingTest {
public JsonNode executeRaw(Operation operation) {
if (content==null)
throw new IllegalStateException("Content not yet set");
+
+ Address address = operation.getAddress();
+ if (address!=null && !address.isEmpty()) {
+ // we need to clone the content and then for the result find the right sub-content to put into result and
+ // return this one.
+
+ // find the sub-content we want
+ String[] parts = address.getPath().split("=");
+ String key = parts[0];
+ String val = parts[1];
+ JsonNode result = content.get("result");
+ JsonNode keyNode = result.get(key);
+ JsonNode valNode = keyNode.get(val);
+
+ // clone the original content
+ ObjectMapper tmpMapper = new ObjectMapper();
+ JsonNode tmp = tmpMapper.createObjectNode();
+ ((ObjectNode)tmp).putAll(((ObjectNode)content));
+
+ // replace the result with the sub-content
+ ((ObjectNode)tmp).put("result",valNode);
+
+ return tmp;
+ }
return content;
}
}
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
index 0a46516..ef58967 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadingTest.java
@@ -416,6 +416,51 @@ public class ConfigurationLoadingTest extends AbstractConfigurationHandlingTest
}
+ public void test9() throws Exception {
+ String resultString = loadJsonFromFile("web.json");
+ ConfigurationDefinition definition = loadDescriptor("test9");
+
+ ObjectMapper mapper = new ObjectMapper();
+ ComplexResult result = mapper.readValue(resultString,ComplexResult.class);
+ JsonNode json = mapper.valueToTree(result);
+
+ FakeConnection connection = new FakeConnection();
+ connection.setContent(json);
+
+ ConfigurationLoadDelegate delegate = new ConfigurationLoadDelegate(definition,connection,null);
+ Configuration config = delegate.loadResourceConfiguration();
+ assert config!=null;
+ assert config.getProperties().size()==5 : "Got " + config.getProperties().size() + " props instead of 5";
+ PropertySimple simple = config.getSimple("check-interval");
+ assert simple !=null;
+ Integer integerValue = simple.getIntegerValue();
+ assert integerValue !=null : "check-interval was null";
+ assert integerValue ==17 : "check-interval was not 17 but " + integerValue;
+ PropertySimple disabled = config.getSimple("disabled");
+ assert disabled !=null : "disabled was null";
+ Boolean booleanValue = disabled.getBooleanValue();
+ assert booleanValue !=null;
+ assert booleanValue;
+ PropertySimple listings = config.getSimple("listings");
+ assert listings !=null;
+ Boolean booleanValue1 = listings.getBooleanValue();
+ assert booleanValue1 !=null;
+ assert !booleanValue1;
+ PropertySimple simple1 = config.getSimple("max-depth");
+ assert simple1 !=null;
+ Integer integerValue1 = simple1.getIntegerValue();
+ assert integerValue1 !=null;
+ assert integerValue1 ==3;
+ PropertySimple simple2 = config.getSimple("default-virtual-server");
+ assert simple2 !=null;
+ String stringValue = simple2.getStringValue();
+ assert stringValue !=null;
+ assert stringValue.equals("default-host");
+
+
+
+ }
+
private String loadJsonFromFile(String fileName) throws Exception {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
index a512133..09439f3 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
@@ -31,6 +31,7 @@ import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+import org.rhq.modules.plugins.jbossas7.json.Address;
import org.rhq.modules.plugins.jbossas7.json.CompositeOperation;
import org.rhq.modules.plugins.jbossas7.json.Operation;
@@ -62,7 +63,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(new PropertySimple("needed","test"));
conf.put(new PropertySimple("optional",null));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1;
Operation step1 = cop.step(0);
@@ -89,7 +90,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -120,7 +121,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -148,7 +149,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -176,7 +177,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -207,7 +208,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -240,7 +241,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
conf.put(new PropertySimple("port-offset",0));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 3 : "#Steps should be 3 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -289,7 +290,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
conf.put(new PropertySimple("port-offset",0));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
assert cop.numberOfSteps() == 5 : "#Steps should be 5 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -317,4 +318,48 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
assert step4.getAddress().get(0).equals("socket-binding=https");
assert step5.getAddress().get(0).equals("socket-binding=https");
}
+
+ public void test9() throws Exception {
+
+ ConfigurationDefinition definition = loadDescriptor("test9");
+
+ FakeConnection connection = new FakeConnection();
+
+ ConfigurationWriteDelegate delegate = new ConfigurationWriteDelegate(definition,connection,null);
+
+ Configuration conf = new Configuration();
+
+ conf.put(new PropertySimple("default-virtual-server","hulla")); // this is read-only and must not show up in result
+ conf.put(new PropertySimple("test-prop","Heiko"));
+ conf.put(new PropertySimple("check-interval",23));
+ conf.put(new PropertySimple("disabled",true));
+ conf.put(new PropertySimple("listings",false));
+ conf.put(new PropertySimple("max-depth",17));
+
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, new Address());
+
+ assert cop.numberOfSteps() == 5 : "#Steps should be 5 but were " + cop.numberOfSteps();
+
+ Operation step1 = cop.step(0);
+ Operation step2 = cop.step(1);
+ Operation step3 = cop.step(2);
+ Operation step4 = cop.step(3);
+ Operation step5 = cop.step(4);
+
+ assert step1.getAddress().isEmpty();
+ assert step2.getAddress().size()==1;
+ assert step3.getAddress().size()==1;
+ assert step4.getAddress().size()==1;
+ assert step5.getAddress().size()==1;
+ assert step2.getAddress().get(0).equals("configuration=jsp-configuration");
+ assert step3.getAddress().get(0).equals("configuration=jsp-configuration");
+ assert step4.getAddress().get(0).equals("configuration=static-resources");
+ assert step5.getAddress().get(0).equals("configuration=static-resources");
+
+ assert step1.getAdditionalProperties().get("name").equals("test-prop");
+ assert step1.getAdditionalProperties().get("value").equals("Heiko");
+ assert step2.getAdditionalProperties().get("name").equals("check-interval");
+ assert step2.getAdditionalProperties().get("value").equals("23");
+
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml b/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
index 69201e2..53f351a 100644
--- a/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
+++ b/modules/plugins/jboss-as-7/src/test/resources/test-plugin.xml
@@ -89,6 +89,21 @@
</server>
+ <server class="foo" discovery="foo" name="test9">
+ <resource-configuration>
+ <c:simple-property name="default-virtual-server" type="string" readOnly="true"/>
+ <c:simple-property name="test-prop" type="string" required="true" defaultValue="Hello"/>
+ <c:group name="child:configuration=jsp-configuration">
+ <c:simple-property name="check-interval" type="integer" units="seconds" readOnly="false" default="1"/>
+ <c:simple-property name="disabled" type="boolean" default="false"/>
+ </c:group>
+ <c:group name="child:configuration=static-resources">
+ <c:simple-property name="listings" default="true" type="boolean"/>
+ <c:simple-property name="max-depth" default="9" type="integer" />
+ </c:group>
+ </resource-configuration>
+ </server>
+
<server class="foo" discovery="foo" name="simple1">
<resource-configuration>
diff --git a/modules/plugins/jboss-as-7/src/test/resources/web.json b/modules/plugins/jboss-as-7/src/test/resources/web.json
new file mode 100644
index 0000000..96f0565
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/web.json
@@ -0,0 +1,62 @@
+{
+ "outcome" : "success",
+ "result" :
+
+
+ {"default-virtual-server" : "default-host",
+ "native" : true,
+ "configuration" : {
+ "container" : {},
+ "static-resources" : {
+ "disabled" : false,
+ "listings" : false,
+ "max-depth" : 3,
+ "read-only" : true,
+ "sendfile" : 49152,
+ "webdav" : false},
+ "jsp-configuration" : {
+ "check-interval" : 17,
+ "development" : false,
+ "disabled" : true,
+ "display-source-fragment" : true,
+ "dump-smap" : false,
+ "error-on-use-bean-invalid-class-attribute" : false,
+ "generate-strings-as-char-arrays" : false,
+ "java-encoding" : "UTF-8",
+ "keep-generated" : true,
+ "mapped-file" : true,
+ "modification-test-interval" : "7",
+ "recompile-on-fail" : false,
+ "smap" : false,
+ "source-vm" : "1.5",
+ "tag-pooling" : true,
+ "target-vm" : "1.5",
+ "trim-spaces" : true,
+ "x-powered-by" : true}
+ },
+ "connector" : {
+ "http" : {
+ "enable-lookups" : true,
+ "enabled" : true,
+ "max-post-size" : 2097152,
+ "max-save-post-size" : 4096,
+ "protocol" : "HTTP/1.1",
+ "redirect-port" : 8443,
+ "scheme" : "http",
+ "secure" : false,
+ "socket-binding" : "http",
+ "ssl" : null,
+ "virtual-server" : null}
+ },
+
+ "virtual-server" : {
+ "default-host" : {
+ "access-log" : null,
+ "alias" : ["localhost","example.com"],
+ "default-web-module" : "ROOT.war",
+ "enable-welcome-root" : true,
+ "rewrite" : null,
+ "sso" : null}
+ }
+ }
+}
commit 74fe0df63135344a74cf0f58edf6f22a5c6c9124
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Dec 20 17:28:21 2011 -0500
[BZ 766574] for some reason, the remote interface was removed from the discovery SLSB. put it back.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
index fcb2f9e..2ea6234 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/discovery/DiscoveryBossBean.java
@@ -99,7 +99,7 @@ import org.rhq.enterprise.server.util.LookupUtil;
* @author Greg Hinkle
*/
@Stateless
-public class DiscoveryBossBean implements DiscoveryBossLocal {
+public class DiscoveryBossBean implements DiscoveryBossLocal, DiscoveryBossRemote {
private final Log log = LogFactory.getLog(DiscoveryBossBean.class.getName());
commit a638398ba148f419eba537b5851dac8955dad482
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Tue Dec 20 14:40:53 2011 -0500
[BZ 766574] fix NPE if there is no availability yet
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
index 6ead45c..94a4d05 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/output/TabularWriter.java
@@ -44,6 +44,7 @@ import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.domain.measurement.AvailabilityType;
import org.rhq.core.domain.measurement.ResourceAvailability;
import org.rhq.core.domain.resource.ResourceType;
@@ -715,7 +716,8 @@ public class TabularWriter {
} else if (object instanceof ResourceType) {
return ((ResourceType) object).getName();
} else if (object instanceof ResourceAvailability) {
- return ((ResourceAvailability) object).getAvailabilityType().getName();
+ AvailabilityType availType = ((ResourceAvailability) object).getAvailabilityType();
+ return (availType == null) ? "?" : availType.getName();
} else if (object != null && object.getClass().isArray()) {
return Arrays.toString((Object[]) object);
} else {
commit 19097edb5d591dae5ae6fdf7565b682cd5b1506c
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Fri Nov 18 15:23:26 2011 +0100
Several improvements to the AS7 plugin:
* BZ 754858 - in as7.1 the management port is now determined via socket binding reference. Also allow discover older versions.
The xml parsing code has been rewritten to use XPath expressions.
* BZ 754849 supply authentication to the remote. The JVM calls back to the AS7 Authenticator when needed.
* Prevent a NPE in the case we get no results.
* Add an operation to install a management user.
* BZ 709678 - update jboss web to latest code and enable updating of properties.
* Allow to merge in new/changed properties instead of requiring to supply the whole configuration in the standalone container.
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
index 10b1b1b..07e2965 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/StandaloneContainer.java
@@ -21,7 +21,6 @@ package org.rhq.core.pc;
import java.io.*;
import java.util.ArrayList;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -31,6 +30,7 @@ import java.util.Stack;
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.configuration.ConfigurationUpdateRequest;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.PropertyDefinition;
@@ -75,8 +75,6 @@ public class StandaloneContainer {
InventoryManager inventoryManager;
/** Global operation counter */
Integer opId = 0;
- /** Map of resource plugin configurations */
- Map<Integer, Configuration> resConfigMap = new HashMap<Integer, Configuration>();
/** variable set by find() and which can be used in set() */
int dollarR = 0;
/** Do we read from stdin ? */
@@ -340,32 +338,58 @@ public class StandaloneContainer {
}
- private void setResourcePluginConfig(String[] tokens,boolean pluginConfig) {
+ private void setResourcePluginConfig(String[] tokens,boolean isPluginConfig) throws PluginContainerException {
if (resourceId == 0) {
System.err.println("No resource set");
return;
}
+ Configuration newConfig = null;
Configuration config = null;
- if (tokens.length > 1)
- config = createConfigurationFromString(tokens[1]);
- else {
+ boolean merge=false;
+ int pos = 1;
+ if (tokens.length < 2) {
+ System.err.println("Need at least 1 token");
+ return;
+ }
+ if (tokens[1].equals("-m")) {
+ merge = true;
+ pos++;
+ }
+ if (tokens.length < pos+1) {
System.err.println("Need at least 1 token");
return;
}
- ConfigurationUpdateRequest request = new ConfigurationUpdateRequest(1,config,resourceId);
+ newConfig = createConfigurationFromString(tokens[pos]);
ConfigurationManager cm = pc.getConfigurationManager();
- if (pluginConfig) {
- pc.getInventoryManager().getResourceContainer(resourceId).getResource().setPluginConfiguration(config);
- } else
- cm.updateResourceConfiguration(request);
-
-
+ if (isPluginConfig) {
+ Resource targetResource = pc.getInventoryManager().getResourceContainer(resourceId).getResource();
+ config = targetResource.getPluginConfiguration();
+ if (merge) {
+ // copy over existing properties that are not in newConfig
+ for (Property p : config.getProperties()) {
+ if (newConfig.get(p.getName())==null)
+ newConfig.put(p);
+ }
+ }
+ targetResource.setPluginConfiguration(newConfig);
+ } else {
+ config = pc.getConfigurationManager().loadResourceConfiguration(resourceId);
+ if (merge) {
+ // copy over existing properties that are not in newConfig
+ for (Property p : config.getProperties()) {
+ if (newConfig.get(p.getName())==null)
+ newConfig.put(p);
+ }
+ }
+ ConfigurationUpdateRequest request = new ConfigurationUpdateRequest(1,newConfig,resourceId);
+ cm.updateResourceConfiguration(request);
+ }
}
@@ -715,7 +739,7 @@ public class StandaloneContainer {
}
private void showConfig(Configuration config) {
- System.out.println(config.getProperties());
+ System.out.println(config.getProperties()); // TODO convert to input format or key=value or json
}
}
diff --git a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/standaloneContainer/Command.java b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/standaloneContainer/Command.java
index c992000..0f1d01d 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/standaloneContainer/Command.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/standaloneContainer/Command.java
@@ -47,8 +47,8 @@ public enum Command {
WAIT("w", "milliseconds", 1, "Waits the given amount of time"),
P_CONFIG("pc", "", 0, "Shows the plugin configuration of the current resource."),
R_CONFIG("rc", "", 0, "Shows the resource configuration of the current resource."),
- SR_CONFIG("rcs", "", 0, "[parameters] set resource config "),
- SP_CONFIG("pcs", "", 0, "[parameters] set plugin config ")
+ SR_CONFIG("rcs", "", 1, "[-m] [parameters] set resource config. '-m' merges with current config; default is overwrite."),
+ SP_CONFIG("pcs", "", 1, "[-m] [parameters] set plugin config.'-m' merges with current config; default is overwrite.")
;
private String abbrev;
diff --git a/modules/plugins/jboss-as-7/d2d.sh b/modules/plugins/jboss-as-7/d2d.sh
index 16c1e57..d36d8e9 100755
--- a/modules/plugins/jboss-as-7/d2d.sh
+++ b/modules/plugins/jboss-as-7/d2d.sh
@@ -1,2 +1,2 @@
#!/bin/sh
-java -cp target/rhq-jboss-as-7-plugin-4.1.0-SNAPSHOT.jar:/im/rhq/modules/enterprise/agent/target/rhq-agent/lib/commons-logging-1.1.0.jboss.jar:/Users/hrupp/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.7.4/jackson-core-asl-1.7.4.jar:/Users/hrupp/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.7.4/jackson-mapper-asl-1.7.4.jar org.rhq.modules.plugins.jbossas7.Domain2Descriptor $*
+java -cp target/rhq-jboss-as-7-plugin-4.3.0-SNAPSHOT.jar:/im/rhq/modules/enterprise/agent/target/rhq-agent/lib/commons-logging-1.1.0.jboss.jar:/Users/hrupp/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.7.4/jackson-core-asl-1.7.4.jar:/Users/hrupp/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.7.4/jackson-mapper-asl-1.7.4.jar org.rhq.modules.plugins.jbossas7.Domain2Descriptor $*
diff --git a/modules/plugins/jboss-as-7/pom.xml b/modules/plugins/jboss-as-7/pom.xml
index e069be3..8220355 100644
--- a/modules/plugins/jboss-as-7/pom.xml
+++ b/modules/plugins/jboss-as-7/pom.xml
@@ -17,6 +17,7 @@
<properties>
<json.version>${project.json.version}</json.version>
<jackson.version>1.7.4</jackson.version>
+ <jboss.sasl.version>1.0.0.Beta9</jboss.sasl.version>
</properties>
<build>
@@ -49,6 +50,11 @@
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
</artifactItem>
+ <artifactItem>
+ <groupId>org.jboss.sasl</groupId>
+ <artifactId>jboss-sasl</artifactId>
+ <version>${jboss.sasl.version}</version>
+ </artifactItem>
</artifactItems>
<outputDirectory>${project.build.outputDirectory}/lib</outputDirectory>
@@ -76,7 +82,7 @@
<plugins>
<plugin>
- <artifactId>maven-antrun-plugin</artifactId>
+ <artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
@@ -204,6 +210,13 @@
<scope>provided</scope>
</dependency>
+ <!-- for the password hashing - we may want to copy the relevant stuff over ourselves -->
+ <dependency>
+ <groupId>org.jboss.sasl</groupId>
+ <artifactId>jboss-sasl</artifactId>
+ <version>${jboss.sasl.version}</version>
+ </dependency>
+
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7Authenticator.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7Authenticator.java
new file mode 100644
index 0000000..703e177
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AS7Authenticator.java
@@ -0,0 +1,26 @@
+package org.rhq.modules.plugins.jbossas7;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+
+/**
+ * Authenticator to authenticate against as7
+ * @author Heiko W. Rupp
+ */
+public class AS7Authenticator extends Authenticator {
+
+ private String user;
+ private String pass;
+
+ public AS7Authenticator(String user, String pass) {
+ this.user = user;
+ this.pass = pass;
+ if (this.pass==null)
+ this.pass=""; // prevent NPE later
+ }
+
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(user,pass.toCharArray());
+ }
+}
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 40561a0..cf0b5b9 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
@@ -23,15 +23,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
@@ -51,15 +50,17 @@ public class ASConnection {
String urlString;
private ObjectMapper mapper;
public static boolean verbose = false; // This is a variable on purpose, so devs can switch it on in the debugger or in the agent
- private HttpURLConnection conn;
+ Authenticator passwordAuthenticator ;
/**
* Construct an ASConnection object. The real "physical" connection is done in
* #executeRaw.
* @param host Host of the DomainController or standalone server
* @param port Port of the JSON api.
+ * @param user user needed for authentication
+ * @param password password needed for authentication
*/
- public ASConnection(String host, int port) {
+ public ASConnection(String host, int port, String user, String password) {
try {
url = new URL("http", host, port, MANAGEMENT);
@@ -69,6 +70,9 @@ public class ASConnection {
throw new IllegalArgumentException(e.getMessage());
}
+ passwordAuthenticator = new AS7Authenticator(user,password);
+ Authenticator.setDefault(passwordAuthenticator);
+
// read system property "as7plugin.verbose"
verbose = Boolean.getBoolean("as7plugin.verbose");
@@ -92,14 +96,15 @@ public class ASConnection {
InputStream inputStream = null;
BufferedReader br = null;
InputStream es = null;
+ HttpURLConnection conn=null;
long t1 = System.currentTimeMillis();
try {
-
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
- conn.addRequestProperty("Content-Type","application/json");
+ conn.addRequestProperty("Content-Type", "application/json");
conn.addRequestProperty("Accept","application/json");
+
OutputStream out = conn.getOutputStream();
String result = mapper.writeValueAsString(operation);
@@ -236,6 +241,7 @@ public class ASConnection {
if (node==null) {
log.warn("Operation [" + op + "] returned null");
+ return null;
}
try {
Result res;
@@ -250,22 +256,5 @@ public class ASConnection {
}
}
- public void writeValue(OutputStream out, Object value) throws IOException, JsonGenerationException,
- JsonMappingException {
- // JsonGenerator jgen = _jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8);
- // JsonGenerator jgen = mapper.createJsonGenerator(out, JsonEncoding.UTF8);
- // JsonGenerator jgen = new Js
- // boolean closed = false;
- // try {
- // writeValue(jgen, value);
- // closed = true;
- // jgen.close();
- // } finally {
- // if (!closed) {
- // jgen.close();
- // }
- // }
-
- }
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
index d17a311..a5b8bdd 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ASUploadConnection.java
@@ -26,6 +26,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -55,15 +56,18 @@ public class ASUploadConnection {
private static final Log log = LogFactory.getLog(ASUploadConnection.class);
+ Authenticator passwordAuthenticator ;
BufferedOutputStream os = null;
InputStream is = null;
private HttpURLConnection connection;
private String host;
private int port;
- public ASUploadConnection(String dcHost, int port) {
+ public ASUploadConnection(String dcHost, int port, String user, String password) {
this.host = dcHost;
this.port = port;
+ passwordAuthenticator = new AS7Authenticator(user,password);
+ Authenticator.setDefault(passwordAuthenticator);
}
public OutputStream getOutputStream(String fileName) {
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
index 8736495..78b1543 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/AbstractBaseDiscovery.java
@@ -24,15 +24,16 @@ import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.rhq.core.pluginapi.inventory.ResourceComponent;
-import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
import org.rhq.core.system.ProcessInfo;
/**
@@ -40,14 +41,24 @@ import org.rhq.core.system.ProcessInfo;
* in the area of processes and host.xml
* @author Heiko W. Rupp
*/
-public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> implements ResourceDiscoveryComponent<T> {
+public class AbstractBaseDiscovery {
static final String DORG_JBOSS_BOOT_LOG_FILE = "-Dorg.jboss.boot.log.file=";
private static final String DJBOSS_SERVER_HOME_DIR = "-Djboss.home.dir";
static final int DEFAULT_MGMT_PORT = 9990;
private static final String JBOSS_AS_PREFIX = "jboss-as-";
+ static final String CALL_READ_STANDALONE_OR_HOST_XML_FIRST = "hostXml is null. You need to call 'readStandaloneOrHostXml' first.";
protected Document hostXml;
protected final Log log = LogFactory.getLog(this.getClass());
private static final String JBOSS_EAP_PREFIX = "jboss-eap-";
+ private XPathFactory factory;
+
+
+
+ protected AbstractBaseDiscovery() {
+ synchronized (this) {
+ factory = XPathFactory.newInstance();
+ }
+ }
/**
* Read the host.xml or standalone.xml file depending on isDomainMode. If isDomainMode is true,
@@ -58,6 +69,10 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
*/
protected void readStandaloneOrHostXml(ProcessInfo processInfo, boolean isDomainMode) {
String hostXmlFile = getHostXmlFileLocation(processInfo,isDomainMode);
+ readStandaloneOrHostXmlFromFile(hostXmlFile);
+ }
+
+ protected void readStandaloneOrHostXmlFromFile(String hostXmlFile) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
@@ -107,99 +122,50 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
*/
protected HostPort getManagementPortFromHostXml(String[] commandLine) {
if (hostXml==null)
- throw new IllegalArgumentException("hostXml is null. You need to call 'readStandaloneOrHostXml' first.");
- Element host = hostXml.getDocumentElement();
- NodeList interfaceParent = host.getElementsByTagName("management-interfaces");
- if (interfaceParent ==null || interfaceParent.getLength()==0) {
- log.warn("No <management-interfaces> found in host.xml");
- return new HostPort();
- }
- NodeList mgmtInterfaces = interfaceParent.item(0).getChildNodes();
- if (mgmtInterfaces==null || mgmtInterfaces.getLength()==0) {
- log.warn("No <*-interface> found in host.xml");
- return new HostPort();
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
+
+ String portString;
+ String interfaceExpession;
+
+ String socketBindingName = obtainXmlPropertyViaXPath(
+ "//management/management-interfaces/http-interface/socket-binding/@http");
+ if (socketBindingName==null || socketBindingName.isEmpty()) {
+ // old AS7.0, early 7.1 style
+ portString = obtainXmlPropertyViaXPath("//management/management-interfaces/http-interface/@port");
+ String interfaceName = obtainXmlPropertyViaXPath(
+ "//management/management-interfaces/http-interface/@interface");
+ interfaceExpession = obtainXmlPropertyViaXPath(
+ "/server/interfaces/interface[@name='" + interfaceName + "']/inet-address/@value");
}
- for (int i = 0 ; i < mgmtInterfaces.getLength(); i++) {
- if (!(mgmtInterfaces.item(i) instanceof Element))
- continue;
-
- Element mgmtInterface = (Element) mgmtInterfaces.item(i);
- if (mgmtInterface.getNodeName().equals("http-interface")) {
- String tmp = mgmtInterface.getAttribute("port"); // TODO if we don't find it, check for socket-binding
- int port;
- if (!tmp.isEmpty())
- port = Integer.valueOf(tmp);
- else
- port = DEFAULT_MGMT_PORT;
- HostPort hp = new HostPort();
- hp.isLocal=true; // TODO adjust when host != localhost
- hp.port = port;
-
- String nIf = mgmtInterface.getAttribute("interface");
- if (!nIf.isEmpty())
- hp.host = getInterface(nIf, commandLine);
- else
- hp.host = "localhost";
- return hp;
- }
- }
- return new HostPort();
- }
+ else {
+ // later AS7.1 and EAP6
+ portString = obtainXmlPropertyViaXPath(
+ "/server/socket-binding-group/socket-binding[@name='" + socketBindingName + "']/@port");
+ String interfaceName = obtainXmlPropertyViaXPath(
+ "/server/socket-binding-group/socket-binding[@name='" + socketBindingName + "']/@interface");
- /**
- * Try to obtain the management interface IP from the host/standalone.xml files
- *
- * @param nIf Interface to look for
- * @param commandLine Command line arguments of the process
- * @return IP address to use
- */
- private String getInterface(String nIf, String[] commandLine) {
- if (hostXml==null)
- throw new IllegalArgumentException("hostXml is null. You need to call 'readStandaloneOrHostXml' first.");
+ // TODO the next may also be expressed differently
+ interfaceExpession = obtainXmlPropertyViaXPath(
+ "/server/interfaces/interface[@name='" + interfaceName + "']/inet-address/@value");
- Element host = hostXml.getDocumentElement();
- NodeList interfaceParent = host.getElementsByTagName("interfaces");
- if (interfaceParent ==null || interfaceParent.getLength()==0) {
- log.warn("No <interfaces> found in host.xml");
- return null;
- }
- NodeList mgmtInterfaces = interfaceParent.item(0).getChildNodes();
- if (mgmtInterfaces==null || mgmtInterfaces.getLength()==0) {
- log.warn("No <*-interface> found in host.xml");
- return null;
}
- for (int i = 0 ; i < mgmtInterfaces.getLength(); i++) {
- if (!(mgmtInterfaces.item(i) instanceof Element))
- continue;
- Element mgmtInterface = (Element) mgmtInterfaces.item(i);
- if (mgmtInterface.getNodeName().equals("interface")) {
- String name = mgmtInterface.getAttribute("name");
- if (!name.equals(nIf))
- continue;
-
- NodeList nl = mgmtInterface.getChildNodes();
- if (nl!=null) {
- for (int j = 0 ; j < nl.getLength(); j++) {
- if (!(nl.item(j) instanceof Element))
- continue;
-
- String nodeName = nl.item(j).getNodeName();
- if (nodeName.equals("any-ipv4-address"))
- return "0.0.0.0";
-
- String value = ((Element) nl.item(j)).getAttribute("value");
- value = replaceExpression(value, commandLine);
- return value;
-
- // TODO check for <any> and so on
- }
- }
- }
+ HostPort hp = new HostPort();
+
+ if (!interfaceExpession.isEmpty())
+ hp.host = replaceDollarExpression(interfaceExpession, commandLine);
+ else
+ hp.host = "localhost"; // Fallback
+
+ if (portString!=null && !portString.isEmpty()) {
+ hp.port = Integer.valueOf(portString);
}
- return null; // TODO: Customise this generated block
+ else
+ hp.port = 9990; // Fallback to default
+ return hp;
}
+
/**
* Check if the passed value has an expression in the form of ${var} or ${var:default},
* try to resolve it. Resolution is done by looking at the command line to see if
@@ -209,7 +175,7 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
* @param commandLine The command line from the process
* @return resolved value
*/
- private String replaceExpression(String value, String[] commandLine) {
+ private String replaceDollarExpression(String value, String[] commandLine) {
if (!value.contains("${"))
return value;
@@ -250,12 +216,12 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
/**
* Try to determine the host name - that is the name of a standalone server or a
- * host in domain mode by looking at the standalone/host.xml files
+ * host in domain mode by looking at the standalone.xml/host.xml files
* @return server name
*/
protected String findHostName() {
if (hostXml==null)
- throw new IllegalArgumentException("hostXml is null. You need to call 'readStandaloneOrHostXml' first.");
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
String hostName = hostXml.getDocumentElement().getAttribute("name");
return hostName;
@@ -267,29 +233,53 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
*/
protected HostPort getDomainControllerFromHostXml() {
if (hostXml==null)
- throw new IllegalArgumentException("hostXml is null. You need to call 'readStandaloneOrHostXml' first.");
-
- Element host = hostXml.getDocumentElement();
- NodeList dcParent = host.getElementsByTagName("domain-controller");
- if (dcParent==null || dcParent.getLength()==0)
- return new HostPort(false);
- NodeList interfs = dcParent.item(0).getChildNodes();
- for (int i = 0; i < interfs.getLength(); i++) {
- if (!(interfs.item(i)instanceof Element))
- continue;
-
- Element interf = (Element) interfs.item(i);
- if (interf.getNodeName().equals("local"))
- return new HostPort();
-
- // not local, so get the remote
- HostPort hp = new HostPort(false);
- hp.host = interf.getAttribute("host");
- hp.port = Integer.parseInt(interf.getAttribute("port"));
- return hp;
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
+
+
+ // first check remote, as we can't distinguish between a missing local element or
+ // and empty one which is the default
+ String remoteHost = obtainXmlPropertyViaXPath("/host/domain-controller/remote/@host");
+ String portString = obtainXmlPropertyViaXPath("/host/domain-controller/remote/@port");
+
+ HostPort hp;
+ if (!remoteHost.isEmpty() && !portString.isEmpty()) {
+ hp = new HostPort(false);
+ hp.host = remoteHost;
+ hp.port = Integer.parseInt(portString);
}
+ else {
+ hp = new HostPort(true);
+ hp.port = 9999;
+ }
+
+ return hp;
+
+ }
+
+ String getManagementSecurtiyRealmFromHostXml() {
+ if (hostXml==null)
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
+
+ String realm = obtainXmlPropertyViaXPath("//management/management-interfaces/http-interface/@security-realm");
+
+ return realm;
+ }
+
+ String getSecurityPropertyFileFromHostXml(String baseDir, AS7Mode mode, String realm) {
+ if (hostXml==null)
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
+
+ // TODO make realm variable
+ String fileName = obtainXmlPropertyViaXPath("//security-realms/security-realm[@name='" + realm + "']/authentication/properties/@path");
+ String relDir = obtainXmlPropertyViaXPath("//security-realms/security-realm[@name='" + realm + "']/authentication/properties/@relative-to");
+
+ String fullName ;
+ if (relDir.equals("jboss.server.config.dir"))
+ fullName = baseDir + File.separator + mode.getBaseDir() + File.separator + "configuration" + File.separator + fileName;
+ else
+ fullName = relDir + File.separator + fileName;
- return new HostPort(false);
+ return fullName;
}
/**
@@ -332,6 +322,34 @@ public abstract class AbstractBaseDiscovery<T extends ResourceComponent<?>> impl
}
/**
+ * Run the passed xpathExpression on the prepopulated hostXml document and
+ * return the target element or attribute as a String.
+ * @param xpathExpression XPath Expression to evaluate
+ * @return String value of the Element or Attribute the XPath was pointing to.
+ * Null in case the xpathExpression could not be evaluated.
+ * @throws IllegalArgumentException if hostXml is null
+ *
+ */
+ protected String obtainXmlPropertyViaXPath(String xpathExpression) {
+ if (hostXml==null)
+ throw new IllegalArgumentException(CALL_READ_STANDALONE_OR_HOST_XML_FIRST);
+
+
+ XPath xpath = factory.newXPath();
+ try {
+ XPathExpression expr = xpath.compile(xpathExpression);
+
+ Object result = expr.evaluate(hostXml, XPathConstants.STRING);
+
+ return result.toString();
+ } catch (XPathExpressionException e) {
+ log.error("Evaluation XPath expression failed: " + e.getMessage());
+ return null;
+ }
+ }
+
+
+ /**
* Helper class that holds information about the host,port tuple
*/
protected static class HostPort {
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
index 7395233..3f03e52 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/BaseComponent.java
@@ -89,6 +89,8 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
String host;
int port;
private boolean verbose = ASConnection.verbose;
+ String managementUser;
+ String managementPassword;
/**
* Return availability of this resource
@@ -99,7 +101,7 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
ReadResource op = new ReadResource(address);
Result res = connection.execute(op);
- return res.isSuccess()? AvailabilityType.UP: AvailabilityType.DOWN;
+ return (res!=null && res.isSuccess()) ? AvailabilityType.UP: AvailabilityType.DOWN;
}
@@ -115,7 +117,9 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
host = pluginConfiguration.getSimpleValue("hostname", LOCALHOST);
String portString = pluginConfiguration.getSimpleValue("port", DEFAULT_HTTP_MANAGEMENT_PORT);
port = Integer.parseInt(portString);
- connection = new ASConnection(host,port);
+ managementUser = pluginConfiguration.getSimpleValue("user","-unset-");
+ managementPassword = pluginConfiguration.getSimpleValue("password","-unset-");
+ connection = new ASConnection(host,port, managementUser, managementPassword);
}
else {
connection = ((BaseComponent)context.getParentResourceComponent()).getASConnection();
@@ -310,7 +314,7 @@ public class BaseComponent<T extends ResourceComponent<?>> implements ResourceCo
ContentServices contentServices = cctx.getContentServices();
String resourceTypeName = report.getResourceType().getName();
- ASUploadConnection uploadConnection = new ASUploadConnection(host,port);
+ ASUploadConnection uploadConnection = new ASUploadConnection(host,port, managementUser, managementPassword);
OutputStream out = uploadConnection.getOutputStream(details.getFileName());
contentServices.downloadPackageBitsForChildResource(cctx, resourceTypeName, details.getKey(), out);
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 54e7e78..3f049dc 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
@@ -75,7 +75,7 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
String serverNameFull;
String serverName;
String psName = psr.getProcessScan().getName();
- String description = discoveryContext.getResourceType().getDescription();
+ String description;
String homeDir = getHomeDirFromCommandLine(commandLine);
String version = determineServerVersionFromHomeDir(homeDir);
boolean isEAP = false;
@@ -115,7 +115,7 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
String host = findHost(psr.getProcessInfo(), true);
config.put(new PropertySimple("domainHost", host));
- fillUserPassFromFile(config, "domain", homeDir);
+ fillUserPassFromFile(config, AS7Mode.DOMAIN, homeDir);
// provide running config
String domainConfig = getServerConfigFromCommandLine(commandLine, AS7Mode.DOMAIN);
@@ -157,7 +157,7 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
config.put(new PropertySimple("config",serverConfig));
config.put(new PropertySimple("startScript",AS7Mode.STANDALONE.getStartScript()));
- fillUserPassFromFile(config, "standalone", serverNameFull);
+ fillUserPassFromFile(config, AS7Mode.STANDALONE, serverNameFull);
//preload server.log file for event log monitoring
logFile = bootLogFile.substring(0, bootLogFile.lastIndexOf("/")) + File.separator + "server.log";
@@ -173,6 +173,8 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
HostPort managmentPort = getManagementPortFromHostXml(commandLine);
config.put(new PropertySimple("hostname", managmentPort.host));
config.put(new PropertySimple("port", managmentPort.port));
+ config.put(new PropertySimple("realm",getManagementSecurtiyRealmFromHostXml()));
+
// String javaClazz = psr.getProcessInfo().getName();
/*
@@ -207,11 +209,14 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
}
- private void fillUserPassFromFile(Configuration config, String mode, String baseDir) {
+ private void fillUserPassFromFile(Configuration config, AS7Mode mode, String baseDir) {
+
+// String configDir = baseDir + File.separator + mode + File.separator + "configuration";
+ String realm = getManagementSecurtiyRealmFromHostXml();
+ String fileName = getSecurityPropertyFileFromHostXml(baseDir,mode, realm);
- String configDir = baseDir + File.separator + mode + File.separator + "configuration";
- File file = new File(configDir, "mgmt-users.properties");
+ File file = new File(fileName);
if (!file.exists() || !file.canRead()) {
if (log.isDebugEnabled())
log.debug("No console user properties file found at [" + file.getAbsolutePath()
@@ -234,7 +239,7 @@ public class BaseProcessDiscovery extends AbstractBaseDiscovery implements Resou
String user = line.substring(0, line.indexOf("="));
String pass = line.substring(line.indexOf("=") + 1);
config.put(new PropertySimple("user", user));
- config.put(new PropertySimple("password", pass));
+// config.put(new PropertySimple("password", pass)); // this is now hashed, so no point in supplying it
}
} catch (IOException e) {
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 581c4e1..3a3fa03 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
@@ -19,13 +19,20 @@
package org.rhq.modules.plugins.jbossas7;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.net.ConnectException;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.jboss.sasl.util.UsernamePasswordHashUtil;
+
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.core.pluginapi.util.ProcessExecutionUtility;
@@ -137,6 +144,11 @@ public class BaseServerComponent extends BaseComponent {
*/
protected OperationResult postProcessResult(String name, Result res) {
OperationResult operationResult = new OperationResult();
+ if (res==null) {
+ operationResult.setErrorMessage("No result received from server");
+ return operationResult;
+ }
+
if (name.equals("shutdown") || name.equals("reload")) {
/*
* Shutdown needs a special treatment, because after sending the operation, if shutdown suceeds,
@@ -168,4 +180,55 @@ public class BaseServerComponent extends BaseComponent {
return operationResult;
}
+ protected OperationResult installManagementUser(Configuration parameters, Configuration pluginConfig, AS7Mode mode) {
+ String user = parameters.getSimpleValue("user","");
+ String password = parameters.getSimpleValue("password","");
+
+ OperationResult result = new OperationResult();
+ if (user.isEmpty() || password.isEmpty()) {
+ result.setErrorMessage("User and Password must not be empty");
+ return result;
+ }
+
+ String baseDir = pluginConfig.getSimpleValue("baseDir","");
+ if (baseDir.isEmpty()) {
+ result.setErrorMessage("No baseDir found, can not continue");
+ return result;
+ }
+ String standaloneXmlFile = pluginConfig.getSimpleValue("config",mode.getDefaultXmlFile());
+
+ String standaloneXml = baseDir + File.separator + mode.getBaseDir() + File.separator + "configuration" + File.separator + standaloneXmlFile;
+
+ AbstractBaseDiscovery abd = new AbstractBaseDiscovery();
+ abd.readStandaloneOrHostXmlFromFile(standaloneXml);
+
+ String realm = pluginConfig.getSimpleValue("realm","ManagementRealm");
+ String propertiesFilePath = abd.getSecurityPropertyFileFromHostXml(baseDir,mode, realm);
+
+
+ Properties p = new Properties();
+ try {
+ UsernamePasswordHashUtil util = new UsernamePasswordHashUtil();
+ String value = util.generateHashedHexURP(user, realm, password.toCharArray());
+
+
+ FileInputStream fis = new FileInputStream(propertiesFilePath);
+ p.load(fis);
+ fis.close();
+ p.setProperty(user,value);
+ FileOutputStream fos = new FileOutputStream(propertiesFilePath);
+ p.store(fos,null);
+ fos.flush();
+ fos.close();
+ } catch (IOException e) {
+ log.error(e.getMessage());
+ result.setErrorMessage(e.getMessage());
+ } catch (NoSuchAlgorithmException nsae) {
+ log.error(nsae.getMessage());
+ result.setErrorMessage(nsae.getMessage());
+ }
+ result.setSimpleResult("User/Password set or updated");
+
+ return result;
+ }
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
index c844d78..cbed07e 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationLoadDelegate.java
@@ -120,6 +120,15 @@ public class ConfigurationLoadDelegate implements ConfigurationFacet {
operation = new ReadChildrenResources(address,type);
operation.addAdditionalProperty("recursive", "true");
}
+ else if (groupName.startsWith("child:")) {
+ String subPath = groupName.substring("child:".length());
+ if (!subPath.contains("="))
+ throw new IllegalArgumentException("subPath of 'child:' expression has no =");
+
+ Address address1 = new Address(address);
+ address1.addSegment(subPath);
+ operation = new ReadResource(address1);
+ }
else {
throw new IllegalArgumentException("Unknown operation in group name [" + groupName + "]");
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
index e966ba3..4f07bfc 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ConfigurationWriteDelegate.java
@@ -50,7 +50,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
final Log log = LogFactory.getLog(this.getClass());
- private Address address;
+ private Address _address;
private ASConnection connection;
private ConfigurationDefinition configurationDefinition;
private String namePropLocator;
@@ -65,7 +65,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
public ConfigurationWriteDelegate(ConfigurationDefinition configDef, ASConnection connection, Address address) {
this.configurationDefinition = configDef;
this.connection = connection;
- this.address = address;
+ this._address = address;
}
/**
@@ -89,7 +89,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
Configuration conf = report.getConfiguration();
- CompositeOperation cop = updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = updateGenerateOperationFromProperties(conf, _address);
Result result = connection.execute(cop);
if (!result.isSuccess()) {
@@ -103,13 +103,13 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
- protected CompositeOperation updateGenerateOperationFromProperties(Configuration conf) {
+ protected CompositeOperation updateGenerateOperationFromProperties(Configuration conf, Address address) {
CompositeOperation cop = new CompositeOperation();
for (PropertyDefinition propDef : configurationDefinition.getNonGroupedProperties()) {
- updateProperty(conf, cop, propDef);
+ updateProperty(conf, cop, propDef, address);
}
for (PropertyGroupDefinition pgd: configurationDefinition.getGroupDefinitions()) {
String groupName = pgd.getName();
@@ -126,8 +126,21 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
List<PropertyDefinition> definitions = configurationDefinition.getPropertiesInGroup(groupName);
for (PropertyDefinition def : definitions) {
- updateProperty(conf,cop,def);
+ updateProperty(conf,cop,def, address);
}
+ } if (groupName.startsWith("child:")) {
+ String subPath = groupName.substring("child:".length());
+ if (!subPath.contains("="))
+ throw new IllegalArgumentException("subPath of 'child:' expression has no =");
+
+ Address address1 = new Address(address);
+ address1.addSegment(subPath);
+
+ List<PropertyDefinition> definitions = configurationDefinition.getPropertiesInGroup(groupName);
+ for (PropertyDefinition def : definitions) {
+ updateProperty(conf,cop,def, address1);
+ }
+
} // TODO handle attribute: case
}
@@ -135,7 +148,8 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
return cop;
}
- private void updateProperty(Configuration conf, CompositeOperation cop, PropertyDefinition propDef) {
+ private void updateProperty(Configuration conf, CompositeOperation cop, PropertyDefinition propDef,
+ Address baseAddress) {
// Skip over read-only properties, the AS can not use them anyway
if (propDef.isReadOnly())
@@ -147,7 +161,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
PropertyList pl = (PropertyList) conf.get("*"); // TODO loop over the list content
for (Property prop2 : pl.getList()) {
- updateHandlePropertyMapSpecial(cop, (PropertyMap) prop2, (PropertyDefinitionMap) propDef);
+ updateHandlePropertyMapSpecial(cop, (PropertyMap) prop2, (PropertyDefinitionMap) propDef, baseAddress);
}
}
else {
@@ -155,25 +169,27 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
Property prop = conf.get(propDef.getName());
if (prop instanceof PropertySimple) {
- updateHandlePropertySimple(cop, (PropertySimple)prop, (PropertyDefinitionSimple) propDef);
+ updateHandlePropertySimple(cop, (PropertySimple)prop, (PropertyDefinitionSimple) propDef, baseAddress);
}
else if (prop instanceof PropertyList) {
- updateHandlePropertyList(cop, (PropertyList) prop, (PropertyDefinitionList) propDef);
+ updateHandlePropertyList(cop, (PropertyList) prop, (PropertyDefinitionList) propDef, baseAddress);
}
else {
- updateHandlePropertyMap(cop,(PropertyMap)prop,(PropertyDefinitionMap)propDef);
+ updateHandlePropertyMap(cop,(PropertyMap)prop,(PropertyDefinitionMap)propDef, baseAddress);
}
}
}
- private void updateHandlePropertyMap(CompositeOperation cop, PropertyMap prop, PropertyDefinitionMap propDef) {
- Map<String,Object> results = updateHandleMap(prop,propDef);
+ private void updateHandlePropertyMap(CompositeOperation cop, PropertyMap prop, PropertyDefinitionMap propDef,
+ Address address) {
+ Map<String,Object> results = updateHandleMap(prop,propDef, address);
Operation writeAttribute = new WriteAttribute(address,prop.getName(),results);
cop.addStep(writeAttribute);
}
- private void updateHandlePropertyMapSpecial(CompositeOperation cop, PropertyMap prop, PropertyDefinitionMap propDef) {
- Map<String,Object> results = updateHandleMap(prop,propDef);
+ private void updateHandlePropertyMapSpecial(CompositeOperation cop, PropertyMap prop, PropertyDefinitionMap propDef,
+ Address address) {
+ Map<String,Object> results = updateHandleMap(prop,propDef, address);
if (prop.get(namePropLocator)==null) {
throw new IllegalArgumentException("There is no element in the map with the name " + namePropLocator);
}
@@ -186,7 +202,8 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
}
- private void updateHandlePropertyList(CompositeOperation cop, PropertyList prop, PropertyDefinitionList propDef) {
+ private void updateHandlePropertyList(CompositeOperation cop, PropertyList prop, PropertyDefinitionList propDef,
+ Address address) {
PropertyDefinition memberDef = propDef.getMemberDefinition();
// We need to collect the list members, create an array and attach this to the cop
@@ -201,7 +218,8 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
if (memberDef instanceof PropertyDefinitionMap) {
- Map<String,Object> mapResult = updateHandleMap((PropertyMap) inner,(PropertyDefinitionMap)memberDef);
+ Map<String,Object> mapResult = updateHandleMap((PropertyMap) inner,(PropertyDefinitionMap)memberDef,
+ address);
values.add(mapResult);
}
}
@@ -210,7 +228,8 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
}
- private void updateHandlePropertySimple(CompositeOperation cop, PropertySimple propertySimple, PropertyDefinitionSimple propDef) {
+ private void updateHandlePropertySimple(CompositeOperation cop, PropertySimple propertySimple,
+ PropertyDefinitionSimple propDef, Address address) {
// If the property value is null and the property is optional, skip too
if (propertySimple.getStringValue()==null && !propDef.isRequired())
@@ -221,7 +240,7 @@ public class ConfigurationWriteDelegate implements ConfigurationFacet {
cop.addStep(writeAttribute);
}
- private Map<String, Object> updateHandleMap(PropertyMap map, PropertyDefinitionMap mapDef) {
+ private Map<String, Object> updateHandleMap(PropertyMap map, PropertyDefinitionMap mapDef, Address address) {
Map<String,PropertyDefinition> memberDefinitions = mapDef.getPropertyDefinitions();
Map<String,Object> results = new HashMap<String,Object>();
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 df5362c..bc7d601 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
@@ -54,28 +54,47 @@ public class Domain2Descriptor {
private void run(String[] args) {
D2DMode mode = null;
+ String user = null;
+ String pass = null;
+
int pos = 0;
- if (args[0].startsWith("-")) {
- if (args[0].equals("-m"))
- mode = D2DMode.METRICS;
- else if (args[0].equals("-p"))
- mode = D2DMode.PROPERTIES;
- else if (args[0].equals("-o"))
- mode = D2DMode.OPERATION;
- else {
- usage();
- return;
+ boolean optionFound=false;
+
+ String arg;
+ do {
+ arg = args[pos];
+ if (arg.startsWith("-")) {
+ if (args[0].equals("-m"))
+ mode = D2DMode.METRICS;
+ else if (arg.equals("-p"))
+ mode = D2DMode.PROPERTIES;
+ else if (arg.equals("-o"))
+ mode = D2DMode.OPERATION;
+ else if (arg.startsWith("-U")) {
+ String tmp = arg.substring(2);
+ if (!tmp.contains(":"))
+ usage();
+ user = tmp.substring(0,tmp.indexOf(":"));
+ pass = tmp.substring(tmp.indexOf(":")+1);
+ }
+ else {
+ usage();
+ return;
+ }
+ pos++;
+ optionFound=true;
}
- pos++;
- }
+ else
+ optionFound=false;
+ }while(optionFound);
- String path = args[pos];
+ String path = arg;
path = path.replaceAll("/",","); // Allow path from jboss-admin.sh's pwd command
String childType = null;
if (args.length>pos+1)
childType = args[pos+1];
- ASConnection conn = new ASConnection("localhost",9990);
+ ASConnection conn = new ASConnection("localhost",9990, user, pass);
Address address = new Address(path);
Operation op = new Operation("read-resource-description",address);
@@ -87,6 +106,10 @@ public class Domain2Descriptor {
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;
@@ -313,6 +336,8 @@ public class Domain2Descriptor {
typeString = "long"; break;
case BIG_DECIMAL:
typeString = "long"; break; // TODO better float or double?
+ case DOUBLE:
+ typeString = "long"; break; // TODO float or double?
case LIST:
typeString = "-list-";
break; // Handled below
@@ -412,6 +437,7 @@ public class Domain2Descriptor {
System.out.println(" -p create properties (default)");
System.out.println(" -m create metrics");
System.out.println(" -o create operations");
+ System.out.println(" -U<user>:<pass> - supply credentials to talk to AS7" );
}
public enum Type {
@@ -421,7 +447,8 @@ public class Domain2Descriptor {
LONG,
BIG_DECIMAL,
OBJECT,
- LIST
+ LIST,
+ DOUBLE
;
}
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
index 6168dad..f4fa473 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/HostControllerComponent.java
@@ -61,6 +61,10 @@ public class HostControllerComponent extends BaseServerComponent implements Oper
return postProcessResult(name,res);
}
+ else if (name.equals("installRhqUser")) {
+ return installManagementUser(parameters, pluginConfiguration, AS7Mode.HOST);
+ }
+
// Defer other stuff to the base component for now
return super.invokeOperation(name, parameters);
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
index 8df1c47..3e90588 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ManagedASDiscovery.java
@@ -48,6 +48,7 @@ import org.rhq.modules.plugins.jbossas7.json.ReadResource;
*
* @author Heiko W. Rupp
*/
+@SuppressWarnings("unused")
public class ManagedASDiscovery extends AbstractBaseDiscovery
{
@@ -138,7 +139,7 @@ public class ManagedASDiscovery extends AbstractBaseDiscovery
}
private ServerInfo getBindingsFromDC(HostPort domainController, String serverGroup) {
- ASConnection dcConnection = new ASConnection(domainController.host, domainController.port);
+ ASConnection dcConnection = new ASConnection(domainController.host, domainController.port, "-TODO-", "-TODO-"); // TODO where do we get these from?
List<PROPERTY_VALUE> address = new ArrayList<PROPERTY_VALUE>();
Address theAddress = new Address("server-group", serverGroup);
Operation op = new ReadResource(theAddress);
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ServerGroupComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ServerGroupComponent.java
index c703635..c5a17a8 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ServerGroupComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/ServerGroupComponent.java
@@ -74,7 +74,7 @@ public class ServerGroupComponent extends ManagedASComponent implements ContentF
for (ResourcePackageDetails details : packages) {
- ASUploadConnection uploadConnection = new ASUploadConnection(host,port);
+ ASUploadConnection uploadConnection = new ASUploadConnection(host,port, super.managementUser, super.managementPassword);
String fileName = details.getFileName();
OutputStream out = uploadConnection.getOutputStream(fileName);
contentServices.downloadPackageBits(cctx, details.getKey(), out, false);
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/StandaloneASComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/StandaloneASComponent.java
index 11a0e4d..f3c3184 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/StandaloneASComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/StandaloneASComponent.java
@@ -40,6 +40,8 @@ public class StandaloneASComponent extends BaseServerComponent implements Operat
} else if (name.equals("restart")) {
return restartServer(parameters, AS7Mode.STANDALONE);
+ } else if (name.equals("installRhqUser")) {
+ return installManagementUser(parameters, pluginConfiguration, AS7Mode.STANDALONE);
}
// reload, shutdown go to the remote server
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
index c0a9196..51fc3a2 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/json/Address.java
@@ -83,11 +83,7 @@ public class Address {
if (tmp.contains("=")) {
// strip / from the start of the key if it happens to be there
- if (tmp.startsWith("/"))
- tmp = tmp.substring(1);
-
- String[] pair = tmp.split("=");
- PROPERTY_VALUE valuePair = new PROPERTY_VALUE(pair[0], pair[1]);
+ PROPERTY_VALUE valuePair = pathFromSegment(tmp);
this.path.add(valuePair);
}
}
@@ -95,6 +91,19 @@ public class Address {
}
/**
+ * Generates a path from a segment in the form of key=value.
+ * @param segment A segment in the form key=value
+ * @return A path
+ */
+ private PROPERTY_VALUE pathFromSegment(String segment) {
+ if (segment.startsWith("/"))
+ segment = segment.substring(1);
+
+ String[] pair = segment.split("=");
+ return new PROPERTY_VALUE(pair[0], pair[1]);
+ }
+
+ /**
* Add a key value pair to the path
* @param key Key part of this path element
* @param value Value part of this path element
@@ -103,6 +112,14 @@ public class Address {
path.add(new PROPERTY_VALUE(key,value));
}
+ public void addSegment(String segment) {
+ if (!segment.contains("="))
+ throw new IllegalArgumentException("Segment [" + segment + "] contains no '='");
+
+ PROPERTY_VALUE pv = pathFromSegment(segment);
+ path.add(pv);
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder( "Address{" +
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 8048100..ee6b902 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
@@ -50,31 +50,11 @@
xmlns:c="urn:xmlns:rhq-configuration"
>
- <depends plugin="JMX" useClasses="true"/>
-
<!-- TODO I think we should introduce an abstract AS7 plugin that contains some base functionality and then
~~ additional 'Personalities' for the kinds of servers (PM, SM, Standalone AS, Managed AS)
-->
- <!-- TODO do we want to show the process controller at all? We have no benefit from it
- <server name="ProcessController"
- discovery="BaseProcessDiscovery"
- class="BaseComponent"
- description="Reaper process for other AS7 services"
- >
-
- <plugin-configuration>
- <c:simple-property name="hostname" default="localhost" required="true"/>
- <c:simple-property name="port" default="9990" type="integer" required="true"/>
-
- </plugin-configuration>
-
- <process-scan name="ProcessController" query="process|basename|match=^java.*,arg|org.jboss.as.process-controller|match=.*"/>
-
-
- </server>
- -->
<server name="JBossAS7 Host Controller"
discovery="BaseProcessDiscovery"
class="HostControllerComponent"
@@ -84,8 +64,8 @@
<plugin-configuration>
<c:simple-property name="hostname" default="localhost" required="true" description="Host name of the domain API"/>
<c:simple-property name="port" default="9990" type="integer" required="true" description="Port of the domain API"/>
- <c:simple-property name="user" type="string" description="Management user for a secured Host controller" required="false"/>
- <c:simple-property name="password" type="password" description="Password for the management user" required="false"/>
+ <c:simple-property name="user" type="string" default="rhqadmin" description="Management user for a secured Host controller" required="false"/>
+ <c:simple-property name="password" type="password" default="rhqadmin" description="Password for the management user" required="false"/>
<c:simple-property name="domainConfig" type="string" default="domain.xml" description="Running configuration (domain part)" displayName="Domain Configuration"/>
<c:simple-property name="hostConfig" type="string" default="host.xml" description="Running configuration (host part)" displayName="Host Configuration"/>
<c:simple-property name="baseDir" type="file" description="Base directory of the server installation" displayName="Base directory" readOnly="true" required="false"/>
@@ -179,6 +159,15 @@
<c:simple-property name="operationResult" description="Outcome of the stop operation"/>
</results>
</operation>
+ <operation name="installRhqUser" description="Installs a user in the server for management" displayName="Install RHQ user">
+ <parameters>
+ <c:simple-property name="user" displayName="Username" description="Name of the management user" default="rhqadmin"/>
+ <c:simple-property name="password" displayName="Password" description="Password of this management user" default="rhqadmin" type="password"/>
+ </parameters>
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
<metric property="_internal:mgmtRequests" category="performance" dataType="measurement" defaultInterval="120000"
@@ -192,6 +181,11 @@
displayType="summary" measurementType="dynamic" description="Max time for a request since last metric get" units="milliseconds"
displayName="Maximum request time"/>
+ <metric property="server-state" dataType="trait" displayName="Server state" description="Detailed server state"
+ displayType="summary"/>
+ <metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
+ <metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
+
<event name="logEntry" description="an entry in a log file"/>
<resource-configuration>
@@ -206,11 +200,10 @@
</c:group>
-->
- <c:group name="children:extension" displayName="Installed extensions">
-
+ <c:group name="children:extension" displayName="Installed extensions" hiddenByDefault="true">
<c:list-property name="*" displayName="Installed extensions" readOnly="true" required="false">
<c:map-property name="*" displayName="Name" readOnly="true">
- <c:simple-property name="module" displayName="Module name"/>
+ <c:simple-property name="module" displayName="Module name" readOnly="true"/>
</c:map-property>
</c:list-property>
</c:group>
@@ -332,8 +325,8 @@
<plugin-configuration>
<c:simple-property name="hostname" default="localhost" required="true"/>
<c:simple-property name="port" default="9990" type="integer" required="true"/>
- <c:simple-property name="user" type="string" description="Management user for a secured AS" required="false"/>
- <c:simple-property name="password" type="password" description="Password for the management user" required="false"/>
+ <c:simple-property name="user" default="rhqadmin" type="string" description="Management user for a secured AS" required="false"/>
+ <c:simple-property name="password" default="rhqadmin" type="password" description="Password for the management user" required="false"/>
<c:simple-property name="config" type="string" default="standalone.xml" description="Running configuration" displayName="Configuration"/>
<c:simple-property name="baseDir" type="file" description="Base directory of the server installation" displayName="Base directory" readOnly="true" required="false"/>
<c:simple-property name="startScript" type="file" default="bin/standalone.sh" description="Script used to start the server. If the path is not absolute, it is relative to the base directory"/>
@@ -404,6 +397,15 @@
<c:simple-property name="operationResult"/>
</results>
</operation>
+ <operation name="installRhqUser" description="Installs a user in the server for management" displayName="Install RHQ user">
+ <parameters>
+ <c:simple-property name="user" displayName="Username" description="Name of the management user" default="rhqadmin"/>
+ <c:simple-property name="password" displayName="Password" description="Password of this management user" default="rhqadmin" type="password"/>
+ </parameters>
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
<metric property="_internal:mgmtRequests" category="performance" dataType="measurement" defaultInterval="120000"
@@ -416,6 +418,11 @@
displayType="summary" measurementType="dynamic" description="Max time for a request since last metric get" units="milliseconds"
displayName="Maximum request time"/>
+ <metric property="server-state" dataType="trait" displayName="Server state" description="Detailed server state"
+ displayType="summary"/>
+ <metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
+ <metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
+
<event name="logEntry" description="an entry in a log file"/>
<resource-configuration>
@@ -431,11 +438,10 @@
</c:group>
-->
- <c:group name="children:extension" displayName="Installed extensions">
-
+ <c:group name="children:extension" displayName="Installed extensions" hiddenByDefault="true">
<c:list-property name="*" displayName="Installed extensions" readOnly="true" required="false">
<c:map-property name="*" displayName="Name" readOnly="true">
- <c:simple-property name="module" displayName="Module name"/>
+ <c:simple-property name="module" displayName="Module name" readOnly="true"/>
</c:map-property>
</c:list-property>
</c:group>
@@ -515,31 +521,98 @@
</results>
</operation>
- <metric property="status" dataType="trait" displayName="Server state" description="Detailed server state"
+ <metric property="server-state" dataType="trait" displayName="Server state" description="Detailed server state"
displayType="summary"/>
+ <metric property="release-codename" dataType="trait" displayName="Code name of the release" displayType="summary"/>
+ <metric property="release-version" dataType="trait" displayName="Version of the server" displayType="summary"/>
<event name="logEntry" description="an entry in a log file"/>
</server>
- <server name="JBoss AS JVM"
- description="JVM of the JBossAS"
- sourcePlugin="JMX"
- sourceType="JMX Server"
- discovery="org.rhq.plugins.jmx.EmbeddedJMXServerDiscoveryComponent"
- class="org.rhq.plugins.jmx.JMXServerComponent"
- singleton="true">
+ <server name="JVM"
+ discovery="SubsystemDiscovery"
+ class="BaseComponent"
+ description="Information about the underlying JVM"
+ singleton="true">
<runs-inside>
<parent-resource-type name="JBossAS7 Managed Server" plugin="jboss-as-7"/>
<parent-resource-type name="JBossAS7 Standalone Server" plugin="jboss-as-7"/>
</runs-inside>
- </server>
- <server name="Messaging"
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="core-service=platform-mbean"/>
+ </plugin-configuration>
+
+ <service name="Operating System"
+ discovery="SubsystemDiscovery"
+ class="BaseComponent"
+ singleton="true"
+ >
+
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="type=operating-system"/>
+ </plugin-configuration>
+
+ <metric property="available-processors"
+ description="The number of processors available to the Java virtual machine."/>
+ <metric property="system-load-average"
+ description="The system load average for the last minute. The load average may not be available on some platforms; if the load average is not available, a negative value is returned."/>
+ </service>
+
+ <service name="Runtime"
+ discovery="SubsystemDiscovery"
+ class="BaseComponent"
+ singleton="true"
+ >
+
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="type=runtime"/>
+ </plugin-configuration>
+
+ <metric property="uptime" description="The uptime of the Java virtual machine in milliseconds."/>
+ </service>
+
+ <service name="Threading"
+ discovery="SubsystemDiscovery"
+ class="BaseComponent"
+ >
+
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="type=threading"/>
+ </plugin-configuration>
+
+ <metric property="thread-count" description="The current number of live threads including both daemon and non-daemon threads."/>
+ <metric property="peak-thread-count" description="The peak live thread count since the Java virtual machine started or peak was reset."/>
+ <metric property="total-started-thread-count" description="The total number of threads created and also started since the Java virtual machine started."/>
+ <metric property="daemon-thread-count" description="The current number of live daemon threads."/>
+ <metric property="current-thread-cpu-time" description="The total CPU time for the current thread in nanoseconds, or -1 if 'thread-cpu-time-enabled' is 'false'. A Java virtual machine implementation may not support CPU time measurement. If 'thread-cpu-time-supported', is 'false' undefined."/>
+ <metric property="current-thread-user-time" description="The CPU time that the current thread has executed in user mode in nanoseconds, or -1 if 'thread-cpu-time-enabled' is 'false'. A Java virtual machine implementation may not support CPU time measurement. If 'thread-cpu-time-supported', is 'false' the result will be undefined "/>
+
+ <resource-configuration>
+ <c:simple-property name="thread-contention-monitoring-enabled" required="false" type="boolean" readOnly="false" description="Whether thread contention monitoring is enabled."/>
+ <c:simple-property name="thread-cpu-time-enabled" required="false" type="boolean" readOnly="false" description="Whether thread CPU time measurement is enabled."/>
+ <c:list-property name="all-thread-ids" description="All live thread IDs. If a security manager is installed and the caller does not have ManagementPermission('monitor'), the result will be und
+ ." >
+ <c:simple-property name="all-thread-ids" />
+ </c:list-property>
+ <c:simple-property name="thread-contention-monitoring-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine supports thread contention monitoring."/>
+ <c:simple-property name="thread-cpu-time-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine implementation supports CPU time measurement for any thread."/>
+ <c:simple-property name="current-thread-cpu-time-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine supports CPU time measurement for the current thread."/>
+ <c:simple-property name="object-monitor-usage-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine supports monitoring of object monitor usage."/>
+ <c:simple-property name="synchronizer-usage-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine supports monitoring of ownable synchronizer usage."/>
+ </resource-configuration>
+ </service>
+
+
+
+ </server>
+
+ <server name="Messaging-Provider"
discovery="SubsystemDiscovery"
class="BaseComponent"
- description="The HornetQ based messaging subsystem"
+ description="The messaging subsystems"
singleton="true"
>
<runs-inside>
@@ -551,82 +624,94 @@
<c:simple-property name="path" readOnly="true" default="subsystem=messaging"/>
</plugin-configuration>
- <operation name="destination:add" displayName="Add destination" description="Add a Queue or Topic">
- <parameters>
- <c:simple-property name="name" description="Name of the Destination" required="true"/>
- <c:list-property name="entries" description="The JNDI names the destination should be bound to." required="true">
- <c:simple-property name="entry" description="A single JNDI name. Note, this is relative to java:jboss/jms/"/>
- </c:list-property>
- <c:simple-property name="type" description="Type of Destination to create" default="Queue">
- <c:property-options>
- <c:option value="jms-queue" name="Queue"/>
- <c:option value="jms-topic" name="Topic"/>
- </c:property-options>
- </c:simple-property>
- <c:simple-property name="durable" description="Defines whether the queue is durable (for Queues only)." type="boolean" default="false"/>
- </parameters>
- <results>
- <c:simple-property name="operationResult"/>
- </results>
- </operation>
- <operation name="destination:remove" displayName="Remove Destination" description="Remove a destination">
- <parameters>
- <c:simple-property name="name" description="Name of the Destination" required="true"/>
- </parameters>
- <results>
- <c:simple-property name="operationResult"/>
- </results>
- </operation>
-
- <resource-configuration>
- <c:simple-property name="journal-min-files" />
- <c:simple-property name="journal-type" />
- </resource-configuration>
+ <server name="HornetQ"
+ discovery="SubsystemDiscovery"
+ class="BaseComponent"
+ description="The HornetQ based messaging subsystem"
+ >
- <service name="JMS Queue"
- discovery="SubsystemDiscovery"
- class="JmsComponent"
- createDeletePolicy="delete-only"
- >
<plugin-configuration>
- <c:simple-property name="path" readOnly="true" default="jms-queue"/>
+ <c:simple-property name="path" readOnly="true" default="hornetq-server"/>
</plugin-configuration>
+
+ <operation name="destination:add" displayName="Add destination" description="Add a Queue or Topic">
+ <parameters>
+ <c:simple-property name="name" description="Name of the Destination" required="true"/>
+ <c:list-property name="entries" description="The JNDI names the destination should be bound to." required="true">
+ <c:simple-property name="entry" description="A single JNDI name. Note, this is relative to java:jboss/jms/"/>
+ </c:list-property>
+ <c:simple-property name="type" description="Type of Destination to create" default="Queue">
+ <c:property-options>
+ <c:option value="jms-queue" name="Queue"/>
+ <c:option value="jms-topic" name="Topic"/>
+ </c:property-options>
+ </c:simple-property>
+ <c:simple-property name="durable" description="Defines whether the queue is durable (for Queues only)." type="boolean" default="false"/>
+ </parameters>
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+ <operation name="destination:remove" displayName="Remove Destination" description="Remove a destination">
+ <parameters>
+ <c:simple-property name="name" description="Name of the Destination" required="true"/>
+ </parameters>
+ <results>
+ <c:simple-property name="operationResult"/>
+ </results>
+ </operation>
+
<resource-configuration>
- <c:simple-property name="durable" required="false" type="boolean" readOnly="true" default="false"
- description="Whether the queue is durable or not."/>
- <c:list-property name="entries" required="false" readOnly="true"
- description="The jndi names the queue will be bound to.">
- <c:simple-property name="entries" type="string"/>
- </c:list-property>
- <c:simple-property name="selector" required="false" type="string" readOnly="true" description="The queue selector."/>
- </resource-configuration>
- </service>
- <service name="JMS Topic"
- discovery="SubsystemDiscovery"
- class="JmsComponent"
- createDeletePolicy="delete-only"
- >
- <plugin-configuration>
- <c:simple-property name="path" readOnly="true" default="jms-topic"/>
- </plugin-configuration>
- <resource-configuration>
- <c:list-property name="entries" required="false" readOnly="true"
- description="The jndi names the queue will be bound to.">
- <c:simple-property name="entries" type="string"/>
- </c:list-property>
+ <c:simple-property name="journal-min-files" />
+ <c:simple-property name="journal-type" />
</resource-configuration>
- </service>
- <service name="Connection-Factory"
- discovery="SubsystemDiscovery"
- class="JmsComponent"
- createDeletePolicy="both"
- >
- <plugin-configuration>
- <c:simple-property name="path" readOnly="true" default="connection-factory"/>
- </plugin-configuration>
- </service>
+ <service name="JMS Queue"
+ discovery="SubsystemDiscovery"
+ class="JmsComponent"
+ createDeletePolicy="delete-only"
+ >
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="jms-queue"/>
+ </plugin-configuration>
+
+ <resource-configuration>
+ <c:simple-property name="durable" required="false" type="boolean" readOnly="true" default="false"
+ description="Whether the queue is durable or not."/>
+ <c:list-property name="entries" required="false" readOnly="true"
+ description="The jndi names the queue will be bound to.">
+ <c:simple-property name="entries" type="string"/>
+ </c:list-property>
+ <c:simple-property name="selector" required="false" type="string" readOnly="true" description="The queue selector."/>
+ </resource-configuration>
+ </service>
+ <service name="JMS Topic"
+ discovery="SubsystemDiscovery"
+ class="JmsComponent"
+ createDeletePolicy="delete-only"
+ >
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="jms-topic"/>
+ </plugin-configuration>
+ <resource-configuration>
+ <c:list-property name="entries" required="false" readOnly="true"
+ description="The jndi names the queue will be bound to.">
+ <c:simple-property name="entries" type="string"/>
+ </c:list-property>
+ </resource-configuration>
+ </service>
+ <service name="Connection-Factory"
+ discovery="SubsystemDiscovery"
+ class="JmsComponent"
+ createDeletePolicy="both"
+ >
+ <plugin-configuration>
+ <c:simple-property name="path" readOnly="true" default="connection-factory"/>
+ </plugin-configuration>
+ </service>
+
+ </server>
</server>
<server name="JBossWeb"
@@ -649,61 +734,64 @@
description="The web container's default virtual server."/>
<c:simple-property name="native" required="false" type="boolean" readOnly="true" defaultValue="true"
description="Add the native initialization listener to the web container."/>
- <c:map-property name="configuration" description="The common web container configuration." >
- <c:map-property name="static-resources" description="Configuration for static resources" >
- <c:simple-property name="listings" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="instance-id" readOnly="true" required="false" type="string" description="The identifier for this server instance."/>
+ <c:group name="child:configuration=static-resources" displayName="Static Resources" >
+ <c:simple-property name="listings" required="false" type="boolean" defaultValue="false"
description="Enable folder listings."/>
- <c:simple-property name="sendfile" required="false" type="integer" readOnly="true" defaultValue="49152"
+ <c:simple-property name="sendfile" required="false" type="integer" defaultValue="49152"
description="Enable sendfile if possible, for files bigger than the specified byte size."/>
- <c:simple-property name="read-only" required="false" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="file-encoding" required="false" description="Force a file encoding." type="string"/>
+ <c:simple-property name="read-only" required="false" type="boolean" defaultValue="true"
description="Allow write HTTP methods (PUT, DELETE)."/>
- <c:simple-property name="webdav" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="webdav" required="false" type="boolean" defaultValue="false"
description="Enable WebDAV functionality."/>
<c:simple-property name="secret" required="false" type="string" readOnly="true" description="Secret for WebDAV locking operations."/>
- <c:simple-property name="max-depth" required="false" type="integer" readOnly="true" defaultValue="3"
+ <c:simple-property name="max-depth" required="false" type="integer" defaultValue="3"
description="Maximum recursion for PROPFIND."/>
- <c:simple-property name="disabled" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="disabled" required="false" type="boolean" defaultValue="false"
+ description="Enable the default Servlet mapping."/>
+ </c:group>
+ <c:group name="child:configuration=jsp-configuration" displayName="JSP Configuration">
+ <c:simple-property name="development" required="false" type="boolean" default="false"
+ description="Enable the development mode, which gives more information when an error occurs. And also enables automatic JSP recompiles."/>
+ <c:simple-property name="disabled" required="false" type="boolean" defaultValue="false"
description="Enable the JSP container."/>
- </c:map-property>
- <c:map-property name="jsp-configuration" description="JSP container configuration">
- <c:simple-property name="development" required="false" type="boolean" readOnly="true" defaultValue="false"
- description="Enable the development mode, which gives more information when an error occurs."/>
- <c:simple-property name="file-encoding" required="false" type="string" readOnly="true" description="Force a file encoding."/>
- <c:simple-property name="keep-generated" required="false" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="keep-generated" required="false" type="boolean" defaultValue="true"
description="Keep the generated Servlets."/>
<c:simple-property name="trim-spaces" required="false" type="boolean" readOnly="true" defaultValue="true"
- description="Trim some spaces from the generated Servlet."/>
- <c:simple-property name="tag-pooling" required="false" type="boolean" readOnly="true" defaultValue="true"
+ description="Trim some spaces from the generated Servlet."/> <!-- TODO make r/w when https://issues.jboss.org/browse/AS7-3097 is solved -->
+ <c:simple-property name="tag-pooling" required="false" type="boolean" defaultValue="true"
description="Enable tag pooling."/>
- <c:simple-property name="mapped-file" required="false" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="mapped-file" required="false" type="boolean" defaultValue="true"
description="Map to the JSP source."/>
- <c:simple-property name="check-interval" required="false" type="integer" readOnly="true" defaultValue="0"
- description="Check interval for JSP updates using a background thread."/>
- <c:simple-property name="modification-test-interval" required="false" type="integer" readOnly="true" defaultValue="4"
+ <c:simple-property name="check-interval" required="false" type="integer" defaultValue="60"
+ description="Check interval for JSP updates using a background thread."/> <!-- TODO revisit default when https://issues.jboss.org/browse/AS7-3098 is fixed -->
+ <c:simple-property name="modification-test-interval" required="false" type="integer" defaultValue="4"
description="Minimum amount of time between two tests for updates, in seconds."/>
- <c:simple-property name="recompile-on-fail" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="recompile-on-fail" required="false" type="boolean" defaultValue="false"
description="Retry failed JSP compilations on each request."/>
- <c:simple-property name="smap" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="smap" required="false" type="boolean" defaultValue="false"
description="Enable SMAP."/>
- <c:simple-property name="dump-smap" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="dump-smap" required="false" type="boolean" defaultValue="false"
description="Write SMAP data to a file."/>
- <c:simple-property name="generate-strings-as-char-arrays" required="false" type="boolean" readOnly="true"
+ <c:simple-property name="generate-strings-as-char-arrays" required="false" type="boolean"
defaultValue="false"
description="Generate String constants as char arrays."/>
- <c:simple-property name="error-on-use-bean-invalid-class-attribute" required="false" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="error-on-use-bean-invalid-class-attribute" required="false" type="boolean" defaultValue="false"
description="Enable errors when using a bad class in useBean."/>
- <c:simple-property name="scratch-dir" required="false" type="string" readOnly="true" description="Specify a different work directory."/>
- <c:simple-property name="source-vm" required="false" type="string" readOnly="true" defaultValue="1.5"
+ <c:simple-property name="scratch-dir" required="false" type="string" description="Specify a different work directory."/>
+ <c:simple-property name="source-vm" required="false" type="string" defaultValue="1.5"
description="Source VM level for compilation."/>
- <c:simple-property name="target-vm" required="false" type="string" readOnly="true" defaultValue="1.5"
+ <c:simple-property name="target-vm" required="false" type="string" defaultValue="1.5"
description="Target VM level for compilation."/>
- <c:simple-property name="java-encoding" required="false" type="string" readOnly="true" defaultValue="UTF-8"
+ <c:simple-property name="java-encoding" required="false" type="string" defaultValue="UTF-8"
description="Specify the encoding used for Java sources."/>
- <c:simple-property name="x-powered-by" required="false" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="x-powered-by" required="false" type="boolean" defaultValue="true"
description="Enable advertising the JSP engine in x-powered-by."/>
- <c:simple-property name="display-source-fragment" required="false" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="display-source-fragment" required="false" type="boolean" defaultValue="true"
description="When a runtime error occurs, attempts to display corresponding JSP source fragment."/>
- </c:map-property>
+ </c:group>
+ <!-- <c:group name="child:configuration=container" displayName="Container">
<c:list-property name="mime-mapping" description="A mime-mapping definition." >
<c:map-property name="mime-mapping" >
<c:simple-property name="name" description="A MIME mapping name"/>
@@ -713,8 +801,8 @@
<c:list-property name="welcome-file" description="A welcome file declaration." >
<c:simple-property name="welcome-file" />
</c:list-property>
- </c:map-property>
- </resource-configuration>
+ </c:group>
+--> </resource-configuration>
<service name="Connector"
discovery="SubsystemDiscovery"
@@ -726,41 +814,41 @@
</plugin-configuration>
- <metric property="bytesSent" measurementType="trendsup"/>
- <metric property="bytesReceived" measurementType="trendsup"/>
- <metric property="processingTime" measurementType="trendsup" units="milliseconds"/>
- <metric property="errorCount" measurementType="trendsup" displayType="summary"/>
- <metric property="maxTime" units="milliseconds"/>
- <metric property="requestCount" measurementType="trendsup" displayType="summary"/>
+ <metric property="bytesSent" measurementType="trendsup" description="Number of byte sent by the connector."/>
+ <metric property="bytesReceived" measurementType="trendsup" description="Number of byte received by the connector (POST data)."/>
+ <metric property="processingTime" measurementType="trendsup" units="milliseconds" description="Processing time used by the connector. Im milli-seconds."/>
+ <metric property="errorCount" measurementType="trendsup" displayType="summary" description="Number of error that occurs when processing requests by the connector."/>
+ <metric property="maxTime" units="milliseconds" description="Max time spent to process a requests."/>
+ <metric property="requestCount" measurementType="trendsup" displayType="summary" description="Number of the request processed by the connector."/>
<resource-configuration>
- <c:simple-property name="protocol" required="true" type="string" readOnly="true" description="The web connector protocol."/>
- <c:simple-property name="socket-binding" required="true" type="string" readOnly="true"
+ <c:simple-property name="protocol" required="true" type="string" description="The web connector protocol."/>
+ <c:simple-property name="socket-binding" required="true" type="string"
description="The web connector socket-binding reference, this connector should be bound to.">
<c:option-source target="configuration" expression="socket-binding=name:type=SocketBindingGroup"/> <!-- TODO different for Domain vs standalone -->
</c:simple-property>
- <c:simple-property name="scheme" type="string" readOnly="true" default="http" description="The web connector scheme." required="true"/>
- <c:simple-property name="executor" type="string" readOnly="true" required="false"
+ <c:simple-property name="scheme" type="string" default="http" description="The web connector scheme." required="true"/>
+ <c:simple-property name="executor" type="string" required="false"
description="The name of the executor that should be used for the processing threads of this connector. Defaults to using an internal pool."/>
- <c:simple-property name="enabled" type="boolean" readOnly="true" defaultValue="true"
+ <c:simple-property name="enabled" type="boolean" default="true"
description="Defines whether the connector should be started on startup."/>
- <c:simple-property name="enable-lookups" type="boolean" readOnly="true" defaultValue="false"
+ <c:simple-property name="enable-lookups" type="boolean" defaultValue="false"
description="Enable DNS lookups for Servlet API."/>
- <c:simple-property name="proxy-name" type="string" readOnly="true" required="false"
+ <c:simple-property name="proxy-name" type="string" required="false"
description="The host name that will be used when sending a redirect. The default value is null."/>
- <c:simple-property name="proxy-port" type="integer" readOnly="true" required="false"
+ <c:simple-property name="proxy-port" type="integer" required="false"
description="The port that will be used when sending a redirect."/>
- <c:simple-property name="max-post-size" type="integer" readOnly="true" defaultValue="2097152"
+ <c:simple-property name="max-post-size" type="integer" defaultValue="2097152"
description="Maximum size in bytes of a POST request that can be parsed by the container."/>
- <c:simple-property name="max-save-post-size" type="integer" readOnly="true" defaultValue="4096"
+ <c:simple-property name="max-save-post-size" type="integer" defaultValue="4096"
description="Maximum size in bytes of a POST request that will be saved during certain authentication schemes."/>
<c:simple-property name="secure" type="boolean" readOnly="true" defaultValue="false"
description="Indicates if content sent or recieved by the connector is secured from the user perspective."/>
<c:simple-property name="redirect-port" type="integer" readOnly="true" defaultValue="8443"
description="The port for redirection to a secure connector."/>
- <c:simple-property name="max-connections" type="integer" readOnly="true" required="false"
+ <c:simple-property name="max-connections" type="integer" required="false"
description="Amount of concurrent connections that can be processed by the connector with optimum performance. The default value depends on the connector used."/>
- <c:list-property name="virtual-server" description="The list of virtual servers that can be accessed through this connector. The default is to allow all virtual servers." readOnly="true" required="false">
+ <c:list-property name="virtual-server" description="The list of virtual servers that can be accessed through this connector. The default is to allow all virtual servers." required="false">
<c:simple-property name="virtual-server" />
</c:list-property>
<c:map-property name="ssl" description="The SSL configuration of the connector." readOnly="true" required="false">
@@ -795,10 +883,10 @@
</plugin-configuration>
<resource-configuration>
- <c:list-property name="alias" >
+ <c:list-property name="alias" description="The virtual server aliases" displayName="Virtual server aliases" >
<c:simple-property name="alias" />
</c:list-property>
- <c:simple-property name="default-web-module" type="string" readOnly="true" defaultValue="ROOT.war"
+ <c:simple-property name="default-web-module" type="string" defaultValue="ROOT.war"
description="The web module deployment name that will be mapped as the root webapp."/>
<c:map-property name="access-log" description="The access log configuration for this virtual server." >
<c:simple-property name="pattern" type="string" readOnly="true" defaultValue="common" required="false" description="The access log pattern."/>
@@ -825,7 +913,7 @@
</c:list-property>
</c:map-property>
</c:list-property>
- <c:simple-property name="enable-welcome-root" type="boolean" />
+ <c:simple-property name="enable-welcome-root" type="boolean" description="Whether or not the bundled welcome directory is used as the root web context."/>
</resource-configuration>
</service>
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 16c94f9..0266071 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
@@ -28,7 +28,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.testng.annotations.BeforeSuite;
import org.rhq.core.clientapi.agent.metadata.ConfigurationMetadataParser;
import org.rhq.core.clientapi.agent.metadata.InvalidPluginDescriptorException;
@@ -97,7 +96,7 @@ public class AbstractConfigurationHandlingTest {
JsonNode content;
public FakeConnection() {
- super("localhost", 1234);
+ super("localhost", 1234, "fake", "fake");
}
public void setContent(JsonNode content) {
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
index d021ab2..a512133 100644
--- a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/ConfigurationUpdatingTest.java
@@ -62,7 +62,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(new PropertySimple("needed","test"));
conf.put(new PropertySimple("optional",null));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1;
Operation step1 = cop.step(0);
@@ -89,7 +89,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -120,7 +120,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -148,7 +148,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -176,7 +176,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyMap);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -207,7 +207,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 1 : "#Steps should be 1 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -240,7 +240,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
conf.put(new PropertySimple("port-offset",0));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 3 : "#Steps should be 3 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
@@ -289,7 +289,7 @@ public class ConfigurationUpdatingTest extends AbstractConfigurationHandlingTest
conf.put(propertyList);
conf.put(new PropertySimple("port-offset",0));
- CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf);
+ CompositeOperation cop = delegate.updateGenerateOperationFromProperties(conf, null);
assert cop.numberOfSteps() == 5 : "#Steps should be 5 but were " + cop.numberOfSteps();
Operation step1 = cop.step(0);
diff --git a/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/XmlFileReadingTest.java b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/XmlFileReadingTest.java
new file mode 100644
index 0000000..2365d19
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/java/org/rhq/modules/plugins/jbossas7/XmlFileReadingTest.java
@@ -0,0 +1,133 @@
+package org.rhq.modules.plugins.jbossas7;
+
+import java.net.URL;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test the ability to read information from the AS7 xml files (standalone.xml and so on)
+ * @author Heiko W. Rupp
+ */
+@Test
+public class XmlFileReadingTest {
+
+ public void hostPort70() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("standalone70.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ AbstractBaseDiscovery.HostPort hp = bd.getManagementPortFromHostXml(new String[]{});
+ System.out.println(hp);
+ assert hp.host.equals("127.0.0.70") : "Host is " + hp.host;
+ assert hp.port==19990 : "Port is " + hp.port;
+ }
+
+ public void hostPort71() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("standalone71.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ AbstractBaseDiscovery.HostPort hp = bd.getManagementPortFromHostXml(new String[]{});
+ System.out.println(hp);
+ // hp : HostPort{host='localhost', port=9990, isLocal=true}
+ assert hp.host.equals("127.0.0.71") : "Host is " + hp.host;
+ assert hp.port==29990 : "Port is " + hp.port;
+ }
+
+ public void domainController1() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("host1.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ AbstractBaseDiscovery.HostPort hp = bd.getDomainControllerFromHostXml();
+ assert hp.isLocal : "DC is not local as expected: " + hp;
+
+ }
+
+ public void domainController2() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("host2.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ AbstractBaseDiscovery.HostPort hp = bd.getDomainControllerFromHostXml();
+ assert "192.168.100.1".equals(hp.host) : "DC is at " + hp.host;
+ assert hp.port == 9559 : "DC port is at " + hp.port;
+ }
+
+
+
+ public void testXpath70() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("standalone70.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+/*
+ String realm = bd.obtainXmlPropertyViaXPath("/management/management-interfaces/http-interface/@security-realm");
+ assert "ManagementRealm".equals(realm) : "Realm was " + realm;
+*/
+
+ String pathExpr = "//management/management-interfaces/http-interface/@port";
+ String port = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "19990".equals(port) : "Port was [" + port + "]";
+
+ pathExpr = "//management/management-interfaces/http-interface/@interface";
+ String interfName = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "management".equals(interfName) : "Interface was " + interfName;
+
+ pathExpr = "/server/interfaces/interface[@name='" + interfName + "']/inet-address/@value";
+ String interfElem = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "${jboss.bind.address.management:127.0.0.70}".equals(interfElem) : "InterfElem was " + interfElem;
+
+ }
+
+
+ public void testXpath71() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("standalone71.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ String realm = bd.obtainXmlPropertyViaXPath("//management/management-interfaces/http-interface/@security-realm");
+ assert "ManagementRealm".equals(realm) : "Realm was " + realm;
+ String sbindingRef = bd.obtainXmlPropertyViaXPath(
+ ("//management/management-interfaces/http-interface/socket-binding/@http"));
+ assert "management-http".equals(sbindingRef): "Socketbinding was " + sbindingRef;
+
+ String pathExpr = "/server/socket-binding-group/socket-binding[@name='" + sbindingRef + "']/@port";
+ String port = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "29990".equals(port) : "Port was [" + port + "]";
+
+ pathExpr = "/server/socket-binding-group/socket-binding[@name='" + sbindingRef + "']/@interface";
+ String interfName = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "management".equals(interfName) : "Interface was " + interfName;
+
+ pathExpr = "/server/interfaces/interface[@name='" + interfName + "']/inet-address/@value";
+ String interfElem = bd.obtainXmlPropertyViaXPath(pathExpr);
+ assert "${jboss.bind.address.management:127.0.0.71}".equals(interfElem) : "InterfElem was " + interfElem;
+
+ }
+
+ public void testGetRealm() throws Exception {
+
+ BaseProcessDiscovery bd = new BaseProcessDiscovery();
+ URL url = getClass().getClassLoader().getResource("standalone71.xml");
+ bd.readStandaloneOrHostXmlFromFile(url.getFile());
+
+ String realm = bd.obtainXmlPropertyViaXPath("//management/management-interfaces/http-interface/@security-realm");
+ assert "ManagementRealm".equals(realm) : "Realm was " + realm;
+
+ String xpathExpression = "//management//security-realm[@name ='%s']/authentication/properties/@path";
+
+ String propsFileName = bd.obtainXmlPropertyViaXPath(String.format(xpathExpression,realm));
+ assert "mgmt-users.properties".equals(propsFileName) : "File name was " + propsFileName;
+
+ String propsFilePathRel = bd.obtainXmlPropertyViaXPath("//management//security-realm[@name ='" + realm + "']/authentication/properties/@relative-to");
+ assert "jboss.server.config.dir".equals(propsFilePathRel) : "Path was " + propsFileName;
+
+ }
+}
diff --git a/modules/plugins/jboss-as-7/src/test/resources/host1.xml b/modules/plugins/jboss-as-7/src/test/resources/host1.xml
new file mode 100644
index 0000000..2e35b78
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/host1.xml
@@ -0,0 +1,92 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software 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
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<host xmlns="urn:jboss:domain:1.1"
+ name="master">
+
+ <management>
+ <security-realms>
+ <security-realm name="ManagementRealm">
+ <authentication>
+ <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
+ </authentication>
+ </security-realm>
+ </security-realms>
+ <management-interfaces>
+ <native-interface security-realm="ManagementRealm">
+ <socket interface="management" port="9999"/>
+ </native-interface>
+ <http-interface security-realm="ManagementRealm">
+ <socket interface="management" port="9990"/>
+ </http-interface>
+ </management-interfaces>
+ </management>
+
+ <domain-controller>
+ <local/>
+ <!-- Alternative remote domain controller configuration with a host and port -->
+ <!-- <remote host="192.168.100.1" port="9999"/> -->
+ </domain-controller>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+ </interface>
+ </interfaces>
+
+ <jvms>
+ <jvm name="default">
+ <heap size="64m" max-size="128m"/>
+ </jvm>
+ </jvms>
+
+ <servers>
+ <server name="server-one" group="main-server-group">
+ <!-- server-one inherits the default socket-group declared in the server-group -->
+ <jvm name="default">
+ <!-- Remote JPDA debugging for a specific server
+ <jvm-options>
+ <option value="-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n"/>
+ </jvm-options>
+ -->
+ </jvm>
+ </server>
+
+ <server name="server-two" group="main-server-group" auto-start="true">
+ <!-- server-two avoids port conflicts by incrementing the ports in
+ the default socket-group declared in the server-group -->
+ <socket-binding-group ref="standard-sockets" port-offset="150"/>
+ <jvm name="default">
+ <heap size="64m" max-size="256m"/>
+ </jvm>
+ </server>
+
+ <server name="server-three" group="other-server-group" auto-start="false">
+ <!-- server-three avoids port conflicts by incrementing the ports in
+ the default socket-group declared in the server-group -->
+ <socket-binding-group ref="ha-sockets" port-offset="250"/>
+ </server>
+ </servers>
+</host>
diff --git a/modules/plugins/jboss-as-7/src/test/resources/host2.xml b/modules/plugins/jboss-as-7/src/test/resources/host2.xml
new file mode 100644
index 0000000..38ada1a
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/host2.xml
@@ -0,0 +1,91 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software 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
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<host xmlns="urn:jboss:domain:1.1"
+ name="master">
+
+ <management>
+ <security-realms>
+ <security-realm name="ManagementRealm">
+ <authentication>
+ <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
+ </authentication>
+ </security-realm>
+ </security-realms>
+ <management-interfaces>
+ <native-interface security-realm="ManagementRealm">
+ <socket interface="management" port="9999"/>
+ </native-interface>
+ <http-interface security-realm="ManagementRealm">
+ <socket interface="management" port="9990"/>
+ </http-interface>
+ </management-interfaces>
+ </management>
+
+ <domain-controller>
+ <!-- Alternative remote domain controller configuration with a host and port -->
+ <remote host="192.168.100.1" port="9559"/>
+ </domain-controller>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+ </interface>
+ </interfaces>
+
+ <jvms>
+ <jvm name="default">
+ <heap size="64m" max-size="128m"/>
+ </jvm>
+ </jvms>
+
+ <servers>
+ <server name="server-one" group="main-server-group">
+ <!-- server-one inherits the default socket-group declared in the server-group -->
+ <jvm name="default">
+ <!-- Remote JPDA debugging for a specific server
+ <jvm-options>
+ <option value="-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n"/>
+ </jvm-options>
+ -->
+ </jvm>
+ </server>
+
+ <server name="server-two" group="main-server-group" auto-start="true">
+ <!-- server-two avoids port conflicts by incrementing the ports in
+ the default socket-group declared in the server-group -->
+ <socket-binding-group ref="standard-sockets" port-offset="150"/>
+ <jvm name="default">
+ <heap size="64m" max-size="256m"/>
+ </jvm>
+ </server>
+
+ <server name="server-three" group="other-server-group" auto-start="false">
+ <!-- server-three avoids port conflicts by incrementing the ports in
+ the default socket-group declared in the server-group -->
+ <socket-binding-group ref="ha-sockets" port-offset="250"/>
+ </server>
+ </servers>
+</host>
diff --git a/modules/plugins/jboss-as-7/src/test/resources/standalone70.xml b/modules/plugins/jboss-as-7/src/test/resources/standalone70.xml
new file mode 100644
index 0000000..e07b9ef
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/standalone70.xml
@@ -0,0 +1,433 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software 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
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<server xmlns="urn:jboss:domain:1.1">
+
+ <extensions>
+ <extension module="org.jboss.as.clustering.infinispan"/>
+ <extension module="org.jboss.as.connector"/>
+ <extension module="org.jboss.as.deployment-scanner"/>
+ <extension module="org.jboss.as.ee"/>
+ <extension module="org.jboss.as.ejb3"/>
+ <extension module="org.jboss.as.jacorb"/>
+ <extension module="org.jboss.as.jaxrs"/>
+ <extension module="org.jboss.as.jmx"/>
+ <extension module="org.jboss.as.jpa"/>
+ <extension module="org.jboss.as.logging"/>
+ <extension module="org.jboss.as.mail"/>
+ <extension module="org.jboss.as.messaging"/>
+ <extension module="org.jboss.as.naming"/>
+ <extension module="org.jboss.as.osgi"/>
+ <extension module="org.jboss.as.remoting"/>
+ <extension module="org.jboss.as.sar"/>
+ <extension module="org.jboss.as.security"/>
+ <extension module="org.jboss.as.threads"/>
+ <extension module="org.jboss.as.transactions"/>
+ <extension module="org.jboss.as.web"/>
+ <extension module="org.jboss.as.webservices"/>
+ <extension module="org.jboss.as.weld"/>
+ </extensions>
+
+ <management>
+ <security-realms>
+ <security-realm name="PropertiesMgmtSecurityRealm">
+ <authentication>
+ <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ </security-realm>
+ </security-realms>
+ <management-interfaces>
+ <native-interface interface="management" port="9999"/>
+ <http-interface interface="management" port="19990"/>
+ </management-interfaces>
+ </management>
+
+ <profile>
+ <subsystem xmlns="urn:jboss:domain:logging:1.1">
+ <console-handler name="CONSOLE">
+ <level name="INFO"/>
+ <formatter>
+ <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
+ </formatter>
+ </console-handler>
+
+ <periodic-rotating-file-handler name="FILE">
+ <level name="INFO"/>
+ <formatter>
+ <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
+ </formatter>
+ <file relative-to="jboss.server.log.dir" path="server.log"/>
+ <suffix value=".yyyy-MM-dd"/>
+ </periodic-rotating-file-handler>
+
+ <logger category="com.arjuna">
+ <level name="WARN"/>
+ </logger>
+ <logger category="org.apache.tomcat.util.modeler">
+ <level name="WARN"/>
+ </logger>
+ <logger category="sun.rmi">
+ <level name="WARN"/>
+ </logger>
+ <logger category="jacorb">
+ <level name="WARN"/>
+ </logger>
+ <!-- set jacorb.config to ERROR to avoid the "jacorb.properties not found" messages during startup -->
+ <logger category="jacorb.config">
+ <level name="ERROR"/>
+ </logger>
+
+ <root-logger>
+ <level name="INFO"/>
+ <handlers>
+ <handler name="CONSOLE"/>
+ <handler name="FILE"/>
+ </handlers>
+ </root-logger>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:datasources:1.0">
+ <datasources>
+ <datasource jndi-name="java:jboss/datasources/ExampleDS" enabled="true" use-java-context="true"
+ pool-name="H2DS">
+ <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
+ <driver>h2</driver>
+ <pool></pool>
+ <security>
+ <user-name>sa</user-name>
+ <password>sa</password>
+ </security>
+ </datasource>
+ <drivers>
+ <driver name="h2" module="com.h2database.h2">
+ <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
+ </driver>
+ </drivers>
+ </datasources>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:deployment-scanner:1.0">
+ <deployment-scanner scan-interval="5000" relative-to="jboss.server.base.dir" path="deployments"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:ee:1.0" />
+ <subsystem xmlns="urn:jboss:domain:ejb3:1.2" >
+
+ <remote connector-ref="remoting-connector" thread-pool-name="default" />
+ <async thread-pool-name="default" />
+
+ <timer-service thread-pool-name="default" >
+ <data-store path="timer-service-data" relative-to="jboss.server.data.dir"/>
+ </timer-service>
+
+ <!-- EJB3 pools -->
+ <pools>
+ <bean-instance-pools>
+ <strict-max-pool name="slsb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5"
+ instance-acquisition-timeout-unit="MINUTES"/>
+
+ <strict-max-pool name="mdb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5"
+ instance-acquisition-timeout-unit="MINUTES"/>
+ </bean-instance-pools>
+ </pools>
+
+ <!-- Default MDB configurations -->
+ <mdb>
+ <resource-adapter-ref resource-adapter-name="hornetq-ra"/>
+ <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
+ </mdb>
+
+ <!-- Session bean configurations -->
+ <session-bean>
+ <stateless>
+ <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
+ </stateless>
+ </session-bean>
+
+ <default-stateful-access-timeout>5000</default-stateful-access-timeout>
+ <default-singleton-access-timeout>5000</default-singleton-access-timeout>
+
+ <thread-pools>
+ <thread-pool name="default" max-threads="10" keepalive-time="100" />
+ </thread-pools>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:infinispan:1.0" default-cache-container="hibernate">
+ <cache-container name="hibernate" default-cache="local-query">
+ <local-cache name="entity">
+ <eviction strategy="LRU" max-entries="10000"/>
+ <expiration max-idle="100000"/>
+ </local-cache>
+ <local-cache name="local-query">
+ <eviction strategy="LRU" max-entries="10000"/>
+ <expiration max-idle="100000"/>
+ </local-cache>
+ <local-cache name="timestamps">
+ <eviction strategy="NONE"/>
+ </local-cache>
+ </cache-container>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jacorb:1.0">
+ <orb name="JBoss" print-version="off" giop-minor-version="2">
+ <connection max-managed-buf-size="24" outbuf-cache-timeout="-1"/>
+ <naming root-context="JBoss/Naming/root" export-corbaloc="on"/>
+ </orb>
+ <poa monitoring="off" queue-wait="off">
+ <request-processors pool-size="2" max-threads="8"/>
+ </poa>
+ <interop sun="on" chunk-custom-rmi-valuetypes="on" strict-check-on-tc-creation="off"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:jca:1.0">
+ <archive-validation enabled="false"/>
+ <bean-validation enabled="false"/>
+ <default-workmanager>
+ <short-running-threads blocking="true">
+ <core-threads count="10" per-cpu="20"/>
+ <queue-length count="10" per-cpu="20"/>
+ <max-threads count="10" per-cpu="20"/>
+ <keepalive-time time="10" unit="seconds"/>
+ </short-running-threads>
+ <long-running-threads blocking="true">
+ <core-threads count="10" per-cpu="20"/>
+ <queue-length count="10" per-cpu="20"/>
+ <max-threads count="10" per-cpu="20"/>
+ <keepalive-time time="10" unit="seconds"/>
+ </long-running-threads>
+ </default-workmanager>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jmx:1.1" show-model="true">
+ <jmx-connector registry-binding="jmx-connector-registry" server-binding="jmx-connector-server" />
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jpa:1.0">
+ <jpa default-datasource=""/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:mail:1.0">
+ <mail-session jndi-name="java:jboss/mail/Default">
+ <smtp-server address="localhost" port="25"/>
+ </mail-session>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:messaging:1.1">
+ <hornetq-server>
+ <!-- Default journal file size is 10Mb, reduced here to 100k for faster first boot -->
+ <journal-file-size>102400</journal-file-size>
+ <journal-min-files>2</journal-min-files>
+ <journal-type>NIO</journal-type>
+ <!-- disable messaging persistence -->
+ <persistence-enabled>false</persistence-enabled>
+
+ <connectors>
+ <netty-connector name="netty" socket-binding="messaging"/>
+ <netty-connector name="netty-throughput" socket-binding="messaging-throughput">
+ <param key="batch-delay" value="50"/>
+ </netty-connector>
+ <in-vm-connector name="in-vm" server-id="0"/>
+ </connectors>
+
+ <acceptors>
+ <netty-acceptor name="netty" socket-binding="messaging"/>
+ <netty-acceptor name="netty-throughput" socket-binding="messaging-throughput">
+ <param key="batch-delay" value="50"/>
+ <param key="direct-deliver" value="false"/>
+ </netty-acceptor>
+ <in-vm-acceptor name="in-vm" server-id="0"/>
+ </acceptors>
+
+ <security-settings>
+ <security-setting match="#">
+ <permission type="createNonDurableQueue" roles="guest"/>
+ <permission type="deleteNonDurableQueue" roles="guest"/>
+ <permission type="consume" roles="guest"/>
+ <permission type="send" roles="guest"/>
+ </security-setting>
+ </security-settings>
+
+ <address-settings>
+ <!--default for catch all-->
+ <address-setting match="#">
+ <dead-letter-address>jms.queue.DLQ</dead-letter-address>
+ <expiry-address>jms.queue.ExpiryQueue</expiry-address>
+ <redelivery-delay>0</redelivery-delay>
+ <max-size-bytes>10485760</max-size-bytes>
+ <message-counter-history-day-limit>10</message-counter-history-day-limit>
+ <address-full-policy>BLOCK</address-full-policy>
+ </address-setting>
+ </address-settings>
+
+ <!--JMS Stuff-->
+ <jms-connection-factories>
+ <connection-factory name="InVmConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="in-vm"/>
+ </connectors>
+ <entries>
+ <entry name="java:/ConnectionFactory"/>
+ </entries>
+ </connection-factory>
+ <connection-factory name="RemoteConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="RemoteConnectionFactory"/>
+ </entries>
+ </connection-factory>
+ <pooled-connection-factory name="hornetq-ra">
+ <transaction mode="xa"/>
+ <connectors>
+ <connector-ref connector-name="in-vm"/>
+ </connectors>
+ <entries>
+ <entry name="java:/JmsXA"/>
+ </entries>
+ </pooled-connection-factory>
+ </jms-connection-factories>
+
+ <jms-destinations>
+ <jms-queue name="testQueue">
+ <entry name="queue/test"/>
+ </jms-queue>
+ <jms-topic name="testTopic">
+ <entry name="topic/test"/>
+ </jms-topic>
+ </jms-destinations>
+ </hornetq-server>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:naming:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:osgi:1.1" activation="lazy">
+ <configuration pid="org.apache.felix.webconsole.internal.servlet.OsgiManager">
+ <property name="manager.root" value="jboss-osgi"/>
+ </configuration>
+ <properties>
+ <!-- Specifies the beginning start level of the framework -->
+ <property name="org.osgi.framework.startlevel.beginning">1</property>
+ </properties>
+ <capabilities>
+ <!-- modules registered with the OSGi layer on startup -->
+ <capability name="javax.api"/>
+ <capability name="javax.servlet.api"/>
+ <capability name="javax.transaction.api"/>
+ <!-- bundles installed on startup -->
+ <capability name="org.apache.aries.util"/>
+ <capability name="org.jboss.osgi.webconsole"/>
+ <capability name="org.osgi.compendium"/>
+ <!-- bundles started in startlevel 1 -->
+ <capability name="org.apache.felix.log" startlevel="1"/>
+ <capability name="org.jboss.osgi.logging" startlevel="1"/>
+ <capability name="org.apache.felix.configadmin" startlevel="1"/>
+ <capability name="org.jboss.as.osgi.configadmin" startlevel="1"/>
+ <!-- bundles started in startlevel 2 -->
+ <capability name="org.apache.aries.jmx" startlevel="2"/>
+ <capability name="org.apache.felix.eventadmin" startlevel="2"/>
+ <capability name="org.apache.felix.metatype" startlevel="2"/>
+ <capability name="org.apache.felix.scr" startlevel="2"/>
+ <capability name="org.apache.felix.webconsole" startlevel="2"/>
+ <capability name="org.jboss.netty" startlevel="2"/>
+ <capability name="org.jboss.osgi.jmx" startlevel="2"/>
+ <capability name="org.jboss.osgi.http" startlevel="2"/>
+ <capability name="org.projectodd.stilts" startlevel="2"/>
+ <!-- bundles started in startlevel 3 -->
+ <capability name="org.jboss.osgi.blueprint" startlevel="3"/>
+ <capability name="org.jboss.osgi.webapp" startlevel="3"/>
+ <capability name="org.jboss.osgi.xerces" startlevel="3"/>
+ </capabilities>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:remoting:1.0">
+ <connector name="remoting-connector" socket-binding="remoting"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0" />
+ <subsystem xmlns="urn:jboss:domain:sar:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:security:1.0">
+ <security-domains>
+ <security-domain name="other" cache-type="default">
+ <authentication>
+ <login-module code="UsersRoles" flag="required"/>
+ </authentication>
+ </security-domain>
+ </security-domains>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:threads:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:transactions:1.0">
+ <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
+ <core-environment>
+ <process-id>
+ <uuid/>
+ </process-id>
+ </core-environment>
+ <coordinator-environment default-timeout="300"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:web:1.0" default-virtual-server="default-host">
+ <connector name="http" scheme="http" protocol="HTTP/1.1" socket-binding="http"/>
+ <virtual-server name="default-host" enable-welcome-root="true">
+ <alias name="localhost"/>
+ <alias name="example.com"/>
+ </virtual-server>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:webservices:1.0">
+ <modify-wsdl-address>true</modify-wsdl-address>
+ <wsdl-host>localhost</wsdl-host>
+ <!--
+ <wsdl-port>8080</wsdl-port>
+ <wsdl-secure-port>8443</wsdl-secure-port>
+ -->
+ <endpoint-config xmlns:ws="urn:jboss:jbossws-jaxws-config:4.0">
+ <ws:config-name>Standard-Endpoint-Config</ws:config-name>
+ </endpoint-config>
+ <endpoint-config xmlns:ws="urn:jboss:jbossws-jaxws-config:4.0">
+ <ws:config-name>Recording-Endpoint-Config</ws:config-name>
+ <ws:pre-handler-chains>
+ <handler-chain xmlns="http://java.sun.com/xml/ns/javaee">
+ <protocol-bindings>##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM
+ </protocol-bindings>
+ <handler>
+ <handler-name>RecordingHandler</handler-name>
+ <handler-class>org.jboss.ws.common.invocation.RecordingServerHandler</handler-class>
+ </handler>
+ </handler-chain>
+ </ws:pre-handler-chains>
+ </endpoint-config>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:weld:1.0"/>
+ </profile>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.70}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.70}"/>
+ </interface>
+ </interfaces>
+
+ <socket-binding-group name="standard-sockets" default-interface="public">
+ <socket-binding name="http" port="8080"/>
+ <socket-binding name="https" port="8443"/>
+ <socket-binding name="jacorb" port="3528"/>
+ <socket-binding name="jacorb-ssl" port="3529"/>
+ <socket-binding name="jmx-connector-registry" interface="management" port="1090"/>
+ <socket-binding name="jmx-connector-server" interface="management" port="1091"/>
+ <socket-binding name="jndi" port="1099"/>
+ <socket-binding name="messaging" port="5445"/>
+ <socket-binding name="messaging-throughput" port="5455"/>
+ <socket-binding name="osgi-http" interface="management" port="8090"/>
+ <socket-binding name="remoting" port="4447"/>
+ <socket-binding name="txn-recovery-environment" port="4712"/>
+ <socket-binding name="txn-status-manager" port="4713"/>
+ </socket-binding-group>
+
+</server>
diff --git a/modules/plugins/jboss-as-7/src/test/resources/standalone71.xml b/modules/plugins/jboss-as-7/src/test/resources/standalone71.xml
new file mode 100644
index 0000000..0de6d00
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/test/resources/standalone71.xml
@@ -0,0 +1,453 @@
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2011, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software 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
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<server xmlns="urn:jboss:domain:1.1">
+
+ <extensions>
+ <extension module="org.jboss.as.clustering.infinispan"/>
+ <extension module="org.jboss.as.cmp"/>
+ <extension module="org.jboss.as.connector"/>
+ <extension module="org.jboss.as.deployment-scanner"/>
+ <extension module="org.jboss.as.ee"/>
+ <extension module="org.jboss.as.ejb3"/>
+ <extension module="org.jboss.as.jacorb"/>
+ <extension module="org.jboss.as.jaxr"/>
+ <extension module="org.jboss.as.jaxrs"/>
+ <extension module="org.jboss.as.jdr"/>
+ <extension module="org.jboss.as.jmx"/>
+ <extension module="org.jboss.as.jpa"/>
+ <extension module="org.jboss.as.logging"/>
+ <extension module="org.jboss.as.mail"/>
+ <extension module="org.jboss.as.messaging"/>
+ <extension module="org.jboss.as.naming"/>
+ <extension module="org.jboss.as.osgi"/>
+ <extension module="org.jboss.as.pojo"/>
+ <extension module="org.jboss.as.remoting"/>
+ <extension module="org.jboss.as.sar"/>
+ <extension module="org.jboss.as.security"/>
+ <extension module="org.jboss.as.threads"/>
+ <extension module="org.jboss.as.transactions"/>
+ <extension module="org.jboss.as.web"/>
+ <extension module="org.jboss.as.webservices"/>
+ <extension module="org.jboss.as.weld"/>
+ </extensions>
+
+ <management>
+ <security-realms>
+ <security-realm name="ManagementRealm">
+ <authentication>
+ <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
+ </authentication>
+ </security-realm>
+ </security-realms>
+ <management-interfaces>
+ <native-interface security-realm="ManagementRealm">
+ <socket-binding native="management-native"/>
+ </native-interface>
+ <http-interface security-realm="ManagementRealm">
+ <socket-binding http="management-http"/>
+ </http-interface>
+ </management-interfaces>
+ </management>
+
+ <profile>
+ <subsystem xmlns="urn:jboss:domain:logging:1.1">
+ <console-handler name="CONSOLE">
+ <level name="INFO"/>
+ <formatter>
+ <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
+ </formatter>
+ </console-handler>
+
+ <periodic-rotating-file-handler name="FILE">
+ <formatter>
+ <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
+ </formatter>
+ <file relative-to="jboss.server.log.dir" path="server.log"/>
+ <suffix value=".yyyy-MM-dd"/>
+ <append value="true"/>
+ </periodic-rotating-file-handler>
+
+ <logger category="com.arjuna">
+ <level name="WARN"/>
+ </logger>
+ <logger category="org.apache.tomcat.util.modeler">
+ <level name="WARN"/>
+ </logger>
+ <logger category="sun.rmi">
+ <level name="WARN"/>
+ </logger>
+ <logger category="jacorb">
+ <level name="WARN"/>
+ </logger>
+ <!-- set jacorb.config to ERROR to avoid the "jacorb.properties not found" messages during startup -->
+ <logger category="jacorb.config">
+ <level name="ERROR"/>
+ </logger>
+
+ <root-logger>
+ <level name="INFO"/>
+ <handlers>
+ <handler name="CONSOLE"/>
+ <handler name="FILE"/>
+ </handlers>
+ </root-logger>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:cmp:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:datasources:1.0">
+ <datasources>
+ <datasource jndi-name="java:jboss/datasources/ExampleDS" enabled="true" use-java-context="true"
+ pool-name="H2DS">
+ <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
+ <driver>h2</driver>
+ <pool></pool>
+ <security>
+ <user-name>sa</user-name>
+ <password>sa</password>
+ </security>
+ </datasource>
+ <drivers>
+ <driver name="h2" module="com.h2database.h2">
+ <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
+ </driver>
+ </drivers>
+ </datasources>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:deployment-scanner:1.0">
+ <deployment-scanner scan-interval="5000" relative-to="jboss.server.base.dir" path="deployments"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:ee:1.0" />
+ <subsystem xmlns="urn:jboss:domain:ejb3:1.2" >
+
+ <remote connector-ref="remoting-connector" thread-pool-name="default" />
+ <async thread-pool-name="default" />
+
+ <timer-service thread-pool-name="default" >
+ <data-store path="timer-service-data" relative-to="jboss.server.data.dir"/>
+ </timer-service>
+
+ <!-- EJB3 pools -->
+ <pools>
+ <bean-instance-pools>
+ <strict-max-pool name="slsb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5"
+ instance-acquisition-timeout-unit="MINUTES"/>
+
+ <strict-max-pool name="mdb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5"
+ instance-acquisition-timeout-unit="MINUTES"/>
+ </bean-instance-pools>
+ </pools>
+
+ <!-- Default MDB configurations -->
+ <mdb>
+ <resource-adapter-ref resource-adapter-name="hornetq-ra"/>
+ <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
+ </mdb>
+
+ <!-- Session bean configurations -->
+ <session-bean>
+ <stateless>
+ <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
+ </stateless>
+ <stateful default-access-timeout="5000"/>
+ <singleton default-access-timeout="5000"/>
+ </session-bean>
+
+ <thread-pools>
+ <thread-pool name="default" max-threads="10" keepalive-time="100" />
+ </thread-pools>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:infinispan:1.0" default-cache-container="hibernate">
+ <cache-container name="hibernate" default-cache="local-query">
+ <local-cache name="entity">
+ <eviction strategy="LRU" max-entries="10000"/>
+ <expiration max-idle="100000"/>
+ </local-cache>
+ <local-cache name="local-query">
+ <eviction strategy="LRU" max-entries="10000"/>
+ <expiration max-idle="100000"/>
+ </local-cache>
+ <local-cache name="timestamps">
+ <eviction strategy="NONE"/>
+ </local-cache>
+ </cache-container>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jacorb:1.1"/>
+ <subsystem xmlns="urn:jboss:domain:jaxr:1.0">
+ <datasource jndi-name="java:jboss/datasources/ExampleDS"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:jca:1.0">
+ <archive-validation enabled="false"/>
+ <bean-validation enabled="false"/>
+ <default-workmanager>
+ <short-running-threads blocking="true">
+ <core-threads count="10" per-cpu="20"/>
+ <queue-length count="10" per-cpu="20"/>
+ <max-threads count="10" per-cpu="20"/>
+ <keepalive-time time="10" unit="seconds"/>
+ </short-running-threads>
+ <long-running-threads blocking="true">
+ <core-threads count="10" per-cpu="20"/>
+ <queue-length count="10" per-cpu="20"/>
+ <max-threads count="10" per-cpu="20"/>
+ <keepalive-time time="10" unit="seconds"/>
+ </long-running-threads>
+ </default-workmanager>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jdr:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:jmx:1.1" show-model="true">
+ <jmx-connector registry-binding="jmx-connector-registry" server-binding="jmx-connector-server" />
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:jpa:1.0">
+ <jpa default-datasource=""/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:mail:1.0">
+ <mail-session jndi-name="java:jboss/mail/Default">
+ <smtp-server address="localhost" port="25"/>
+ </mail-session>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:messaging:1.1">
+ <hornetq-server>
+ <!-- Default journal file size is 10Mb, reduced here to 100k for faster first boot -->
+ <journal-file-size>102400</journal-file-size>
+ <journal-min-files>2</journal-min-files>
+ <!-- disable messaging persistence -->
+ <persistence-enabled>false</persistence-enabled>
+
+ <connectors>
+ <netty-connector name="netty" socket-binding="messaging-client"/>
+ <netty-connector name="netty-throughput" socket-binding="messaging-throughput-client">
+ <param key="batch-delay" value="50"/>
+ </netty-connector>
+ <in-vm-connector name="in-vm" server-id="0"/>
+ </connectors>
+
+ <acceptors>
+ <netty-acceptor name="netty" socket-binding="messaging"/>
+ <netty-acceptor name="netty-throughput" socket-binding="messaging-throughput">
+ <param key="batch-delay" value="50"/>
+ <param key="direct-deliver" value="false"/>
+ </netty-acceptor>
+ <in-vm-acceptor name="in-vm" server-id="0"/>
+ </acceptors>
+
+ <security-settings>
+ <security-setting match="#">
+ <permission type="createNonDurableQueue" roles="guest"/>
+ <permission type="deleteNonDurableQueue" roles="guest"/>
+ <permission type="consume" roles="guest"/>
+ <permission type="send" roles="guest"/>
+ </security-setting>
+ </security-settings>
+
+ <address-settings>
+ <!--default for catch all-->
+ <address-setting match="#">
+ <dead-letter-address>jms.queue.DLQ</dead-letter-address>
+ <expiry-address>jms.queue.ExpiryQueue</expiry-address>
+ <redelivery-delay>0</redelivery-delay>
+ <max-size-bytes>10485760</max-size-bytes>
+ <message-counter-history-day-limit>10</message-counter-history-day-limit>
+ <address-full-policy>BLOCK</address-full-policy>
+ </address-setting>
+ </address-settings>
+
+ <!--JMS Stuff-->
+ <jms-connection-factories>
+ <connection-factory name="InVmConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="in-vm"/>
+ </connectors>
+ <entries>
+ <entry name="java:/ConnectionFactory"/>
+ </entries>
+ </connection-factory>
+ <connection-factory name="RemoteConnectionFactory">
+ <connectors>
+ <connector-ref connector-name="netty"/>
+ </connectors>
+ <entries>
+ <entry name="RemoteConnectionFactory"/>
+ </entries>
+ </connection-factory>
+ <pooled-connection-factory name="hornetq-ra">
+ <transaction mode="xa"/>
+ <connectors>
+ <connector-ref connector-name="in-vm"/>
+ </connectors>
+ <entries>
+ <entry name="java:/JmsXA"/>
+ </entries>
+ </pooled-connection-factory>
+ </jms-connection-factories>
+
+ <jms-destinations>
+ <jms-queue name="testQueue">
+ <entry name="queue/test"/>
+ </jms-queue>
+ <jms-topic name="testTopic">
+ <entry name="topic/test"/>
+ </jms-topic>
+ </jms-destinations>
+ </hornetq-server>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:naming:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:osgi:1.1" activation="lazy">
+ <configuration pid="org.apache.felix.webconsole.internal.servlet.OsgiManager">
+ <property name="manager.root" value="jboss-osgi"/>
+ </configuration>
+ <properties>
+ <!-- Specifies the beginning start level of the framework -->
+ <property name="org.osgi.framework.startlevel.beginning">1</property>
+ </properties>
+ <capabilities>
+ <!-- modules registered with the OSGi layer on startup -->
+ <capability name="javax.api"/>
+ <capability name="javax.servlet.api"/>
+ <capability name="javax.transaction.api"/>
+ <!-- bundles installed on startup -->
+ <capability name="org.apache.aries.util"/>
+ <capability name="org.jboss.osgi.webconsole"/>
+ <capability name="org.osgi.compendium"/>
+ <!-- bundles started in startlevel 1 -->
+ <capability name="org.apache.felix.log" startlevel="1"/>
+ <capability name="org.jboss.osgi.logging" startlevel="1"/>
+ <capability name="org.apache.felix.configadmin" startlevel="1"/>
+ <capability name="org.jboss.as.osgi.configadmin" startlevel="1"/>
+ <!-- bundles started in startlevel 2 -->
+ <capability name="org.apache.aries.jmx" startlevel="2"/>
+ <capability name="org.apache.felix.eventadmin" startlevel="2"/>
+ <capability name="org.apache.felix.metatype" startlevel="2"/>
+ <capability name="org.apache.felix.scr" startlevel="2"/>
+ <capability name="org.apache.felix.webconsole" startlevel="2"/>
+ <capability name="org.jboss.netty" startlevel="2"/>
+ <capability name="org.jboss.osgi.jmx" startlevel="2"/>
+ <capability name="org.jboss.osgi.http" startlevel="2"/>
+ <capability name="org.projectodd.stilts" startlevel="2"/>
+ <!-- bundles started in startlevel 3 -->
+ <capability name="org.jboss.osgi.blueprint" startlevel="3"/>
+ <capability name="org.jboss.osgi.webapp" startlevel="3"/>
+ <capability name="org.jboss.osgi.xerces" startlevel="3"/>
+ </capabilities>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:pojo:1.0" />
+ <subsystem xmlns="urn:jboss:domain:remoting:1.0">
+ <connector name="remoting-connector" socket-binding="remoting"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0" />
+ <subsystem xmlns="urn:jboss:domain:sar:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:security:1.0">
+ <security-domains>
+ <security-domain name="other" cache-type="default">
+ <authentication>
+ <login-module code="UsersRoles" flag="required"/>
+ </authentication>
+ </security-domain>
+ <security-domain name="jboss-web-policy" cache-type="default">
+ <authorization>
+ <policy-module code="Delegating" flag="required"/>
+ </authorization>
+ </security-domain>
+ <security-domain name="jboss-ejb-policy" cache-type="default">
+ <authorization>
+ <policy-module code="Delegating" flag="required"/>
+ </authorization>
+ </security-domain>
+ </security-domains>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:threads:1.0"/>
+ <subsystem xmlns="urn:jboss:domain:transactions:1.1">
+ <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
+ <core-environment>
+ <process-id>
+ <uuid/>
+ </process-id>
+ </core-environment>
+ <coordinator-environment default-timeout="300"/>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:web:1.0" default-virtual-server="default-host">
+ <connector name="http" scheme="http" protocol="HTTP/1.1" socket-binding="http"/>
+ <virtual-server name="default-host" enable-welcome-root="true">
+ <alias name="localhost"/>
+ <alias name="example.com"/>
+ </virtual-server>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:webservices:1.0">
+ <modify-wsdl-address>true</modify-wsdl-address>
+ <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
+ <!--
+ <wsdl-port>8080</wsdl-port>
+ <wsdl-secure-port>8443</wsdl-secure-port>
+ -->
+ <endpoint-config xmlns:ws="urn:jboss:jbossws-jaxws-config:4.0">
+ <ws:config-name>Standard-Endpoint-Config</ws:config-name>
+ </endpoint-config>
+ <endpoint-config xmlns:ws="urn:jboss:jbossws-jaxws-config:4.0">
+ <ws:config-name>Recording-Endpoint-Config</ws:config-name>
+ <ws:pre-handler-chains>
+ <handler-chain xmlns="http://java.sun.com/xml/ns/javaee">
+ <protocol-bindings>##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM
+ </protocol-bindings>
+ <handler>
+ <handler-name>RecordingHandler</handler-name>
+ <handler-class>org.jboss.ws.common.invocation.RecordingServerHandler</handler-class>
+ </handler>
+ </handler-chain>
+ </ws:pre-handler-chains>
+ </endpoint-config>
+ </subsystem>
+ <subsystem xmlns="urn:jboss:domain:weld:1.0"/>
+ </profile>
+
+ <interfaces>
+ <interface name="management">
+ <inet-address value="${jboss.bind.address.management:127.0.0.71}"/>
+ </interface>
+ <interface name="public">
+ <inet-address value="${jboss.bind.address:127.0.0.71}"/>
+ </interface>
+ </interfaces>
+
+ <socket-binding-group name="standard-sockets" default-interface="public">
+ <socket-binding name="http" port="8080"/>
+ <socket-binding name="https" port="8443"/>
+ <socket-binding name="jacorb" port="3528"/>
+ <socket-binding name="jacorb-ssl" port="3529"/>
+ <socket-binding name="jmx-connector-registry" interface="management" port="1090"/>
+ <socket-binding name="jmx-connector-server" interface="management" port="1091"/>
+ <socket-binding name="management-native" interface="management" port="9999"/>
+ <socket-binding name="management-http" interface="management" port="29990"/>
+ <socket-binding name="messaging" port="5445"/>
+ <socket-binding name="messaging-throughput" port="5455"/>
+ <socket-binding name="osgi-http" interface="management" port="8090"/>
+ <socket-binding name="remoting" port="4447"/>
+ <socket-binding name="txn-recovery-environment" port="4712"/>
+ <socket-binding name="txn-status-manager" port="4713"/>
+ <outbound-socket-binding name="messaging-client">
+ <local-destination socket-binding-ref="messaging"/>
+ </outbound-socket-binding>
+ <outbound-socket-binding name="messaging-throughput-client">
+ <local-destination socket-binding-ref="messaging-throughput"/>
+ </outbound-socket-binding>
+ </socket-binding-group>
+
+</server>
commit 846c73c606a445dbe9f4627d28eafc154421eec6
Merge: f2803b9 572db8c
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Dec 19 19:57:58 2011 +0100
Merge branch 'master' into lkrejci/dissalow-alert-scripts-from-accessing-local-slsbs
commit f2803b9046bfe26c9cbc80ec15bd458ac4f46db5
Merge: 8f9acfd 35fcafb
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Dec 19 19:56:15 2011 +0100
Merge branch 'master' into lkrejci/dissalow-alert-scripts-from-accessing-local-slsbs
commit 8f9acfd64f725fb1ce4d1fafb3e44fde57de4b99
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Mon Dec 19 19:55:08 2011 +0100
Revamped the script security to apply the checks at the JNDI lookup level
to support restricting access to EntityManager or a datasource.
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index 6932b60..4dfd109 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -93,6 +93,13 @@
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>hibernate</groupId>
<artifactId>hibernate3</artifactId>
<!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
index 9c9d1bb..dc1fc83 100644
--- a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
+++ b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
@@ -22,9 +22,6 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.SerializablePermission;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.security.PermissionCollection;
import java.util.Collections;
@@ -41,9 +38,9 @@ import org.rhq.bindings.StandardScriptPermissions;
import org.rhq.bindings.util.PackageFinder;
import org.rhq.core.domain.auth.Subject;
import org.rhq.enterprise.client.LocalClient;
-import org.rhq.enterprise.server.security.AllowEjbAccessPermission;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
/**
*
@@ -78,7 +75,7 @@ public class EjbAccessTest extends AbstractEJB3Test {
Assert.fail("The script shouldn't have been able to call local SLSB method.");
} catch (ScriptException e) {
- assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ checkIsDesiredSecurityException(e);
}
}
@@ -95,66 +92,34 @@ public class EjbAccessTest extends AbstractEJB3Test {
Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
} catch (ScriptException e) {
- //TODO java.io.IOException: access denied (java.io.SerializablePermission enableSubclassImplementation)
- assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ checkIsDesiredSecurityException(e);
}
}
- public void testScriptCantUseSessionManager() throws ScriptException, IOException {
- Subject overlord = LookupUtil.getSubjectManager().getOverlord();
-
- ScriptEngine engine = getEngine(overlord);
-
- try {
- engine.eval("org.rhq.enterprise.server.auth.SessionManager.getInstance();");
-
- Assert.fail("The script shouldn't have been able to get instance of SessionManager.");
- } catch (ScriptException e) {
- assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
- }
- }
-
- @SuppressWarnings("unused")
public void testScriptCantUseSessionManagerMethods() throws Exception {
- //The code below cannot work in Rhino because as of now, Rhino modifies
- //the return value of Class.getDeclaredField() to be null when there
- //is a security manager installed.
- //This has been filed as a bug at Oracle (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7119959)
-
- if (true) {
- return;
- }
-
Subject overlord = LookupUtil.getSubjectManager().getOverlord();
final ScriptEngine engine = getEngine(overlord);
class G {
- private String obtainSessionManagerUsingReflection = ""
- + "var sessionManagerClass = java.lang.Class.forName(\"org.rhq.enterprise.server.auth.SessionManager\");\n"
- + "println(sessionManagerClass);\n"
- + "var managerField = sessionManagerClass.getDeclaredField(\"_manager\");\n"
- + "println(managerField);\n"
- + "managerField.setAccessible(true);\n"
- + "var manager = managerField.get(null);\n"
- + "println(manager);\n"
- + "manager.";
+ private String sessionManager = ""
+ + "org.rhq.enterprise.server.auth.SessionManager.getInstance().";
public void testInvoke(String methodCall) throws ScriptException {
- String code = obtainSessionManagerUsingReflection + methodCall;
+ String code = sessionManager + methodCall;
try {
engine.eval(code);
- Assert.fail("The script shouldn't have been able to a method on a SessionManager.");
+ Assert.fail("The script shouldn't have been able to call a method on a SessionManager: " + methodCall);
} catch (ScriptException e) {
- assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ checkIsDesiredSecurityException(e);
}
}
};
G manager = new G();
- manager.testInvoke("getLastAccess(0);");
+ manager.testInvoke("getlastAccess(0);");
manager.testInvoke("getOverlord()");
manager.testInvoke("getSubject(2);");
manager.testInvoke("invalidate(0);");
@@ -163,6 +128,57 @@ public class EjbAccessTest extends AbstractEJB3Test {
manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
}
+ public void testScriptCantObtainRawJDBCConnectionsWithoutCredentials() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "datasource = context.lookup('java:/RHQDS');\n"
+ + "con = datasource.getConnection();");
+
+ Assert.fail("The script shouldn't have been able to obtain the datasource from the JNDI.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
+ public void testScriptCantUseEntityManager() throws Exception {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+
+ //try harder with manually specifying the initial context factory
+ try {
+ engine.eval(""
+ + "env = new java.util.Hashtable();"
+ + "env.put('java.naming.factory.initial', 'org.jnp.interfaces.LocalOnlyContextFactory');"
+ + "env.put('java.naming.factory.url.pkgs', 'org.jboss.naming:org.jnp.interfaces');"
+ + "context = new javax.naming.InitialContext(env);\n"
+ + "entityManagerFactory = context.lookup('java:/RHQEntityManagerFactory');\n"
+ + "entityManager = entityManagerFactory.createEntityManager();\n"
+ + "entityManager.find(java.lang.Class.forName('org.rhq.core.domain.resource.Resource'), java.lang.Integer.valueOf('10001'));");
+
+ Assert.fail("The script shouldn't have been able to use the EntityManager even using custom initial context factory.");
+ } catch (ScriptException e) {
+ checkIsDesiredSecurityException(e);
+ }
+ }
+
private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
@@ -172,4 +188,11 @@ public class EjbAccessTest extends AbstractEJB3Test {
return new SandboxedScriptEngine(engine, perms);
}
+
+ private static void checkIsDesiredSecurityException(ScriptException e) {
+ String message = e.getMessage();
+ String permissionTrace = AllowRhqServerInternalsAccessPermission.class.getName();
+
+ Assert.assertTrue(message.contains(permissionTrace), "The script exception doesn't seem to be caused by the AllowRhqServerInternalsAccessPermission security exception. " + message);
+ }
}
diff --git a/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml b/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml
deleted file mode 100644
index caa7513..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
- version="3.0">
-
- <description>RHQ</description>
- <display-name>RHQ</display-name>
-
- <assembly-descriptor>
-
- <!-- This interceptor checks that the alert CLI scripts don't try to circumvent our access objects by accessing the local SLSB beans directly. -->
- <interceptor-binding>
- <ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.server.security.AllowEjbAccessInterceptor</interceptor-class>
- </interceptor-binding>
-
- <!-- all our EJB3 SLSBs can define custom @RequiredPermissions annotations for authorization checks-->
- <interceptor-binding>
- <ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.server.authz.RequiredPermissionsInterceptor</interceptor-class>
- </interceptor-binding>
- <interceptor-binding>
- <ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.server.common.TransactionInterruptInterceptor</interceptor-class>
- </interceptor-binding>
- <interceptor-binding>
- <ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.server.common.PerformanceMonitorInterceptor</interceptor-class>
- </interceptor-binding>
-
- </assembly-descriptor>
-
-</ejb-jar>
diff --git a/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml b/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml
deleted file mode 100644
index b7c5c66..0000000
--- a/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml
+++ /dev/null
@@ -1,168 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<jboss xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
- version="3.0">
-
- <enterprise-beans>
-
- <!--
- The AlertConditionLogManagerBean, AlertConditionManagerBean, AlertDampeningManagerBean,
- AlertDefinitionManagerBean, AlertManagerBean, AuthorizationManagerBean, CachedConditionManagerBean, and
- SubjectManager SLSB's are all invoked, either directly or indirectly, by the AlertConditionConsumerBean MDB.
- Since MDB invocations are always done in new threads, using the default SLSB pool impl (ThreadlocalPool) would
- cause a new instance of these SLSB's to be created every time they were invoked by AlertConditionConsumerBean.
- This would be bad if only because existing instances would
- not be reused, but it is really bad because the instances would also never get destroyed, causing heap space to
- gradually leak until the Server eventually ran out of memory. Hence, we must use a StrictMaxPool, which
- will use a fixed pool of instances of this SLSB, instead of a ThreadlocalPool. Because lots of alert
- definitions could result in many concurrent calls to AlertConditionConsumerBean, and because most of these
- SLSB's are also invoked by other callers (i.e. Agents, GUI's, or CLI's), we set the max pool size to 100 to
- minimize the chances of AlertConditionConsumerBean invocations, which are the most critical, from having to
- block and potentially getting backed up in the queue. We set the pool timeout extremely high to essentially
- prevent queued callers from timing out. Note, MDB's are configured in ejb3-interceptors-aop.xml to use a strict
- max pool with a max of 15 and a timeout of 10000, so AlertConditionConsumerBean might become a bottleneck for
- systems with a lot of alerts defined. (ips, 05/10/11)
-
- For more details, see https://bugzilla.redhat.com/show_bug.cgi?id=693232 .
- -->
-
- <session>
- <ejb-name>AlertConditionLogManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>AlertConditionManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>AlertDampeningManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>AlertDefinitionManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>AlertManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>AuthorizationManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>CachedConditionManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>SubjectManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>100</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
-
- <!--
- The CacheConsistencyManagerBean, CloudManagerBean, ServerManagerBean, StatusManagerBean, and SystemManagerBean
- SLSB's are all invoked, either directly or indirectly, by EJB timers. Since EJB timer invocations are always
- done in new threads, using the default SLSB pool impl (ThreadlocalPool) would cause a new instance of this
- SLSB to be created every time it was invoked by an EJB timer. This would be bad if only because an existing
- instance would not be reused, but it is really bad because the instance would also never get destroyed, causing
- heap space to gradually leak until the Server eventually ran out of memory. Hence, we must use a
- StrictMaxPool, which will use a fixed pool of instances of this SLSB, instead of a ThreadlocalPool.
- The timer invocations will only require one or two instances at any given time, but because most of these
- SLSB's are also invoked by other callers (i.e. Agents, GUI's, or CLI's, we set the max pool size to 30, to
- minimize the chances of EJB timer invocations, which are the most critical, from having to block and
- potentially getting backed up in the queue. We set the pool timeout extremely high to essentially prevent
- queued callers from timing out. (ips, 05/10/11)
-
- For more details, see https://bugzilla.redhat.com/show_bug.cgi?id=693232 .
- -->
-
- <session>
- <ejb-name>CacheConsistencyManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>30</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>CloudManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>30</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>ServerManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>30</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>StatusManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>30</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- <session>
- <ejb-name>SystemManagerBean</ejb-name>
- <pool-config>
- <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
- <pool-max-size>30</pool-max-size>
- <pool-timeout>1000000000</pool-timeout>
- </pool-config>
- </session>
-
- </enterprise-beans>
-
-</jboss>
diff --git a/modules/enterprise/server/container-lib/pom.xml b/modules/enterprise/server/container-lib/pom.xml
index b832b06..9d7d603 100644
--- a/modules/enterprise/server/container-lib/pom.xml
+++ b/modules/enterprise/server/container-lib/pom.xml
@@ -39,6 +39,11 @@
<scope>provided</scope> <!-- by JBossAS -->
</dependency>
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jnpserver</artifactId>
+ <version>4.2.2.GA</version>
+ </dependency>
</dependencies>
<profiles>
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java
new file mode 100644
index 0000000..df42afe
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingContextDecorator.java
@@ -0,0 +1,237 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
+ * applied security checks in each method (lookups, (un)bindings, etc).
+ * <p>
+ * The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
+ * <p>
+ * This decorator applies the security check on any JNDI name without a scheme and
+ * on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
+ * in the constructor.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingContextDecorator implements Context {
+
+ private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
+ private Context original;
+ private List<String> checkedSchemes;
+
+ public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
+ this.original = original;
+ this.checkedSchemes = Arrays.asList(checkedSchemes);
+ }
+
+ private static void check() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(PERM);
+ }
+
+ private void checkScheme(String scheme) {
+ if (scheme == null || checkedSchemes.contains(scheme)) {
+ check();
+ }
+ }
+
+ private void check(String name) {
+ checkScheme(getURLScheme(name));
+ }
+
+ private void check(Name name) {
+ if (name.size() == 0) {
+ check();
+ } else {
+ String first = name.get(0);
+ checkScheme(getURLScheme(first));
+ }
+ }
+
+ public Object lookup(Name name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ check(name);
+ return original.lookup(name);
+ }
+
+ public void bind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ check(name);
+ original.bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ check(name);
+ original.rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ check(name);
+ original.unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ check(oldName);
+ check(newName);
+ original.rename(oldName, newName);
+ }
+
+ public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ check(name);
+ return original.list(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
+ check(name);
+ return original.listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ check(name);
+ original.destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ check(name);
+ return original.createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ check(name);
+ return original.lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ check(name);
+ return original.getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix) throws NamingException {
+ check(name);
+ return original.composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+ check();
+ return original.addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ check();
+ return original.removeFromEnvironment(propName);
+ }
+
+ public Hashtable<?, ?> getEnvironment() throws NamingException {
+ check();
+ return original.getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ check();
+ original.close();
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ check();
+ return original.getNameInNamespace();
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
new file mode 100644
index 0000000..1a9562a
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryBuilder.java
@@ -0,0 +1,180 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jnp.interfaces.NamingContextFactory;
+
+/**
+ * This initial context factory builder is installed early on during the RHQ server startup
+ * and is later on used for obtaining the {@link Context}s for all JNDI lookups in the
+ * RHQ server.
+ * <p>
+ * We use a custom initial context factory builder to prevent the potential malicious 3rd party
+ * code (like CLI alert scripts) from supplying custom environment variables to {@link InitialContext}
+ * that would modify the JNDI lookup to skip our security access checks.
+ * <p>
+ * By using a builder we effectively take control of the initial context creation process
+ * and are free to ignore whatever the script is trying to supply.
+ * <p>
+ * This builder makes sure to install the RHQ server's security access checks to whatever
+ * initial context that is configured by the standard environment variables
+ * ({@link Context#INITIAL_CONTEXT_FACTORY}, etc.)
+ * <p>
+ * This class is heavily inspired by the implementation of a similar builder in JBoss AS 7.
+ *
+ * @see AllowRhqServerInternalsAccessPermission
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
+ private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
+
+ /**
+ * The list of JNDI name schemes that should be checked for security permissions
+ * (in addition to the names with no scheme).
+ *
+ * @see AccessCheckingContextDecorator
+ */
+ private static final String[] CHECKED_SCHEMES = { "java" };
+
+ private static final Set<InetAddress> SERVER_BIND_IPS;
+
+ static {
+ SERVER_BIND_IPS = new HashSet<InetAddress>();
+
+ try {
+ String bindingAddressString = System.getProperty("jboss.bind.address");
+ InetAddress bindingAddress = InetAddress.getByName(bindingAddressString);
+
+ if (bindingAddress.isAnyLocalAddress()) {
+ Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+ while(ifaces.hasMoreElements()) {
+ NetworkInterface iface = ifaces.nextElement();
+ SERVER_BIND_IPS.addAll(Collections.list(iface.getInetAddresses()));
+ }
+ } else {
+ SERVER_BIND_IPS.add(bindingAddress);
+ }
+ } catch (SocketException e) {
+ LOG.error("Could not obtain the list of local IPs", e);
+ } catch (UnknownHostException e) {
+ LOG.error("Failed to get the binding address of the RHQ server.", e);
+ }
+
+ }
+
+ /**
+ * This is the default initial context factory that is returned when no other is
+ * configured using the environment variables.
+ * <p>
+ * It uses {@link NamingContextFactory} as the underlying mechanism - the same
+ * as the default configuration in JBoss 4.
+ */
+ private static final InitialContextFactory DEFAULT_FACTORY = new InitialContextFactory() {
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return createSecureWrapper(new NamingContextFactory(), environment).getInitialContext(environment);
+ }
+ };
+
+ /**
+ * Create a InitialContext factory. If the environment does not override the factory class it will use the
+ * default context factory.
+ *
+ * @param environment The environment
+ * @return An initial context factory
+ * @throws NamingException If an error occurs loading the factory class.
+ */
+ public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
+ final String factoryClassName = (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
+ if (factoryClassName == null) {
+ return DEFAULT_FACTORY;
+ }
+ final ClassLoader classLoader = getContextClassLoader();
+ try {
+ final Class<?> factoryClass = Class.forName(factoryClassName, true, classLoader);
+ InitialContextFactory configuredFactory = (InitialContextFactory) factoryClass.newInstance();
+ return createSecureWrapper(configuredFactory, environment);
+ } catch (Exception e) {
+ throw new NamingException("Failed instantiate InitialContextFactory " + factoryClassName
+ + " from classloader " + classLoader);
+ }
+ }
+
+ private ClassLoader getContextClassLoader() {
+ return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ }
+
+ private static InitialContextFactory createSecureWrapper(InitialContextFactory factory, Hashtable<?, ?> environment) {
+ String providerUrl = (String) environment.get(Context.PROVIDER_URL);
+
+ if (providerUrl == null) {
+ return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ } else {
+ try {
+ URI uri = new URI(providerUrl);
+ InetAddress providerHost = InetAddress.getByName(uri.getHost());
+
+ //check if we are accessing the RHQ server through some remoting
+ //interface.
+ //I just can't find where to read the magic number 1099 from.
+ //it is defined in the jboss config files, but in the code
+ //it seems hardcoded - see JDBCLoginModule.
+ if (uri.getPort() == 1099 && SERVER_BIND_IPS.contains(providerHost)) {
+ return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ } else {
+ return new URLPreferringInitialContextFactoryDecorator(factory);
+ }
+ } catch (URISyntaxException e) {
+ return new AccessCheckingInitialContextFactoryDecorator(factory, CHECKED_SCHEMES);
+ } catch (UnknownHostException e) {
+ //let the factory deal with the unknown host...
+ //this most probably shouldn't be secured because localhost addresses
+ //should be resolvable.
+ return new URLPreferringInitialContextFactoryDecorator(factory);
+ }
+ }
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java
new file mode 100644
index 0000000..b23935f
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AccessCheckingInitialContextFactoryDecorator.java
@@ -0,0 +1,60 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+/**
+ * A decorator of an {@link InitialContextFactory} that adds the security checking
+ * machinery to the returned initial contexts.
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingInitialContextFactoryDecorator extends URLPreferringInitialContextFactoryDecorator {
+
+ private final String[] checkedSchemes;
+
+ /**
+ * @param factory the factory to wrap
+ * @param checkedSchemes the list of JNDI name schemes to check for permissions
+ * @see AccessCheckingContextDecorator
+ */
+ public AccessCheckingInitialContextFactoryDecorator(InitialContextFactory factory, String... checkedSchemes) {
+ super(factory);
+ this.checkedSchemes = checkedSchemes;
+ }
+
+ /**
+ * @param environment the environment variables for the return {@link Context} to use
+ *
+ * @return the initial context returned by the decorated factory wrapped in
+ * {@link URLPreferringContext} and {@link AccessCheckingContextDecorator} in that
+ * order.
+ */
+ @Override
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return new AccessCheckingContextDecorator(super.getInitialContext(environment), checkedSchemes);
+ }
+
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
new file mode 100644
index 0000000..aa807d6
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/AllowRhqServerInternalsAccessPermission.java
@@ -0,0 +1,36 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.security.BasicPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowRhqServerInternalsAccessPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 1L;
+
+ public AllowRhqServerInternalsAccessPermission() {
+ super("org.rhq.allow.server.internals.access");
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
new file mode 100644
index 0000000..b291c3e
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringContext.java
@@ -0,0 +1,104 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.NamingManager;
+
+/**
+ * This is a modification of the default {@link InitialContext} class that
+ * ignores the initial context factory builder when constructing the default
+ * context to use in lookups etc.
+ * <p>
+ * This is important because RHQ server has its own initial context factory
+ * builder that creates factories that in turn create contexts. If the default
+ * {@link InitialContext} implementation was used, we'd end up with a stack overflow
+ * error caused by the callchain loop when the {@link InitialContext} would ask
+ * the builder for a factory that would create another context that would ask the
+ * builder for the factory, etc. ad infinitum.
+ * <p>
+ * This class prevents that by acting exactly like the InitialContext would if
+ * the initial context factory builder wasn't installed. This enables the callers
+ * to still use the standard InitialContext when doing lookups etc. This standard
+ * initial context will ask our initial context factory builder which will then
+ * in chain create this {@link URLPreferringContext} that behaves like the original
+ * InitialContext would if the builder wasn't there.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringContext extends InitialContext {
+
+ public URLPreferringContext(InitialContextFactory defaultContextFactory) throws NamingException {
+ super(true);
+ this.defaultInitCtx = defaultContextFactory.getInitialContext(null);
+ this.gotDefault = true;
+ init(null);
+ }
+
+ public URLPreferringContext(Hashtable<?, ?> environment, InitialContextFactory defaultContextFactory) throws NamingException {
+ super(true);
+ this.defaultInitCtx = defaultContextFactory.getInitialContext(environment);
+ this.gotDefault = true;
+ init(environment);
+ }
+
+ @Override
+ protected Context getURLOrDefaultInitCtx(Name name) throws NamingException {
+ if (name.size() > 0) {
+ String first = name.get(0);
+ String scheme = getURLScheme(first);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, myProps);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+ }
+ return getDefaultInitCtx();
+ }
+
+ @Override
+ protected Context getURLOrDefaultInitCtx(String name) throws NamingException {
+ String scheme = getURLScheme(name);
+ if (scheme != null) {
+ Context ctx = NamingManager.getURLContext(scheme, myProps);
+ if (ctx != null) {
+ return ctx;
+ }
+ }
+ return getDefaultInitCtx();
+ }
+
+ //copied from InitialContext
+ private static String getURLScheme(String str) {
+ int colon_posn = str.indexOf(':');
+ int slash_posn = str.indexOf('/');
+
+ if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
+ return str.substring(0, colon_posn);
+ return null;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
new file mode 100644
index 0000000..6c311c7
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/URLPreferringInitialContextFactoryDecorator.java
@@ -0,0 +1,54 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+/**
+ * A decorator of an {@link InitialContextFactory} that returns an {@link URLPreferringContext}
+ * backed by the wrapped initial context factory.
+ * <p>
+ * This is to support contexts that don't need to be secured, yet we need to make sure to
+ * break the call-chain loop caused by the {@link InitialContext} asking the RHQ's {@link AccessCheckingInitialContextFactoryBuilder} for
+ * default contexts.
+ *
+ * @author Lukas Krejci
+ */
+public class URLPreferringInitialContextFactoryDecorator implements InitialContextFactory {
+
+ private final InitialContextFactory factory;
+
+ public URLPreferringInitialContextFactoryDecorator(InitialContextFactory factory) {
+ this.factory = factory;
+ }
+
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return new URLPreferringContext(environment, getFactory());
+ }
+
+ protected InitialContextFactory getFactory() {
+ return factory;
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
new file mode 100644
index 0000000..d938c50
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstaller.java
@@ -0,0 +1,45 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.mbean;
+
+import javax.naming.spi.NamingManager;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.jndi.AccessCheckingInitialContextFactoryBuilder;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AccessCheckingInitialContextFactoryBuilderInstaller implements AccessCheckingInitialContextFactoryBuilderInstallerMBean {
+ private static final Log LOG = LogFactory.getLog(AccessCheckingInitialContextFactoryBuilder.class);
+
+ public void start() throws Exception {
+ LOG.info("Installing RHQ's access permission checking initial context factory builder");
+
+ NamingManager.setInitialContextFactoryBuilder(new AccessCheckingInitialContextFactoryBuilder());
+ }
+
+ public void stop() throws Exception {
+ }
+}
diff --git a/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
new file mode 100644
index 0000000..87d19ab
--- /dev/null
+++ b/modules/enterprise/server/container-lib/src/main/java/org/rhq/jndi/mbean/AccessCheckingInitialContextFactoryBuilderInstallerMBean.java
@@ -0,0 +1,32 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.jndi.mbean;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public interface AccessCheckingInitialContextFactoryBuilderInstallerMBean {
+
+ void start() throws Exception;
+
+ void stop() throws Exception;
+}
diff --git a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
index 859b552..f231f15 100644
--- a/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
+++ b/modules/enterprise/server/container/src/main/resources/jbossas/server/default/conf/jboss-service.xml
@@ -225,6 +225,13 @@
<!-- JNDI -->
<!-- ==================================================================== -->
+ <!-- This installs a custom initial context factory builder into the JVM
+ that will ensure that all the default InitialContexts are going to check
+ for the permission to access the RHQ internals. -->
+ <mbean code="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
+ name="org.rhq:service=AccessCheckingInitialContextFactoryBuilderInstaller">
+ </mbean>
+
<!-- A simple mbean wrapper around the jndi Naming object. This
only handles an in memory instance. The NamingService uses this
as the JNDI store and exposes it remotely.
diff --git a/modules/enterprise/server/jar/pom.xml b/modules/enterprise/server/jar/pom.xml
index db286a1..a876809 100644
--- a/modules/enterprise/server/jar/pom.xml
+++ b/modules/enterprise/server/jar/pom.xml
@@ -78,6 +78,13 @@
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-container-lib</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<groupId>com.googlecode.java-diff-utils</groupId>
<artifactId>diffutils</artifactId>
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
index b4a19b7..ecf2f6f 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
@@ -25,8 +25,8 @@ import java.util.Map;
import java.util.Random;
import org.rhq.core.domain.auth.Subject;
-import org.rhq.enterprise.server.security.AllowEjbAccessPermission;
import org.rhq.enterprise.server.util.LookupUtil;
+import org.rhq.jndi.AllowRhqServerInternalsAccessPermission;
/**
* This is the JON Server's own session ID generator. It is outside any container-provided session mechanism. Its sole
@@ -45,7 +45,7 @@ import org.rhq.enterprise.server.util.LookupUtil;
*/
public final class SessionManager {
- private static final AllowEjbAccessPermission ACCESS_PERMISSION = new AllowEjbAccessPermission();
+ private static final AllowRhqServerInternalsAccessPermission ACCESS_PERMISSION = new AllowRhqServerInternalsAccessPermission();
/**
* Our source for random session IDs.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java
deleted file mode 100644
index 350453fb..0000000
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.enterprise.server.security;
-
-import java.security.Permission;
-
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.InvocationContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AllowEjbAccessInterceptor {
-
- private static final Permission PERM = new AllowEjbAccessPermission();
-
- @AroundInvoke
- public Object intercept(InvocationContext invocationContext) throws Exception {
- //check that the caller has permissions to access the EJBs.
- //normal code does, only alert CLI scripts that try to circumvent our
- //manager proxies don't.
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) sm.checkPermission(PERM);
-
- return invocationContext.proceed();
- }
-}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java
deleted file mode 100644
index 67f418d..0000000
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.enterprise.server.security;
-
-import java.security.BasicPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AllowEjbAccessPermission extends BasicPermission {
-
- private static final long serialVersionUID = 1L;
-
- public AllowEjbAccessPermission() {
- super("rhq.allow.ejb.access");
- }
-}
diff --git a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
index caa7513..8222948 100644
--- a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
+++ b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
@@ -9,12 +9,6 @@
<assembly-descriptor>
- <!-- This interceptor checks that the alert CLI scripts don't try to circumvent our access objects by accessing the local SLSB beans directly. -->
- <interceptor-binding>
- <ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.server.security.AllowEjbAccessInterceptor</interceptor-class>
- </interceptor-binding>
-
<!-- all our EJB3 SLSBs can define custom @RequiredPermissions annotations for authorization checks-->
<interceptor-binding>
<ejb-name>*</ejb-name>
diff --git a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
index 05edefa..85e2fb3 100644
--- a/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
+++ b/modules/enterprise/server/jar/src/test/resources/embedded-jboss-beans.xml
@@ -4,6 +4,14 @@
xsi:schemaLocation="urn:jboss:bean-deployer:2.0 bean-deployer_2_0.xsd"
xmlns="urn:jboss:bean-deployer:2.0">
+ <!-- This installs a custom initial context factory builder into the JVM
+ that will ensure that all the default InitialContexts are going to check
+ for the permission to access the RHQ internals. -->
+ <bean class="org.rhq.jndi.mbean.AccessCheckingInitialContextFactoryBuilderInstaller"
+ name="AccessCheckingInitialContextFactoryBuilderInstaller">
+ </bean>
+
+
<bean name="Naming" class="org.jnp.server.SingletonNamingServer"/>
<bean name="InitialContextProperties" class="java.util.Hashtable">
@@ -20,7 +28,7 @@
</entry>
</map>
</parameter>
- </constructor>
+ </constructor>
</bean>
<bean name="java:comp/Initializer" class="org.jboss.ejb3.embedded.JavaCompInitializer">
commit ca4757776c008f12a053c816d7b9cf8c6a310596
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Sat Dec 10 01:19:40 2011 +0100
Adding EjbAccessTest to make sure the CLI scripts can access the business
layer only through the designated interface. No direct local or remote
EJB access is possible.
diff --git a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
index 894c953..5822d44 100644
--- a/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
+++ b/modules/enterprise/binding/src/main/java/org/rhq/bindings/StandardScriptPermissions.java
@@ -20,6 +20,7 @@
package org.rhq.bindings;
import java.io.FilePermission;
+import java.io.SerializablePermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.Permission;
@@ -83,6 +84,11 @@ public class StandardScriptPermissions extends PermissionCollection {
add(new PropertyPermission("*", "read"));
add(new ReflectPermission("suppressAccessChecks"));
+
+ //these 2 are required for server-side scripts to be able to
+ //invoke remote EJBs.
+ add(new SerializablePermission("enableSubclassImplementation"));
+ add(new RuntimePermission("reflectionFactoryAccess"));
}
public void add(Permission permission) {
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index b125b3b..6932b60 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -17,9 +17,28 @@
<properties>
<persistence-api.version>1.0</persistence-api.version>
+ <rhq.server.datasource>java:/RHQDS</rhq.server.datasource>
+ <rhq.server.ds-mapping>PostgreSQL</rhq.server.ds-mapping>
+
+ <!-- dependency versions -->
+ <jboss-embeddable-ejb3.version>1.0.0.Alpha9</jboss-embeddable-ejb3.version>
+
+ <clean.db>true</clean.db>
</properties>
<dependencies>
+
+ <!-- Note, the test deps are intentionally placed above the other scoped deps because of classpath
+ reasons. Maven orders the [test] classpath in the order listed in the pom. We specifically
+ need the embeddable-ejb3 jar above the standard ejb3 jars because we need the embeddble packages
+ loaded when testing. -->
+ <dependency>
+ <groupId>jboss.jboss-embeddable-ejb3</groupId>
+ <artifactId>jboss-ejb3-all</artifactId>
+ <version>${jboss-embeddable-ejb3.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.rhq</groupId>
<artifactId>rhq-script-bindings</artifactId>
@@ -48,21 +67,319 @@
<!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
<scope>provided</scope> <!-- by JBossAS -->
</dependency>
-
+
+ <!-- Test deps - this insane list of deps is needed to get the embedded JBoss server with RHQ server deployed running -->
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>test-utils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rhq-enterprise-server</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate</groupId>
+ <artifactId>hibernate3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>hibernate-entitymanager</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-javamail_1.3.1_spec</artifactId>
+ <!-- The Sun javamail jar isn't available from a public repo due to licensing issues,
+ so use the Geronimo one instead. -->
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opensymphony.quartz</groupId>
+ <artifactId>quartz-oracle</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-annotations-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-cache</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-common</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <!-- includes the org.jboss.ejb3.StrictMaxPool class, which is needed by the PoolClass annotation used on some
+ of our SLSB's -->
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-j2ee</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-jmx</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-system</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jbosssx</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jbpm</artifactId>
+ <version>3.1.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.7</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>trove</groupId>
+ <artifactId>trove</artifactId>
+ <version>1.0.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.opencsv</groupId>
+ <artifactId>opencsv</artifactId>
+ <version>1.8</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- for the transaction interrupt EJB3 interceptor -->
+ <dependency>
+ <groupId>org.jboss.transaction</groupId>
+ <artifactId>jboss-jta</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>tomcat</groupId>
+ <artifactId>catalina</artifactId>
+ <version>5.5.20</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>tomcat</groupId>
+ <artifactId>tomcat-jk</artifactId>
+ <version>4.1.31</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Needed by com.jboss.jbossnetwork.apl.actions.xml.XPathProcessor; TODO: Remove once APL has been excised. -->
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.jcraft</groupId>
+ <artifactId>jsch</artifactId>
+ <version>0.1.29</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jettison-provider</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-links</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.el</groupId>
+ <artifactId>jboss-el</artifactId>
+ <version>2.0.1.GA</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.18</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+
<plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
- <!-- <argLine>-Xdebug -Xnoagent -Djava.compiler=NONE
- -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> -->
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <!-- Everything but the web service tests, this is the standard test execution -->
+ <configuration>
+ <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups>
+ <groups>${rhq.testng.includedGroups}</groups>
+ <systemPropertyVariables>
+ <embeddedDeployment>true</embeddedDeployment>
+ <deploymentDirectory>target/test-classes</deploymentDirectory>
+ <hibernate.dialect>${rhq.test.ds.hibernate-dialect}</hibernate.dialect>
+ <clean.db>${clean.db}</clean.db>
+ </systemPropertyVariables>
+ <argLine>-Djava.security.manager -Djava.security.policy==target/test-classes/security.policy</argLine>
+ <additionalClasspathElements>
+ <!-- The below is required for tests to run against Oracle. -->
+ <additionalClasspathElement>${settings.localRepository}/com/oracle/ojdbc5/${ojdbc5.version}/ojdbc5-${ojdbc5.version}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
</configuration>
- </plugin>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+
+ <!-- in order to get JMS to work properly in embedded test container, extract jms-rs.rar classes -->
+ <execution>
+ <id>Extract JMS classes from RAR needed for JMS tests</id>
+ <phase>process-classes</phase>
+ <configuration>
+ <tasks>
+ <unzip src="src/test/resources/jms-ra.rar" dest="target">
+ <patternset>
+ <include name="jms-ra.jar"/>
+ </patternset>
+ </unzip>
+ <unzip src="target/jms-ra.jar" dest="target/test-classes">
+ <patternset>
+ <include name="org/**"/>
+ </patternset>
+ </unzip>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
new file mode 100644
index 0000000..9c9d1bb
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/java/org/rhq/enterprise/client/security/test/EjbAccessTest.java
@@ -0,0 +1,175 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.rhq.enterprise.client.security.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.SerializablePermission;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.PermissionCollection;
+import java.util.Collections;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.rhq.bindings.SandboxedScriptEngine;
+import org.rhq.bindings.ScriptEngineFactory;
+import org.rhq.bindings.StandardBindings;
+import org.rhq.bindings.StandardScriptPermissions;
+import org.rhq.bindings.util.PackageFinder;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.client.LocalClient;
+import org.rhq.enterprise.server.security.AllowEjbAccessPermission;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.util.LookupUtil;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+@Test
+public class EjbAccessTest extends AbstractEJB3Test {
+
+ public void testEjbsAccessibleThroughPrivilegedCode() {
+ LookupUtil.getSubjectManager().getOverlord();
+ }
+
+ public void testEjbsAccessibleThroughLocalClient() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ engine.eval("SubjectManager.getSubjectByName('rhqadmin');");
+ }
+
+ public void testLocalEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/local');\n"
+ + "subjectManager.getOverlord();");
+
+ Assert.fail("The script shouldn't have been able to call local SLSB method.");
+ } catch (ScriptException e) {
+ assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ }
+ }
+
+ public void testRemoteEjbsInaccessibleThroughJndiLookup() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval(""
+ + "context = new javax.naming.InitialContext();\n"
+ + "subjectManager = context.lookup('SubjectManagerBean/remote');\n"
+ + "subjectManager.getSubjectByName('rhqadmin');");
+
+ Assert.fail("The script shouldn't have been able to call remote SLSB method directly.");
+ } catch (ScriptException e) {
+ //TODO java.io.IOException: access denied (java.io.SerializablePermission enableSubclassImplementation)
+ assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ }
+ }
+
+ public void testScriptCantUseSessionManager() throws ScriptException, IOException {
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ ScriptEngine engine = getEngine(overlord);
+
+ try {
+ engine.eval("org.rhq.enterprise.server.auth.SessionManager.getInstance();");
+
+ Assert.fail("The script shouldn't have been able to get instance of SessionManager.");
+ } catch (ScriptException e) {
+ assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public void testScriptCantUseSessionManagerMethods() throws Exception {
+
+ //The code below cannot work in Rhino because as of now, Rhino modifies
+ //the return value of Class.getDeclaredField() to be null when there
+ //is a security manager installed.
+ //This has been filed as a bug at Oracle (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7119959)
+
+ if (true) {
+ return;
+ }
+
+ Subject overlord = LookupUtil.getSubjectManager().getOverlord();
+
+ final ScriptEngine engine = getEngine(overlord);
+
+ class G {
+ private String obtainSessionManagerUsingReflection = ""
+ + "var sessionManagerClass = java.lang.Class.forName(\"org.rhq.enterprise.server.auth.SessionManager\");\n"
+ + "println(sessionManagerClass);\n"
+ + "var managerField = sessionManagerClass.getDeclaredField(\"_manager\");\n"
+ + "println(managerField);\n"
+ + "managerField.setAccessible(true);\n"
+ + "var manager = managerField.get(null);\n"
+ + "println(manager);\n"
+ + "manager.";
+
+ public void testInvoke(String methodCall) throws ScriptException {
+ String code = obtainSessionManagerUsingReflection + methodCall;
+
+ try {
+ engine.eval(code);
+ Assert.fail("The script shouldn't have been able to a method on a SessionManager.");
+ } catch (ScriptException e) {
+ assert e.getMessage().contains(AllowEjbAccessPermission.class.getName());
+ }
+ }
+ };
+ G manager = new G();
+
+ manager.testInvoke("getLastAccess(0);");
+ manager.testInvoke("getOverlord()");
+ manager.testInvoke("getSubject(2);");
+ manager.testInvoke("invalidate(0);");
+ manager.testInvoke("invalidate(\"\");");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject());");
+ manager.testInvoke("put(new org.rhq.core.domain.auth.Subject(), 0);");
+ }
+
+ private ScriptEngine getEngine(Subject subject) throws ScriptException, IOException {
+ StandardBindings bindings = new StandardBindings(new PrintWriter(System.out), new LocalClient(subject));
+ ScriptEngine engine = ScriptEngineFactory.getScriptEngine("JavaScript", new PackageFinder(Collections.<File>emptyList()), bindings);
+
+ PermissionCollection perms = new StandardScriptPermissions();
+ perms.add(new SerializablePermission("enableSubclassImplementation"));
+
+ return new SandboxedScriptEngine(engine, perms);
+ }
+}
diff --git a/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml b/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml
new file mode 100644
index 0000000..caa7513
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/META-INF/ejb-jar.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
+ version="3.0">
+
+ <description>RHQ</description>
+ <display-name>RHQ</display-name>
+
+ <assembly-descriptor>
+
+ <!-- This interceptor checks that the alert CLI scripts don't try to circumvent our access objects by accessing the local SLSB beans directly. -->
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.rhq.enterprise.server.security.AllowEjbAccessInterceptor</interceptor-class>
+ </interceptor-binding>
+
+ <!-- all our EJB3 SLSBs can define custom @RequiredPermissions annotations for authorization checks-->
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.rhq.enterprise.server.authz.RequiredPermissionsInterceptor</interceptor-class>
+ </interceptor-binding>
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.rhq.enterprise.server.common.TransactionInterruptInterceptor</interceptor-class>
+ </interceptor-binding>
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.rhq.enterprise.server.common.PerformanceMonitorInterceptor</interceptor-class>
+ </interceptor-binding>
+
+ </assembly-descriptor>
+
+</ejb-jar>
diff --git a/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml b/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml
new file mode 100644
index 0000000..b7c5c66
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/META-INF/jboss.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<jboss xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd"
+ version="3.0">
+
+ <enterprise-beans>
+
+ <!--
+ The AlertConditionLogManagerBean, AlertConditionManagerBean, AlertDampeningManagerBean,
+ AlertDefinitionManagerBean, AlertManagerBean, AuthorizationManagerBean, CachedConditionManagerBean, and
+ SubjectManager SLSB's are all invoked, either directly or indirectly, by the AlertConditionConsumerBean MDB.
+ Since MDB invocations are always done in new threads, using the default SLSB pool impl (ThreadlocalPool) would
+ cause a new instance of these SLSB's to be created every time they were invoked by AlertConditionConsumerBean.
+ This would be bad if only because existing instances would
+ not be reused, but it is really bad because the instances would also never get destroyed, causing heap space to
+ gradually leak until the Server eventually ran out of memory. Hence, we must use a StrictMaxPool, which
+ will use a fixed pool of instances of this SLSB, instead of a ThreadlocalPool. Because lots of alert
+ definitions could result in many concurrent calls to AlertConditionConsumerBean, and because most of these
+ SLSB's are also invoked by other callers (i.e. Agents, GUI's, or CLI's), we set the max pool size to 100 to
+ minimize the chances of AlertConditionConsumerBean invocations, which are the most critical, from having to
+ block and potentially getting backed up in the queue. We set the pool timeout extremely high to essentially
+ prevent queued callers from timing out. Note, MDB's are configured in ejb3-interceptors-aop.xml to use a strict
+ max pool with a max of 15 and a timeout of 10000, so AlertConditionConsumerBean might become a bottleneck for
+ systems with a lot of alerts defined. (ips, 05/10/11)
+
+ For more details, see https://bugzilla.redhat.com/show_bug.cgi?id=693232 .
+ -->
+
+ <session>
+ <ejb-name>AlertConditionLogManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>AlertConditionManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>AlertDampeningManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>AlertDefinitionManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>AlertManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>AuthorizationManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>CachedConditionManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>SubjectManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>100</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+
+ <!--
+ The CacheConsistencyManagerBean, CloudManagerBean, ServerManagerBean, StatusManagerBean, and SystemManagerBean
+ SLSB's are all invoked, either directly or indirectly, by EJB timers. Since EJB timer invocations are always
+ done in new threads, using the default SLSB pool impl (ThreadlocalPool) would cause a new instance of this
+ SLSB to be created every time it was invoked by an EJB timer. This would be bad if only because an existing
+ instance would not be reused, but it is really bad because the instance would also never get destroyed, causing
+ heap space to gradually leak until the Server eventually ran out of memory. Hence, we must use a
+ StrictMaxPool, which will use a fixed pool of instances of this SLSB, instead of a ThreadlocalPool.
+ The timer invocations will only require one or two instances at any given time, but because most of these
+ SLSB's are also invoked by other callers (i.e. Agents, GUI's, or CLI's, we set the max pool size to 30, to
+ minimize the chances of EJB timer invocations, which are the most critical, from having to block and
+ potentially getting backed up in the queue. We set the pool timeout extremely high to essentially prevent
+ queued callers from timing out. (ips, 05/10/11)
+
+ For more details, see https://bugzilla.redhat.com/show_bug.cgi?id=693232 .
+ -->
+
+ <session>
+ <ejb-name>CacheConsistencyManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>30</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>CloudManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>30</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>ServerManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>30</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>StatusManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>30</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ <session>
+ <ejb-name>SystemManagerBean</ejb-name>
+ <pool-config>
+ <pool-class>org.jboss.ejb3.StrictMaxPool</pool-class>
+ <pool-max-size>30</pool-max-size>
+ <pool-timeout>1000000000</pool-timeout>
+ </pool-config>
+ </session>
+
+ </enterprise-beans>
+
+</jboss>
diff --git a/modules/enterprise/server/client-api/src/test/resources/hibernate.properties b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
new file mode 100644
index 0000000..1951b84
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/hibernate.properties
@@ -0,0 +1,26 @@
+# FOR SOME STRANGE REASON, THIS FILE NEEDS TO BE HERE FOR THE HIBERNATE TO CORRECTLY
+# INITIALIZE. I DON'T KNOW WHY THE STANDARD default.persistence.properties FILE DOESN'T
+# WORK IN THIS MODULE.
+
+hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
+#hibernate.connection.release_mode=after_statement
+#hibernate.transaction.flush_before_completion=false
+#hibernate.transaction.auto_close_session=false
+#hibernate.query.factory_class=org.hibernate.hql.ast.ASTQueryTranslatorFactory
+#hibernate.hbm2ddl.auto=create-drop
+#hibernate.hbm2ddl.auto=create
+hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider
+# Clustered cache with TreeCache
+#hibernate.cache.provider_class=org.jboss.ejb3.entity.TreeCacheProviderHook
+#hibernate.treecache.mbean.object_name=jboss.cache:service=EJB3EntityTreeCache
+#hibernate.dialect=org.hibernate.dialect.HSQLDialect
+hibernate.jndi.java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+hibernate.jndi.java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
+hibernate.bytecode.use_reflection_optimizer=false
+# I don't think this is honored, but EJB3Deployer uses it
+hibernate.bytecode.provider=javassist
+hibernate.jdbc.use_streams_for_binary=true
+hibernate.show_sql=false
+hibernate.format_sql=true
+hibernate.default_batch_fetch_size=16
+hibernate.jdbc.batch_size=20
diff --git a/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar b/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar
new file mode 100644
index 0000000..c4807c6
Binary files /dev/null and b/modules/enterprise/server/client-api/src/test/resources/jms-ra.rar differ
diff --git a/modules/enterprise/server/client-api/src/test/resources/security.policy b/modules/enterprise/server/client-api/src/test/resources/security.policy
new file mode 100644
index 0000000..8860b47
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/test/resources/security.policy
@@ -0,0 +1,10 @@
+// We need the SecurityManager installed to enable sandboxing of CLI scripts
+// but we don't define any other security measures on the RHQ server itself.
+//
+// Granting all permissions allows us to run the RHQ server as if no security
+// manager was in place (which is assumed by default by JBoss AS) but be able
+// to use it when we need it for our own purposes.
+
+grant {
+ permission java.security.AllPermission;
+};
commit ef5673fb4482fd08cdec672740afc2f12a3d2b0b
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Sat Dec 10 01:17:50 2011 +0100
Making SessionManager behave the same as EJBs wrt the AccessEjbPermission.
It is very security-sensitive so we shouldn't allow scripts to just access
it and cause havoc in user sessions.
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
index 39b6076..b4a19b7 100644
--- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/auth/SessionManager.java
@@ -25,30 +25,42 @@ import java.util.Map;
import java.util.Random;
import org.rhq.core.domain.auth.Subject;
+import org.rhq.enterprise.server.security.AllowEjbAccessPermission;
import org.rhq.enterprise.server.util.LookupUtil;
/**
* This is the JON Server's own session ID generator. It is outside any container-provided session mechanism. Its sole
* purpose is to provide session IDs to logged in {@link Subject}s. It will timeout those sessions regardless of any
* container-provided session-timeout mechanism.
- *
+ * <p>
+ * Because this is a very security-sensitive class, any public method requires the caller to
+ * have the {@link AllowEjbAccessPermission} as any other calls to the EJB layer. This is so that the
+ * malicious users can't trick the EJB layer into thinking that some users are logged in or log out other
+ * users.
+ * <p>
+ * Also, for security reasons, this class is final so that malicious code can't subclass it and modify its
+ * behavior.
+ *
* <p>This object is a {@link #getInstance() singleton}.</p>
*/
-public class SessionManager {
+public final class SessionManager {
+
+ private static final AllowEjbAccessPermission ACCESS_PERMISSION = new AllowEjbAccessPermission();
+
/**
* Our source for random session IDs.
*/
- private static Random _random = new Random();
+ private static final Random _random = new Random();
/**
* Our session cache that is keyed on the session ID.
*/
- private static Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
+ private static final Map<Integer, AuthSession> _cache = new HashMap<Integer, AuthSession>();
/**
* The singleton instance
*/
- private static SessionManager _manager = new SessionManager();
+ private static final SessionManager _manager = new SessionManager();
/**
* The timeout for all user sessions.
@@ -78,7 +90,7 @@ public class SessionManager {
/**
* Return the singleton object.
- *
+ *
* @return the {@link SessionManager}
*/
public static SessionManager getInstance() {
@@ -95,6 +107,7 @@ public class SessionManager {
* sessionId will be assigned.
*/
public Subject put(Subject subject) {
+ checkPermission();
return put(subject, DEFAULT_TIMEOUT);
}
@@ -108,6 +121,7 @@ public class SessionManager {
* that Subject is overlord). The sessionId will be assigned.
*/
public synchronized Subject put(Subject subject, long timeout) {
+ checkPermission();
Integer key;
do {
@@ -141,6 +155,7 @@ public class SessionManager {
* @throws SessionTimeoutException
*/
public synchronized Subject getSubject(int sessionId) throws SessionNotFoundException, SessionTimeoutException {
+ checkPermission();
Integer id = new Integer(sessionId);
AuthSession session = _cache.get(id);
@@ -162,6 +177,7 @@ public class SessionManager {
* @param sessionId session id to invalidate
*/
public synchronized void invalidate(int sessionId) {
+ checkPermission();
_cache.remove(new Integer(sessionId));
// while we are here, let's go through the entire session cache and remove expired sessions
@@ -187,6 +203,7 @@ public class SessionManager {
* @param username username for the sessions to be invalidated
*/
public synchronized void invalidate(String username) {
+ checkPermission();
List<Integer> doomedSessionIds = new ArrayList<Integer>(_cache.size());
for (AuthSession s : _cache.values()) {
if (username.equals(s.getSubject(false).getName())) {
@@ -201,6 +218,7 @@ public class SessionManager {
}
public long getlastAccess(int sessionId) {
+ checkPermission();
AuthSession session = _cache.get(sessionId);
if (session == null) {
return -1;
@@ -209,6 +227,7 @@ public class SessionManager {
}
public Subject getOverlord() {
+ checkPermission();
if (overlordSubject == null) {
overlordSubject = LookupUtil.getSubjectManager().getSubjectById(OVERLORD_SUBJECT_ID);
@@ -256,4 +275,9 @@ public class SessionManager {
return copy;
}
+
+ private static void checkPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+ }
}
\ No newline at end of file
commit 0b0632e5641e91f3549e5addbc2c18bb27132c5a
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Sat Dec 10 01:16:26 2011 +0100
moving the EJB access permission and the interceptor back to the server
jar.
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java
deleted file mode 100644
index d3dcdb2..0000000
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.enterprise.client.security;
-
-import java.security.AccessController;
-import java.security.Permission;
-
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.InvocationContext;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AllowEjbAccessInterceptor {
-
- private static final Permission PERM = new AllowEjbAccessPermission();
-
- @AroundInvoke
- public Object intercept(InvocationContext invocationContext) throws Exception {
- //check that the caller has permissions to access the EJBs.
- //normal code does, only alert CLI scripts that try to circumvent our
- //manager proxies don't.
- AccessController.checkPermission(PERM);
- return invocationContext.proceed();
- }
-}
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java
deleted file mode 100644
index 19ee165..0000000
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2011 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-package org.rhq.enterprise.client.security;
-
-import java.security.BasicPermission;
-
-/**
- *
- *
- * @author Lukas Krejci
- */
-public class AllowEjbAccessPermission extends BasicPermission {
-
- private static final long serialVersionUID = 1L;
-
- public AllowEjbAccessPermission() {
- super("rhq.allow.ejb.access");
- }
-}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java
new file mode 100644
index 0000000..350453fb
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessInterceptor.java
@@ -0,0 +1,46 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.server.security;
+
+import java.security.Permission;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowEjbAccessInterceptor {
+
+ private static final Permission PERM = new AllowEjbAccessPermission();
+
+ @AroundInvoke
+ public Object intercept(InvocationContext invocationContext) throws Exception {
+ //check that the caller has permissions to access the EJBs.
+ //normal code does, only alert CLI scripts that try to circumvent our
+ //manager proxies don't.
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) sm.checkPermission(PERM);
+
+ return invocationContext.proceed();
+ }
+}
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java
new file mode 100644
index 0000000..67f418d
--- /dev/null
+++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/security/AllowEjbAccessPermission.java
@@ -0,0 +1,36 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.server.security;
+
+import java.security.BasicPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowEjbAccessPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 1L;
+
+ public AllowEjbAccessPermission() {
+ super("rhq.allow.ejb.access");
+ }
+}
diff --git a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
index 2700ae3..caa7513 100644
--- a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
+++ b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
@@ -12,7 +12,7 @@
<!-- This interceptor checks that the alert CLI scripts don't try to circumvent our access objects by accessing the local SLSB beans directly. -->
<interceptor-binding>
<ejb-name>*</ejb-name>
- <interceptor-class>org.rhq.enterprise.client.security.AllowEjbAccessInterceptor</interceptor-class>
+ <interceptor-class>org.rhq.enterprise.server.security.AllowEjbAccessInterceptor</interceptor-class>
</interceptor-binding>
<!-- all our EJB3 SLSBs can define custom @RequiredPermissions annotations for authorization checks-->
commit 248f6d5a2e08b7367490a47b892ccf8080fa1545
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Dec 7 17:50:25 2011 +0100
be paranoid even in the comments ;)
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
index 7fcdac3..e9f1e4d 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
@@ -62,7 +62,9 @@ public class LocalClientProxy extends AbstractRhqFacadeProxy<LocalClient> {
//run this through the privileged block to elevate the privs of the script
//the scripts don't have the AllowEjbAccessPermission but this code has
- //all perms.
+ //all perms (or at least all perms assigned to it by the current context,
+ //which at the time of writing is defined by the rhq-server.policy file
+ //which gives all code all permissions).
return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
commit 84f032252328434e01ac68d40bec34d102533d81
Author: Lukas Krejci <lkrejci(a)redhat.com>
Date: Wed Dec 7 13:54:34 2011 +0100
Use a custom java permission and an EJB interceptor to disallow server-side CLI scripts from accessing the EJBs directly.
diff --git a/modules/enterprise/server/client-api/pom.xml b/modules/enterprise/server/client-api/pom.xml
index e777e21..b125b3b 100644
--- a/modules/enterprise/server/client-api/pom.xml
+++ b/modules/enterprise/server/client-api/pom.xml
@@ -26,6 +26,7 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
+
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
@@ -40,6 +41,14 @@
section. -->
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-ejb3x</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement section. -->
+ <scope>provided</scope> <!-- by JBossAS -->
+ </dependency>
+
</dependencies>
<build>
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
index 5f3ff90..7fcdac3 100644
--- a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/LocalClientProxy.java
@@ -20,6 +20,8 @@
package org.rhq.enterprise.client;
import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import org.apache.commons.logging.Log;
@@ -54,11 +56,19 @@ public class LocalClientProxy extends AbstractRhqFacadeProxy<LocalClient> {
}
}
- protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, Object[] args) throws Throwable {
+ protected Object doInvoke(Object proxy, Method originalMethod, java.lang.Class<?>[] argTypes, final Object[] args) throws Throwable {
try {
- Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
-
- return realMethod.invoke(localSLSB, args);
+ final Method realMethod = localSLSB.getClass().getMethod(originalMethod.getName(), argTypes);
+
+ //run this through the privileged block to elevate the privs of the script
+ //the scripts don't have the AllowEjbAccessPermission but this code has
+ //all perms.
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ @Override
+ public Object run() throws Exception {
+ return realMethod.invoke(localSLSB, args);
+ }
+ });
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Method [" + originalMethod + "] does not have a desimplified counterpart with arguments " + Arrays.asList(argTypes) + ".", e);
}
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java
new file mode 100644
index 0000000..d3dcdb2
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessInterceptor.java
@@ -0,0 +1,45 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.client.security;
+
+import java.security.AccessController;
+import java.security.Permission;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowEjbAccessInterceptor {
+
+ private static final Permission PERM = new AllowEjbAccessPermission();
+
+ @AroundInvoke
+ public Object intercept(InvocationContext invocationContext) throws Exception {
+ //check that the caller has permissions to access the EJBs.
+ //normal code does, only alert CLI scripts that try to circumvent our
+ //manager proxies don't.
+ AccessController.checkPermission(PERM);
+ return invocationContext.proceed();
+ }
+}
diff --git a/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java
new file mode 100644
index 0000000..19ee165
--- /dev/null
+++ b/modules/enterprise/server/client-api/src/main/java/org/rhq/enterprise/client/security/AllowEjbAccessPermission.java
@@ -0,0 +1,36 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package org.rhq.enterprise.client.security;
+
+import java.security.BasicPermission;
+
+/**
+ *
+ *
+ * @author Lukas Krejci
+ */
+public class AllowEjbAccessPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 1L;
+
+ public AllowEjbAccessPermission() {
+ super("rhq.allow.ejb.access");
+ }
+}
diff --git a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
index 8222948..2700ae3 100644
--- a/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
+++ b/modules/enterprise/server/jar/src/main/resources/META-INF/ejb-jar.xml
@@ -9,6 +9,12 @@
<assembly-descriptor>
+ <!-- This interceptor checks that the alert CLI scripts don't try to circumvent our access objects by accessing the local SLSB beans directly. -->
+ <interceptor-binding>
+ <ejb-name>*</ejb-name>
+ <interceptor-class>org.rhq.enterprise.client.security.AllowEjbAccessInterceptor</interceptor-class>
+ </interceptor-binding>
+
<!-- all our EJB3 SLSBs can define custom @RequiredPermissions annotations for authorization checks-->
<interceptor-binding>
<ejb-name>*</ejb-name>
12 years, 3 months
[rhq] 2 commits - modules/plugins
by Heiko W. Rupp
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java | 74 ++++++++--
modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JVMDiscoveryComponent.java | 53 +++++++
modules/plugins/jboss-as-7/src/main/resources/META-INF/rhq-plugin.xml | 21 ++
3 files changed, 129 insertions(+), 19 deletions(-)
New commits:
commit ee0af237ea589d4bacf2f6c3cd35867fce2d24cc
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Feb 1 16:39:02 2012 +0100
We need to disable the datasource before making changes an re-enable it later.
Sub-resource properties are read-only for now
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
index ee8c108..0543b81 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
@@ -10,6 +10,8 @@ import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.PropertyList;
import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.configuration.ConfigurationFacet;
+import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.modules.plugins.jbossas7.json.Address;
@@ -21,7 +23,7 @@ import org.rhq.modules.plugins.jbossas7.json.Result;
* Handle JDBC-driver related stuff
* @author Heiko W. Rupp
*/
-public class DatasourceComponent extends BaseComponent implements OperationFacet {
+public class DatasourceComponent extends BaseComponent implements OperationFacet, ConfigurationFacet {
private static final String NOTSET = "-notset-";
private final Log log = LogFactory.getLog(DatasourceComponent.class);
@@ -143,4 +145,22 @@ public class DatasourceComponent extends BaseComponent implements OperationFacet
void addOptionalToOp(Operation op, Configuration parameters, String property) {
addAdditionalToOp(op,parameters,property,true);
}
+
+ @Override
+ public void updateResourceConfiguration(ConfigurationUpdateReport report) {
+
+ Operation op = new Operation("disable",getAddress());
+ Result res = getASConnection().execute(op);
+ if (!res.isSuccess()) {
+ report.setErrorMessage("Was not able to disable the datasource for config changes");
+ return;
+ }
+
+
+ super.updateResourceConfiguration(report); // TODO: Customise this generated block
+
+ op = new Operation("enable",getAddress());
+ res = getASConnection().execute(op);
+
+ }
}
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 a7f5b64..495c050 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
@@ -1353,10 +1353,10 @@
<c:group name="children:xa-datasource-properties:key+" displayName="XA Datasource Properties">
- <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="true">
<c:map-property name="*:key" displayName="Name" readOnly="true">
<c:simple-property name="key" displayName="Property-Name" readOnly="true"/>
- <c:simple-property name="value" displayName="Value"/>
+ <c:simple-property name="value" displayName="Value" readOnly="true"/>
</c:map-property>
</c:list-property>
</c:group>
commit 7daec9f1b83a4d16735ebb4004437f59f8d03a94
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Feb 1 14:59:25 2012 +0100
Take care of changes in XA-DS land within AS7
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
index 68c0bce..ee8c108 100644
--- a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/DatasourceComponent.java
@@ -1,19 +1,20 @@
package org.rhq.modules.plugins.jbossas7;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.Property;
+import org.rhq.core.domain.configuration.PropertyList;
+import org.rhq.core.domain.configuration.PropertyMap;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.pluginapi.operation.OperationFacet;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.modules.plugins.jbossas7.json.Address;
+import org.rhq.modules.plugins.jbossas7.json.CompositeOperation;
import org.rhq.modules.plugins.jbossas7.json.Operation;
-import org.rhq.modules.plugins.jbossas7.json.PROPERTY_VALUE;
import org.rhq.modules.plugins.jbossas7.json.Result;
/**
@@ -64,16 +65,41 @@ public class DatasourceComponent extends BaseComponent implements OperationFacet
Address theAddress = new Address(address);
theAddress.add("xa-data-source",name);
- op = new Operation("add",theAddress);
- addRequiredToOp(op,parameters,"driver-name");
- addRequiredToOp(op,parameters,"jndi-name");
- addOptionalToOp(op,parameters,"user-name");
- addOptionalToOp(op,parameters,"password");
- addRequiredToOp(op,parameters,"xa-datasource-class");
-
- Map<String,Object> props = new HashMap<String, Object>(); // TODO
- op.addAdditionalProperty("xa-data-source-properties",props);
-
+ op = new CompositeOperation();
+ Operation step1 = new Operation("add",theAddress);
+ addRequiredToOp(step1,parameters,"driver-name");
+ addRequiredToOp(step1,parameters,"jndi-name");
+ addOptionalToOp(step1,parameters,"user-name");
+ addOptionalToOp(step1,parameters,"password");
+ addRequiredToOp(step1,parameters,"xa-datasource-class");
+
+ ((CompositeOperation)op).addStep(step1);
+
+ // handling of xa-properties -- this is now a subresource in AS7 and at least needs a connection url
+ String connectionUrl = parameters.getSimpleValue("connection-url",null);
+ if (connectionUrl==null || connectionUrl.isEmpty())
+ throw new IllegalArgumentException("Connection-url must not be empty");
+ Address cuAddress = new Address(theAddress);
+ cuAddress.add("xa-datasource-properties","connection-url");
+ Operation step2 = new Operation("add",cuAddress);
+ step2.addAdditionalProperty("value",connectionUrl);
+ ((CompositeOperation)op).addStep(step2);
+
+
+ PropertyList xaPropList = parameters.getList("xa-properties");
+ if (xaPropList != null) {
+ List<Property> xaProps = xaPropList.getList();
+ for (Property prop : xaProps) {
+ PropertyMap pMap = (PropertyMap) prop;
+ PropertySimple keyProp = pMap.getSimple("key");
+ PropertySimple valProp = pMap.getSimple("value");
+ Address propAddress = new Address(theAddress);
+ propAddress.add("xa-datasource-properties",keyProp.getStringValue());
+ Operation step = new Operation("add",propAddress);
+ step.addAdditionalProperty("value",valProp.getStringValue()); // TODO ??
+ ((CompositeOperation)op).addStep(step);
+ }
+ }
}
else {
/*
diff --git a/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JVMDiscoveryComponent.java b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JVMDiscoveryComponent.java
new file mode 100644
index 0000000..aa870fb
--- /dev/null
+++ b/modules/plugins/jboss-as-7/src/main/java/org/rhq/modules/plugins/jbossas7/JVMDiscoveryComponent.java
@@ -0,0 +1,53 @@
+package org.rhq.modules.plugins.jbossas7;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.configuration.PropertySimple;
+import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails;
+import org.rhq.core.pluginapi.inventory.ResourceComponent;
+import org.rhq.core.pluginapi.inventory.ResourceContext;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent;
+import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext;
+
+/**
+ * Discovery component for special treatment of JVMs, which live below server=server-x for managed servers
+ * @author Heiko W. Rupp
+ */
+public class JVMDiscoveryComponent extends SubsystemDiscovery {
+
+ @Override
+ public Set<DiscoveredResourceDetails> discoverResources(
+ ResourceDiscoveryContext<BaseComponent<?>> context) throws Exception {
+
+ ResourceContext parentContext = context.getParentResourceContext();
+
+
+ if (!parentContext.getResourceType().getName().equals("Managed Server"))
+ return super.discoverResources(context);
+
+ PropertySimple pathProp = parentContext.getPluginConfiguration().getSimple("path");
+ String path = pathProp.getStringValue();
+ path = path.replaceAll("server-config=","server=");
+ path = path + ",core-service=platform-mbean";
+
+ Configuration config = new Configuration();
+ PropertySimple ps = new PropertySimple("path",path);
+ config.getProperties().add(ps);
+
+ DiscoveredResourceDetails detail = new DiscoveredResourceDetails(
+ context.getResourceType(),
+ path,
+ path, // dname, todo
+ null,
+ context.getResourceType().getDescription(),
+ config,
+ null
+ );
+
+ Set<DiscoveredResourceDetails> discoveredResourceDetails = new HashSet<DiscoveredResourceDetails>();
+ discoveredResourceDetails.add(detail);
+ return discoveredResourceDetails;
+ }
+}
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 3ef70c9..a7f5b64 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
@@ -558,12 +558,13 @@
<server name="JVM"
- discovery="SubsystemDiscovery"
+ discovery="JVMDiscoveryComponent"
class="BaseComponent"
description="Information about the underlying JVM"
singleton="true">
<runs-inside>
<parent-resource-type name="Managed Server" plugin="jboss-as-7"/>
+ <parent-resource-type name="Host" plugin="jboss-as-7"/>
<parent-resource-type name="JBossAS7 Standalone Server" plugin="jboss-as-7"/>
</runs-inside>
@@ -619,9 +620,8 @@
<resource-configuration>
<c:simple-property name="thread-contention-monitoring-enabled" required="false" type="boolean" readOnly="false" description="Whether thread contention monitoring is enabled."/>
<c:simple-property name="thread-cpu-time-enabled" required="false" type="boolean" readOnly="false" description="Whether thread CPU time measurement is enabled."/>
- <c:list-property name="all-thread-ids" description="All live thread IDs. If a security manager is installed and the caller does not have ManagementPermission('monitor'), the result will be und
- ." >
- <c:simple-property name="all-thread-ids" />
+ <c:list-property name="all-thread-ids" description="All live thread IDs. If a security manager is installed and the caller does not have ManagementPermission('monitor'), the result will be undefined." readOnly="true">
+ <c:simple-property name="all-thread-ids" readOnly="true"/>
</c:list-property>
<c:simple-property name="thread-contention-monitoring-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine supports thread contention monitoring."/>
<c:simple-property name="thread-cpu-time-supported" required="false" type="boolean" readOnly="true" description="Whether the Java virtual machine implementation supports CPU time measurement for any thread."/>
@@ -1036,10 +1036,11 @@
<c:option-source target="resource" expression="type=^Deployment$" filter=".*\.jar"/>
</c:simple-property>
<c:simple-property name="xa-datasource-class" required="true" description="xa-datasource-class"/>
+ <c:simple-property name="connection-url" required="true" description="Connection URL. Will be turned into an Xa-property)"/>
<c:simple-property name="jndi-name" description="JNDI-Name of the Datasource" required="true"/>
<c:simple-property name="user-name" description="User name for DB-connections" required="false" />
<c:simple-property name="password" description="Password" type="password" required="false"/>
- <c:list-property name="xa-properties" displayName="XA Properties" description="Additional XA Properties" required="false">
+ <c:list-property name="xa-properties" displayName="XA Properties" description="Additional XA Properties (connection url is set above)" required="false">
<c:map-property name="xa-properties">
<c:simple-property name="key" displayName="Key" description="Key of the property"/>
<c:simple-property name="value" displayName="Value" description="Value of the property"/>
@@ -1349,6 +1350,16 @@
</c:map-property>
-->
<c:simple-property name="no-recovery" required="false" type="boolean" readOnly="true" description="if true no recovery are tried for this connection pool"/>
+
+
+ <c:group name="children:xa-datasource-properties:key+" displayName="XA Datasource Properties">
+ <c:list-property name="*2" displayName="Properties" required="false" readOnly="false">
+ <c:map-property name="*:key" displayName="Name" readOnly="true">
+ <c:simple-property name="key" displayName="Property-Name" readOnly="true"/>
+ <c:simple-property name="value" displayName="Value"/>
+ </c:map-property>
+ </c:list-property>
+ </c:group>
</resource-configuration>
</service>
12 years, 3 months