You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by rv...@apache.org on 2015/04/28 23:40:38 UTC
[33/51] [partial] incubator-geode git commit: Init
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/AgentLauncher.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/AgentLauncher.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/AgentLauncher.java
new file mode 100644
index 0000000..b6bc44f
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/AgentLauncher.java
@@ -0,0 +1,880 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.GemFireException;
+import com.gemstone.gemfire.SystemFailure;
+import com.gemstone.gemfire.admin.AdminException;
+import com.gemstone.gemfire.admin.jmx.Agent;
+import com.gemstone.gemfire.admin.jmx.AgentConfig;
+import com.gemstone.gemfire.admin.jmx.AgentFactory;
+import com.gemstone.gemfire.distributed.internal.DistributionManager;
+import com.gemstone.gemfire.internal.OSProcess;
+import com.gemstone.gemfire.internal.PureJavaMode;
+import com.gemstone.gemfire.internal.SocketCreator;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.util.IOUtils;
+import com.gemstone.gemfire.internal.util.JavaCommandBuilder;
+
+/**
+ * A command line utility inspired by the <code>CacheServerLauncher</code> that is responsible for administering
+ * a stand-along GemFire JMX {@link Agent}.
+ * <p/>
+ * @author David Whitlock
+ * @since 3.5
+ */
+public class AgentLauncher {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /** Should the launch command be printed? */
+ public static final boolean PRINT_LAUNCH_COMMAND = Boolean.getBoolean(AgentLauncher.class.getSimpleName()
+ + ".PRINT_LAUNCH_COMMAND");
+
+ /* constants used to define state */
+ static final int SHUTDOWN = 0;
+ static final int STARTING = 1;
+ static final int RUNNING = 2;
+ static final int SHUTDOWN_PENDING = 3;
+ static final int SHUTDOWN_PENDING_AFTER_FAILED_STARTUP = 4;
+ static final int UNKNOWN = 6;
+
+ /** Agent configuration options */
+ static final String AGENT_PROPS = "agent-props";
+
+ /** A flag to indicate if the current log file should be kept. Used only when 'start' is used to fork off the 'server' */
+ static final String APPENDTO_LOG_FILE = "appendto-log-file";
+
+ /** optional and additional classpath entries */
+ static final String CLASSPATH = "classpath";
+
+ /** The directory argument */
+ static final String DIR = "dir";
+
+ /** Extra VM arguments */
+ static final String VMARGS = "vmargs";
+
+ /** The directory in which the agent's output resides */
+ private File workingDirectory = null;
+
+ /** The Status object for the agent */
+ private Status status = null;
+
+ /** base name for the agent to be launched */
+ private final String basename;
+
+ /** The name for the start up log file */
+ private final String startLogFileName;
+
+ /** The name of the status file */
+ private final String statusFileName;
+
+ /**
+ * Instantiates an AgentLauncher for execution and control of the GemFire JMX Agent process. This constructor is
+ * package private to prevent direct instantiation or subclassing by classes outside this package, but does allow
+ * the class to be tested as needed.
+ * <p/>
+ * @param basename base name for the application to be launched
+ */
+ AgentLauncher(final String basename) {
+ assert basename != null : "The base name used by the AgentLauncher to create files cannot be null!";
+ this.basename = basename;
+ final String formattedBasename = this.basename.toLowerCase().replace(" ", "");
+ this.startLogFileName = "start_" + formattedBasename + ".log";
+ this.statusFileName = "." + formattedBasename + ".ser";
+ }
+
+ /**
+ * Prints information about the agent configuration options
+ */
+ public void configHelp() {
+ PrintStream out = System.out;
+
+ Properties props = AgentConfigImpl.getDefaultValuesForAllProperties();
+
+ out.println("\n");
+ out.println(LocalizedStrings.AgentLauncher_AGENT_CONFIGURATION_PROPERTIES.toString());
+
+ SortedMap<String, String> map = new TreeMap<String, String>();
+
+ int maxLength = 0;
+ for (Iterator<Object> iter = props.keySet().iterator(); iter.hasNext(); ) {
+ String prop = (String) iter.next();
+ int length = prop.length();
+ if (length > maxLength) {
+ maxLength = length;
+ }
+
+ map.put(prop, AgentConfigImpl.getPropertyDescription(prop) +
+ " (" + LocalizedStrings.AgentLauncher_DEFAULT.toLocalizedString() + " \"" + props.getProperty(prop) + "\")");
+ }
+
+ Iterator<Entry<String, String>> entries = map.entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<String, String> entry = entries.next();
+ String prop = entry.getKey();
+ out.print(" ");
+ out.println(prop);
+
+ String description = entry.getValue();
+ StringTokenizer st = new StringTokenizer(description, " ");
+ out.print(" ");
+ int printed = 6;
+ while (st.hasMoreTokens()) {
+ String word = st.nextToken();
+ if (printed + word.length() > 72) {
+ out.print("\n ");
+ printed = 6;
+ }
+ out.print(word);
+ out.print(" ");
+ printed += word.length() + 1;
+ }
+ out.println("");
+ }
+ out.println("");
+
+ System.exit(1);
+ }
+
+ /**
+ * Returns a map that maps the name of the start options to its value on the command line. If no value is
+ * specified on the command line, a default one is provided.
+ */
+ protected Map<String, Object> getStartOptions(final String[] args) throws Exception {
+ final Map<String, Object> options = new HashMap<String, Object>();
+
+ options.put(APPENDTO_LOG_FILE, "false");
+ options.put(DIR, IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(new File(".")));
+
+ final List<String> vmArgs = new ArrayList<String>();
+ options.put(VMARGS, vmArgs);
+
+ final Properties agentProps = new Properties();
+ options.put(AGENT_PROPS, agentProps);
+
+ for (final String arg : args) {
+ if (arg.startsWith("-classpath=")) {
+ options.put(CLASSPATH, arg.substring("-classpath=".length()));
+ }
+ else if (arg.startsWith("-dir=")) {
+ final File workingDirectory = processDirOption(options, arg.substring("-dir=".length()));
+ System.setProperty(AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME,
+ new File(workingDirectory, AgentConfig.DEFAULT_PROPERTY_FILE).getPath());
+ }
+ else if (arg.startsWith("-J")) {
+ vmArgs.add(arg.substring(2));
+ }
+ else if (arg.contains("=")) {
+ final int index = arg.indexOf("=");
+ final String prop = arg.substring(0, index);
+ final String value = arg.substring(index + 1);
+
+ // if appendto-log-file is set, put it in options; it is not set as an agent prop
+ if (prop.equals(APPENDTO_LOG_FILE)) {
+ options.put(APPENDTO_LOG_FILE, value);
+ continue;
+ }
+
+ // verify the property is valid
+ AgentConfigImpl.getPropertyDescription(prop);
+
+ // Note, the gfAgentPropertyFile System property is ultimately read in the constructor of the AgentImpl class
+ // in order to make any properties defined in this file not only accessible to the DistributedSystem but to
+ // the GemFire Agent as well.
+ if (AgentConfigImpl.PROPERTY_FILE_NAME.equals(prop)) {
+ System.setProperty(AgentConfigImpl.AGENT_PROPSFILE_PROPERTY_NAME, value);
+ }
+
+ // The Agent properties file (specified with the command-line key=value) is used to pass configuration settings
+ // to the GemFire DistributedSystem. A property file can be passed using the property-file command-line switch
+ // is a large number of properties are specified, or the properties maybe individually specified on the
+ // command-line as property=value arguments.
+ agentProps.setProperty(prop, value);
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * After parsing the command line arguments, spawn the Java VM that will host the GemFire JMX Agent.
+ */
+ public void start(final String[] args) throws Exception {
+ final Map<String, Object> options = getStartOptions(args);
+
+ workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));
+
+ // verify that any GemFire JMX Agent process has been properly shutdown and delete any remaining status files...
+ verifyAndClearStatus();
+
+ // start the GemFire JMX Agent process...
+ runCommandLine(options, buildCommandLine(options));
+
+ // wait for the GemFire JMX Agent process to complete startup and begin running...
+ // it is also possible the Agent process may fail to start, so this should not wait indefinitely unless
+ // the status file was not successfully written to
+ pollAgentUntilRunning();
+
+ System.exit(0);
+ }
+
+ private void verifyAndClearStatus() throws Exception {
+ final Status status = getStatus();
+
+ if (status != null && status.state != SHUTDOWN) {
+ throw new IllegalStateException(LocalizedStrings.AgentLauncher_JMX_AGENT_EXISTS_BUT_WAS_NOT_SHUTDOWN.toLocalizedString());
+ }
+
+ deleteStatus();
+ }
+
+ private String[] buildCommandLine(final Map<String, Object> options) {
+ final List<String> commands = JavaCommandBuilder.buildCommand(AgentLauncher.class.getName(), (String) options.get(CLASSPATH), null,
+ (List<String>) options.get(VMARGS));
+
+ commands.add("server");
+ commands.add("-dir=" + workingDirectory);
+
+ final Properties agentProps = (Properties) options.get(AGENT_PROPS);
+
+ for (final Object key : agentProps.keySet()) {
+ commands.add(key + "=" + agentProps.get(key.toString()));
+ }
+
+ return commands.toArray(new String[commands.size()]);
+ }
+
+ private void printCommandLine(final String[] commandLine) {
+ if (PRINT_LAUNCH_COMMAND) {
+ System.out.print("Starting " + this.basename + " with command:\n");
+ for (final String command : commandLine) {
+ System.out.print(command);
+ System.out.print(' ');
+ }
+ System.out.println();
+ }
+ }
+
+ private int runCommandLine(final Map<String, Object> options, final String[] commandLine) throws IOException {
+ // initialize the startup log starting with a fresh log file (where all startup messages are printed)
+ final File startLogFile = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(
+ new File(workingDirectory, startLogFileName));
+
+ if (startLogFile.exists() && !startLogFile.delete()) {
+ throw new IOException(LocalizedStrings.AgentLauncher_UNABLE_TO_DELETE_FILE_0.toLocalizedString(
+ startLogFile.getAbsolutePath()));
+ }
+
+ Map<String, String> env = new HashMap<String, String>();
+ // read the passwords from command line
+ SocketCreator.readSSLProperties(env, true);
+
+ printCommandLine(commandLine);
+
+ final int pid = OSProcess.bgexec(commandLine, workingDirectory, startLogFile, false, env);
+
+ System.out.println(LocalizedStrings.AgentLauncher_STARTING_JMX_AGENT_WITH_PID_0.toLocalizedString(pid));
+
+ return pid;
+ }
+
+ private void pollAgentUntilRunning() throws Exception {
+ Status status = spinReadStatus();
+
+ // TODO this loop could recurse indefinitely if the GemFire JMX Agent's state never changes from STARTING
+ // to something else (like RUNNING), which could happen if server process fails to startup correctly
+ // and did not or could not write to the status file!
+ // TODO should we really allow the InterruptedException from the Thread.sleep call to break this loop (yeah, I
+ // think so given the fact this could loop indefinitely)?
+ while (status != null && status.state == STARTING) {
+ Thread.sleep(500);
+ status = spinReadStatus();
+ }
+
+ if (status == null) {
+ // TODO throw a more appropriate Exception here!
+ throw new Exception(LocalizedStrings.AgentLauncher_NO_AVAILABLE_STATUS.toLocalizedString());
+ }
+ else {
+ System.out.println(status);
+ }
+ }
+
+ /**
+ * Starts the GemFire JMX Agent "server" process with the given command line arguments.
+ */
+ public void server(final String[] args) throws Exception {
+ final Map<String, Object> options = getStartOptions(args);
+
+ workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));
+
+ writeStatus(createStatus(this.basename, STARTING, OSProcess.getId()));
+
+ final Agent agent = createAgent((Properties) options.get(AGENT_PROPS));
+
+ final Thread thread = createAgentProcessThread(createAgentProcessThreadGroup(), agent);
+ thread.setDaemon(true);
+ thread.start();
+
+ // periodically check and see if the JMX Agent has been told to stop
+ pollAgentForPendingShutdown(agent);
+ }
+
+ private Agent createAgent(final Properties props) throws IOException, AdminException {
+ DistributionManager.isDedicatedAdminVM = true;
+ SystemFailure.setExitOK(true);
+
+ final AgentConfigImpl config = new AgentConfigImpl(props);
+
+ // see bug 43760
+ if (config.getLogFile() == null || "".equals(config.getLogFile().trim())) {
+ config.setLogFile(AgentConfigImpl.DEFAULT_LOG_FILE);
+ }
+
+ // LOG:TODO: redirectOutput called here
+ OSProcess.redirectOutput(new File(config.getLogFile())); // redirect output to the configured log file
+
+ return AgentFactory.getAgent(config);
+ }
+
+ private ThreadGroup createAgentProcessThreadGroup() {
+ return new ThreadGroup(LocalizedStrings.AgentLauncher_STARTING_AGENT.toLocalizedString()) {
+ @Override
+ public void uncaughtException(final Thread t, final Throwable e) {
+ if (e instanceof VirtualMachineError) {
+ SystemFailure.setFailure((VirtualMachineError) e);
+ }
+ setServerError(LocalizedStrings.AgentLauncher_UNCAUGHT_EXCEPTION_IN_THREAD_0.toLocalizedString(t.getName()), e);
+ }
+ };
+ }
+
+ private Thread createAgentProcessThread(final ThreadGroup group, final Agent agent) {
+ return new Thread(group, createAgentProcessRunnable(agent), "Start agent");
+ }
+
+ private Runnable createAgentProcessRunnable(final Agent agent) {
+ return new Runnable() {
+ public void run() {
+ try {
+ agent.start();
+ writeStatus(createStatus(AgentLauncher.this.basename, RUNNING, OSProcess.getId()));
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ catch (GemFireException e) {
+ e.printStackTrace();
+ handleGemFireException(e);
+ }
+ }
+
+ private void handleGemFireException(final GemFireException e) {
+ String message = LocalizedStrings.AgentLauncher_SERVER_FAILED_TO_START_0.toLocalizedString(e.getMessage());
+
+ if (e.getCause() != null) {
+ if (e.getCause().getCause() != null) {
+ message += ", " + e.getCause().getCause().getMessage();
+ }
+ }
+
+ setServerError(null, new Exception(message));
+ }
+ };
+ }
+
+
+ /**
+ * Notes that an error has occurred in the agent and that it has shut down because of it.
+ */
+ private void setServerError(final String message, final Throwable cause) {
+ try {
+ writeStatus(createStatus(this.basename, SHUTDOWN_PENDING_AFTER_FAILED_STARTUP, OSProcess.getId(), message, cause));
+ }
+ catch (Exception e) {
+ logger.fatal(e.getMessage(), e);
+ System.exit(1);
+ }
+ }
+
+ private void pollAgentForPendingShutdown(final Agent agent) throws Exception {
+ while (true) {
+ pause(500);
+ spinReadStatus();
+
+ if (isStatus(SHUTDOWN_PENDING, SHUTDOWN_PENDING_AFTER_FAILED_STARTUP)) {
+ agent.stop();
+ final int exitCode = (isStatus(SHUTDOWN_PENDING_AFTER_FAILED_STARTUP) ? 1 : 0);
+ writeStatus(createStatus(this.status, SHUTDOWN));
+ System.exit(exitCode);
+ }
+ }
+ }
+
+ /**
+ * Extracts configuration information for stopping a agent based on the
+ * contents of the command line. This method can also be used with getting
+ * the status of a agent.
+ */
+ protected Map<String, Object> getStopOptions(final String[] args) throws Exception {
+ final Map<String, Object> options = new HashMap<String, Object>();
+
+ options.put(DIR, IOUtils.tryGetCanonicalFileElseGetAbsoluteFile(new File(".")));
+
+ for (final String arg : args) {
+ if (arg.equals("stop") || arg.equals("status")) {
+ // expected
+ }
+ else if (arg.startsWith("-dir=")) {
+ processDirOption(options, arg.substring("-dir=".length()));
+ }
+ else {
+ throw new Exception(LocalizedStrings.AgentLauncher_UNKNOWN_ARGUMENT_0.toLocalizedString(arg));
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * Stops a running JMX Agent by setting the status to "shutdown pending".
+ */
+ public void stop(final String[] args) throws Exception {
+ final Map<String, Object> options = getStopOptions(args);
+
+ workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) options.get(DIR));
+
+ int exitStatus = 1;
+
+ if (new File(workingDirectory, statusFileName).exists()) {
+ spinReadStatus();
+
+ if (!isStatus(SHUTDOWN)) {
+ writeStatus(createStatus(this.basename, SHUTDOWN_PENDING, status.pid));
+ }
+
+ pollAgentForShutdown();
+
+ if (isStatus(SHUTDOWN)) {
+ System.out.println(LocalizedStrings.AgentLauncher_0_HAS_STOPPED.toLocalizedString(this.basename));
+ deleteStatus();
+ exitStatus = 0;
+ }
+ else {
+ System.out.println(LocalizedStrings.AgentLauncher_TIMEOUT_WAITING_FOR_0_TO_SHUTDOWN_STATUS_IS_1
+ .toLocalizedString(this.basename, status));
+ }
+ }
+ else {
+ System.out.println(LocalizedStrings.AgentLauncher_THE_SPECIFIED_WORKING_DIRECTORY_0_CONTAINS_NO_STATUS_FILE
+ .toLocalizedString(workingDirectory));
+ }
+
+ System.exit(exitStatus);
+ }
+
+ private void pollAgentForShutdown() throws InterruptedException {
+ final long endTime = (System.currentTimeMillis() + 20000);
+ long clock = 0;
+
+ while (clock < endTime && !isStatus(SHUTDOWN)) {
+ pause(500);
+ spinReadStatus();
+ clock = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Prints the status of the GemFire JMX Agent running in the configured working directory.
+ */
+ public void status(final String[] args) throws Exception {
+ this.workingDirectory = IOUtils.tryGetCanonicalFileElseGetAbsoluteFile((File) getStopOptions(args).get(DIR));
+ System.out.println(getStatus());
+ System.exit(0);
+ }
+
+ /**
+ * Returns the <code>Status</code> of the GemFire JMX Agent in the <code>workingDirectory</code>.
+ */
+ protected Status getStatus() throws Exception {
+ Status status;
+
+ if (new File(workingDirectory, statusFileName).exists()) {
+ status = spinReadStatus();
+ }
+ else {
+ status = createStatus(this.basename, SHUTDOWN, 0, LocalizedStrings.AgentLauncher_0_IS_NOT_RUNNING_IN_SPECIFIED_WORKING_DIRECTORY_1
+ .toLocalizedString(this.basename, this.workingDirectory), null);
+ }
+
+ return status;
+ }
+
+ /**
+ * Determines if the Status.state is one of the specified states in the given array of states. Note, the status
+ * of the Agent, as indicated in the .agent.ser status file, should never have a written value of UNKNOWN.
+ * <p/>
+ * @param states an array of possible acceptable states satisfying the condition of the Agent's status.
+ * @return a boolean value indicating whether the Agent's status satisfies one of the specified states.
+ */
+ private boolean isStatus(final Integer... states) {
+ return (this.status != null && Arrays.asList(defaultToUnknownStateIfNull(states)).contains(this.status.state));
+ }
+
+ /**
+ * Removes an agent's status file
+ */
+ protected void deleteStatus() throws IOException {
+ final File statusFile = new File(workingDirectory, statusFileName);
+
+ if (statusFile.exists() && !statusFile.delete()) {
+ throw new IOException("Could not delete status file (" + statusFile.getAbsolutePath() + ")");
+ }
+ }
+
+ /**
+ * Reads the GemFire JMX Agent's status from the status file (.agent.ser) in it's working directory.
+ * <p/>
+ * @return a Status object containing the state persisted to the .agent.ser file in the working directory
+ * and representing the status of the Agent
+ * @throws IOException if the status file was unable to be read.
+ * @throws RuntimeException if the class of the object written to the .agent.ser file is not of type Status.
+ */
+ protected Status readStatus() throws IOException {
+ FileInputStream fileIn = null;
+ ObjectInputStream objectIn = null;
+
+ try {
+ fileIn = new FileInputStream(new File(workingDirectory, statusFileName));
+ objectIn = new ObjectInputStream(fileIn);
+ this.status = (Status) objectIn.readObject();
+ return this.status;
+ }
+ catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ IOUtils.close(objectIn);
+ IOUtils.close(fileIn);
+ }
+ }
+
+ /**
+ * A wrapper method for the readStatus method to make one last check for the GemFire JMX Agent process if running
+ * with the native libraries.
+ * @return the Status object as returned from readStatus unless running in native mode and a determination is made
+ * such that the Agent process is not running.
+ * @throws IOException if the state of the Agent process could not be read from the .agent.ser status file.
+ * @see #readStatus()
+ */
+ protected Status nativeReadStatus() throws IOException {
+ Status status = readStatus();
+
+ // @see Bug #32760 - the bug is still possible in pure Java mode
+ if (status != null && !PureJavaMode.isPure() && !OSProcess.exists(status.pid)) {
+ status = createStatus(status, SHUTDOWN);
+ }
+
+ return status;
+ }
+
+ /**
+ * Reads the JMX Agent's status from the .agent.ser status file. If the status file cannot be read due
+ * to I/O problems, the method will keep attempting to read the file for up to 20 seconds.
+ * <p/>
+ * @return the Status of the GemFire JMX Agent as determined by the .agent.ser status file, or natively
+ * based on the presence/absence of the Agent process.
+ */
+ protected Status spinReadStatus() {
+ Status status = null;
+
+ final long endTime = (System.currentTimeMillis() + 20000);
+ long clock = 0;
+
+ while (status == null && clock < endTime) {
+ try {
+ status = nativeReadStatus();
+ }
+ catch (Exception ignore) {
+ // see bug 31575
+ // see bug 36998
+ // try again after a short delay... the status file might have been read prematurely before it existed
+ // or while the server was trying to write to it resulting in a possible EOFException, or other IOException.
+ pause(500);
+ }
+ finally {
+ clock = System.currentTimeMillis();
+ }
+ }
+
+ return status;
+ }
+
+ /**
+ * Sets the status of the GemFire JMX Agent by serializing a <code>Status</code> object to a status file
+ * in the Agent's working directory.
+ * <p/>
+ * @param status the Status object representing the state of the Agent process to persist to disk.
+ * @return the written Status object.
+ * @throws IOException if the Status could not be successfully persisted to disk.
+ */
+ public Status writeStatus(final Status status) throws IOException {
+ FileOutputStream fileOut = null;
+ ObjectOutputStream objectOut = null;
+
+ try {
+ fileOut = new FileOutputStream(new File(workingDirectory, statusFileName));
+ objectOut = new ObjectOutputStream(fileOut);
+ objectOut.writeObject(status);
+ objectOut.flush();
+ this.status = status;
+ return this.status;
+ }
+ finally {
+ IOUtils.close(objectOut);
+ IOUtils.close(fileOut);
+ }
+ }
+
+ protected static Status createStatus(final String basename, final int state, final int pid) {
+ return createStatus(basename, state, pid, null, null);
+ }
+
+ protected static Status createStatus(final String basename, final int state, final int pid, final String msg, final Throwable t) {
+ final Status status = new Status(basename);
+ status.state = state;
+ status.pid = pid;
+ status.msg = msg;
+ status.exception = t;
+ return status;
+ }
+
+ protected static Status createStatus(final Status status, final int state) {
+ assert status != null : "The status to clone cannot be null!";
+ return createStatus(status.baseName, state, status.pid, status.msg, status.exception);
+ }
+
+ protected static Integer[] defaultToUnknownStateIfNull(final Integer... states) {
+ return (states != null ? states : new Integer[] { UNKNOWN });
+ }
+
+ protected static boolean pause(final int milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ return true;
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ protected static File processDirOption(final Map<String, Object> options, final String dirValue) throws FileNotFoundException {
+ final File workingDirectory = new File(dirValue);
+
+ if (!workingDirectory.exists()) {
+ throw new FileNotFoundException(LocalizedStrings.AgentLauncher_THE_INPUT_WORKING_DIRECTORY_DOES_NOT_EXIST_0
+ .toLocalizedString(dirValue));
+ }
+
+ options.put(DIR, workingDirectory);
+
+ return workingDirectory;
+ }
+
+ /**
+ * Prints usage information for the AgentLauncher to the command line.
+ * <p/>
+ * @param message a String to output to the command line indicating the user error.
+ */
+ private static void usage(final String message) {
+ final PrintStream out = System.out;
+
+ out.println("\n** " + message + "\n");
+
+ out.println("agent start [-J<vmarg>]* [-dir=<dir>] [prop=value]*");
+ out.println(LocalizedStrings.AgentLauncher_STARTS_THE_GEMFIRE_JMX_AGENT.toLocalizedString());
+ out.println("\t" + LocalizedStrings.AgentLauncher_VMARG.toLocalizedString() );
+ out.println("\t" + LocalizedStrings.AgentLauncher_DIR.toLocalizedString());
+ out.println("\t" + LocalizedStrings.AgentLauncher_PROP.toLocalizedString());
+ out.println("\t" + LocalizedStrings.AgentLauncher_SEE_HELP_CONFIG.toLocalizedString());
+ out.println();
+
+ out.println("agent stop [-dir=<dir>]");
+ out.println(LocalizedStrings.AgentLauncher_STOPS_A_GEMFIRE_JMX_AGENT.toLocalizedString());
+ out.println("\t" + LocalizedStrings.AgentLauncher_DIR.toLocalizedString());
+ out.println("");
+ out.println("agent status [-dir=<dir>]");
+ out.println(LocalizedStrings.AgentLauncher_REPORTS_THE_STATUS_AND_THE_PROCESS_ID_OF_A_GEMFIRE_JMX_AGENT.toLocalizedString());
+ out.println("\t" + LocalizedStrings.AgentLauncher_DIR.toLocalizedString());
+ out.println();
+
+ System.exit(1);
+ }
+
+ /**
+ * Bootstrap method to launch the GemFire JMX Agent process to monitor and manage a GemFire Distributed System/Cache.
+ * Main will read the arguments passed on the command line and dispatch the command to the appropriate handler.
+ */
+ public static void main(final String[] args) {
+ if (args.length < 1) {
+ usage(LocalizedStrings.AgentLauncher_MISSING_COMMAND.toLocalizedString());
+ }
+
+ // TODO is this only needed on 'agent server'? 'agent {start|stop|status}' technically do no run any GemFire Cache
+ // or DS code inside the current process.
+ SystemFailure.loadEmergencyClasses();
+
+ final AgentLauncher launcher = new AgentLauncher("Agent");
+
+ try {
+ final String command = args[0];
+
+ if (command.equalsIgnoreCase("start")) {
+ launcher.start(args);
+ }
+ else if (command.equalsIgnoreCase("server")) {
+ launcher.server(args);
+ }
+ else if (command.equalsIgnoreCase("stop")) {
+ launcher.stop(args);
+ }
+ else if (command.equalsIgnoreCase("status")) {
+ launcher.status(args);
+ }
+ else if (command.toLowerCase().matches("-{0,2}help")) {
+ if (args.length > 1) {
+ final String topic = args[1];
+
+ if (topic.equals("config")) {
+ launcher.configHelp();
+ }
+ else {
+ usage(LocalizedStrings.AgentLauncher_NO_HELP_AVAILABLE_FOR_0.toLocalizedString(topic));
+ }
+ }
+
+ usage(LocalizedStrings.AgentLauncher_AGENT_HELP.toLocalizedString());
+ }
+ else {
+ usage(LocalizedStrings.AgentLauncher_UNKNOWN_COMMAND_0.toLocalizedString(command));
+ }
+ }
+ catch (VirtualMachineError e) {
+ SystemFailure.initiateFailure(e);
+ throw e;
+ }
+ catch (Throwable t) {
+ SystemFailure.checkFailure();
+ t.printStackTrace();
+ System.err.println(LocalizedStrings.AgentLauncher_ERROR_0.toLocalizedString(t.getLocalizedMessage()));
+ System.exit(1);
+ }
+ }
+
+ /**
+ * A class representing the current state of the GemFire JMX Agent process. Instances of this class are serialized
+ * to a {@linkplain #statusFileName file} on disk in the specified working directory {@linkplain #workingDirectory}.
+ * <p/>
+ * @see #SHUTDOWN
+ * @see #STARTING
+ * @see #RUNNING
+ * @see #SHUTDOWN_PENDING
+ * @see #SHUTDOWN_PENDING_AFTER_FAILED_STARTUP
+ */
+ // TODO refactor this class and internalize the state
+ // TODO refactor the class and make immutable
+ static class Status implements Serializable {
+
+ private static final long serialVersionUID = -7758402454664266174L;
+
+ int pid = 0;
+ int state = 0;
+
+ final String baseName;
+ String msg;
+
+ Throwable exception;
+
+ public Status(final String baseName) {
+ this.baseName = baseName;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder buffer = new StringBuilder();
+
+ if (pid == Integer.MIN_VALUE && state == SHUTDOWN && msg != null) {
+ buffer.append(msg);
+ }
+ else {
+ buffer.append(LocalizedStrings.AgentLauncher_0_PID_1_STATUS.toLocalizedString(this.baseName, pid));
+
+ switch (state) {
+ case SHUTDOWN:
+ buffer.append(LocalizedStrings.AgentLauncher_SHUTDOWN.toLocalizedString());
+ break;
+ case STARTING:
+ buffer.append(LocalizedStrings.AgentLauncher_STARTING.toLocalizedString());
+ break;
+ case RUNNING:
+ buffer.append(LocalizedStrings.AgentLauncher_RUNNING.toLocalizedString());
+ break;
+ case SHUTDOWN_PENDING:
+ buffer.append(LocalizedStrings.AgentLauncher_SHUTDOWN_PENDING.toLocalizedString());
+ break;
+ case SHUTDOWN_PENDING_AFTER_FAILED_STARTUP:
+ buffer.append(LocalizedStrings.AgentLauncher_SHUTDOWN_PENDING_AFTER_FAILED_STARTUP.toLocalizedString());
+ break;
+ default:
+ buffer.append(LocalizedStrings.AgentLauncher_UNKNOWN.toLocalizedString());
+ break;
+ }
+
+ if (exception != null) {
+ if (msg != null) {
+ buffer.append("\n").append(msg).append(" - ");
+ }
+ else {
+ buffer.append("\n " + LocalizedStrings.AgentLauncher_EXCEPTION_IN_0_1
+ .toLocalizedString(this.baseName, exception.getMessage()) + " - ");
+ }
+ buffer.append(LocalizedStrings.AgentLauncher_SEE_LOG_FILE_FOR_DETAILS.toLocalizedString());
+ }
+ }
+
+ return buffer.toString();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/CacheServerJmxImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/CacheServerJmxImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/CacheServerJmxImpl.java
new file mode 100644
index 0000000..78d868b
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/CacheServerJmxImpl.java
@@ -0,0 +1,633 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+import javax.naming.OperationNotSupportedException;
+
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.admin.AdminException;
+import com.gemstone.gemfire.admin.CacheServerConfig;
+import com.gemstone.gemfire.admin.CacheVmConfig;
+import com.gemstone.gemfire.admin.ConfigurationParameter;
+import com.gemstone.gemfire.admin.StatisticResource;
+import com.gemstone.gemfire.admin.SystemMemberCache;
+import com.gemstone.gemfire.admin.SystemMemberCacheEvent;
+import com.gemstone.gemfire.admin.SystemMemberRegionEvent;
+import com.gemstone.gemfire.admin.internal.CacheServerImpl;
+import com.gemstone.gemfire.admin.internal.ConfigurationParameterImpl;
+import com.gemstone.gemfire.internal.admin.ClientMembershipMessage;
+import com.gemstone.gemfire.internal.admin.GemFireVM;
+import com.gemstone.gemfire.internal.admin.StatResource;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+import com.gemstone.gemfire.internal.logging.LogService;
+
+/**
+ * MBean representation of a {@link
+ * com.gemstone.gemfire.admin.CacheVm}.
+ *
+ * @author David Whitlock
+ * @since 4.0
+ */
+public class CacheServerJmxImpl extends CacheServerImpl
+ implements ManagedResource, CacheVmConfig, CacheServerConfig, SystemMemberJmx {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /**
+ * Interval in seconds between refreshes. Value less than one results in no
+ * refreshing
+ */
+ private int refreshInterval = 0;
+
+ /** The object name of this managed resource */
+ private ObjectName objectName;
+
+ /** The name of the MBean that will manage this resource */
+ private String mbeanName;
+
+ /** The ModelMBean that is configured to manage this resource */
+ private ModelMBean modelMBean;
+
+ /** Reference to the cache MBean representing a Cache in the Cache VM Member */
+ private SystemMemberCacheJmxImpl managedSystemMemberCache;
+
+ /** collection to collect all the resources created for this member */
+ private Map<StatResource, StatisticResourceJmxImpl> managedStatisticsResourcesMap = new HashMap<StatResource, StatisticResourceJmxImpl>();
+
+ ////////////////////// Constructors //////////////////////
+
+ /**
+ * Creates a new <code>CacheServerJmxImpl</code> for an existing
+ * cache server.
+ */
+ CacheServerJmxImpl(AdminDistributedSystemJmxImpl system,
+ GemFireVM vm)
+ throws AdminException {
+
+ super(system, vm);
+ initializeMBean();
+ }
+
+ /**
+ * Creates a new <code>CacheServerJmxImpl</code> for an
+ * newly-created cache server.
+ */
+ CacheServerJmxImpl(AdminDistributedSystemJmxImpl system,
+ CacheVmConfig config)
+ throws AdminException {
+
+ super(system, config);
+ initializeMBean();
+ }
+
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Creates and registers the MBean to manage this resource
+ */
+ private void initializeMBean()
+ throws AdminException {
+ //initialize Managed Resources for stats & cache first.
+// initializeManagedResources();
+
+ this.mbeanName = new StringBuffer("GemFire.CacheVm:")
+ .append("id=")
+ .append(MBeanUtil.makeCompliantMBeanNameProperty(getId()))
+ .append(",type=")
+ .append(MBeanUtil.makeCompliantMBeanNameProperty(getType().getName()))
+ .toString();
+
+ this.objectName = MBeanUtil.createMBean(this,
+ addDynamicAttributes(MBeanUtil.lookupManagedBean(this)));
+
+ // Refresh Interval
+ AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl)system;
+ if (sysJmx.getRefreshInterval()>0)
+ this.refreshInterval = sysJmx.getRefreshInterval();
+ }
+
+ public String getMBeanName() {
+ return this.mbeanName;
+ }
+
+ public ModelMBean getModelMBean() {
+ return this.modelMBean;
+ }
+ public void setModelMBean(ModelMBean modelMBean) {
+ this.modelMBean = modelMBean;
+ }
+
+ public ObjectName getObjectName() {
+ return this.objectName;
+ }
+
+ public ManagedResourceType getManagedResourceType() {
+ return ManagedResourceType.CACHE_VM;
+ }
+
+ /**
+ * Un-registers all the statistics & cache managed resource created for this
+ * member. After un-registering the resource MBean instances, clears
+ * managedStatisticsResourcesMap collection & sets managedSystemMemberCache
+ * to null.
+ *
+ * Creates ConfigurationParameterJmxImpl, StatisticResourceJmxImpl and
+ * SystemMemberCacheJmxImpl. But cleans up only StatisticResourceJmxImpl and
+ * SystemMemberCacheJmxImpl which are of type ManagedResource.
+ */
+ public void cleanupResource() {
+ synchronized (this.managedStatisticsResourcesMap) {
+ ConfigurationParameter[] names = getConfiguration();
+ if (names != null) {
+ for (int i = 0; i < names.length; i++) {
+ ConfigurationParameter parm = names[i];
+ ((ConfigurationParameterImpl) parm).removeConfigurationParameterListener(this);
+ }
+ }
+ this.parms.clear();
+
+ Collection<StatisticResourceJmxImpl> statisticResources = managedStatisticsResourcesMap.values();
+
+ for (StatisticResourceJmxImpl statisticResource : statisticResources) {
+ MBeanUtil.unregisterMBean(statisticResource);
+ }
+
+ this.managedStatisticsResourcesMap.clear();
+ }
+
+ MBeanUtil.unregisterMBean(this.managedSystemMemberCache);
+ this.managedSystemMemberCache = null;
+ }
+
+ /////////////////////// Configuration ///////////////////////
+
+ @Override
+ public String getHost() {
+ return this.getConfig().getHost();
+ }
+
+ public void setHost(String host) {
+ this.getConfig().setHost(host);
+ }
+
+ @Override
+ public String getWorkingDirectory() {
+ return this.getConfig().getWorkingDirectory();
+ }
+
+ @Override
+ public void setWorkingDirectory(String dir) {
+ this.getConfig().setWorkingDirectory(dir);
+ }
+
+ @Override
+ public String getProductDirectory() {
+ return this.getConfig().getProductDirectory();
+ }
+
+ @Override
+ public void setProductDirectory(String dir) {
+ this.getConfig().setProductDirectory(dir);
+ }
+
+ public String getRemoteCommand() {
+ return this.getConfig().getRemoteCommand();
+ }
+
+ public void setRemoteCommand(String remoteCommand) {
+ this.getConfig().setRemoteCommand(remoteCommand);
+ }
+
+ public void validate() {
+ throw new UnsupportedOperationException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString());
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ throw new UnsupportedOperationException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString());
+ }
+
+ public String getCacheXMLFile() {
+ return this.getConfig().getCacheXMLFile();
+ }
+
+ public void setCacheXMLFile(String cacheXMLFile) {
+ this.getConfig().setCacheXMLFile(cacheXMLFile);
+ }
+
+ public String getClassPath() {
+ return this.getConfig().getClassPath();
+ }
+
+ public void setClassPath(String classpath) {
+ this.getConfig().setClassPath(classpath);
+ }
+
+ // -------------------------------------------------------------------------
+ // MBean attribute accessors/mutators
+ // -------------------------------------------------------------------------
+
+ /**
+ * Gets the interval in seconds between config refreshes
+ *
+ * @return the current refresh interval in seconds
+ */
+ public int getRefreshInterval() {
+ return this.refreshInterval;
+ }
+
+ /**
+ * Sets interval in seconds between cache config refreshes; zero or less turns
+ * off auto refreshing. Manual refreshing has no effect on when the next
+ * scheduled refresh will occur.
+ *
+ * @param refreshInterval the new refresh interval in seconds
+ */
+ public void _setRefreshInterval(int refreshInterval) {
+ boolean isRegistered = MBeanUtil.isRefreshNotificationRegistered(this,
+ RefreshNotificationType.SYSTEM_MEMBER_CONFIG);
+
+ if (isRegistered && (getRefreshInterval() == refreshInterval))
+ return;
+
+ this.refreshInterval = Helper.setAndReturnRefreshInterval(this, refreshInterval);
+ }
+
+ /**
+ * RefreshInterval is now set only through the AdminDistributedSystem property
+ * refreshInterval. Attempt to set refreshInterval on CacheServerJmx MBean
+ * would result in an OperationNotSupportedException Auto-refresh is enabled
+ * on demand when a call to refreshConfig is made
+ *
+ * @param refreshInterval
+ * the new refresh interval in seconds
+ * @deprecated since 6.0 use DistributedSystemConfig.refreshInterval instead
+ */
+ @Deprecated
+ public void setRefreshInterval(int refreshInterval)
+ throws OperationNotSupportedException {
+ throw new OperationNotSupportedException(
+ LocalizedStrings.MANAGED_RESOURCE_REFRESH_INTERVAL_CANT_BE_SET_DIRECTLY.toLocalizedString());
+ }
+
+ // -------------------------------------------------------------------------
+ // MBean Operations
+ // -------------------------------------------------------------------------
+
+ public void refreshConfig()
+ throws com.gemstone.gemfire.admin.AdminException {
+ // 1st call to refreshConfig would trigger
+ // the auto-refresh if an interval is set
+ if (this.refreshInterval>0) {
+ this._setRefreshInterval(this.refreshInterval);
+ }
+
+ super.refreshConfig();
+ }
+
+ /**
+ * Initializes Cache & Statistics managed resources.
+ *
+ * @throws AdminException
+ * if initialization of managed resources fails
+ */
+// private void initializeManagedResources() throws AdminException {
+// try {
+// manageCache();
+// } catch (MalformedObjectNameException e) {
+// throw new AdminException(LocalizedStrings.SystemMemberJmxImpl_EXCEPTION_OCCURRED_WHILE_INITIALIZING_0_MBEANS_FOR_1.toLocalizedString(
+// new Object[] {"Cache", getId()}),
+// e);
+// } catch (AdminException ae) {
+// if (LocalizedStrings.SystemMemberJmx_THIS_SYSTEM_MEMBER_DOES_NOT_HAVE_A_CACHE.toLocalizedString().equals(ae.getMessage())) {
+// //ignore this exception for a cache-less peer
+// } else {
+// throw ae;
+// }
+// }
+// try {
+// manageStats();
+// } catch (MalformedObjectNameException e) {
+// throw new AdminException(LocalizedStrings.SystemMemberJmxImpl_EXCEPTION_OCCURRED_WHILE_INITIALIZING_0_MBEANS_FOR_1.toLocalizedString(
+// new Object[] {"Statistics", getId()}),
+// e);
+// }
+// }
+
+ /**
+ * Gets this member's cache.
+ *
+ * @return array of ObjectName for this member's cache
+ */
+ public ObjectName manageCache()
+ throws AdminException, MalformedObjectNameException {
+ return Helper.manageCache(this);
+ }
+
+ /**
+ * Gets all active StatisticResources for this manager.
+ *
+ * @return array of ObjectName instances
+ */
+ public ObjectName[] manageStats()
+ throws AdminException, MalformedObjectNameException {
+ return Helper.manageStats(this);
+ }
+
+ /**
+ * Gets the active StatisticResources for this manager, based on the
+ * typeName as the key
+ *
+ * @return ObjectName of StatisticResourceJMX instance
+ */
+ public ObjectName[] manageStat(String statisticsTypeName)
+ throws AdminException, MalformedObjectNameException {
+
+ return Helper.manageStat(this, statisticsTypeName);
+ }
+
+ // -------------------------------------------------------------------------
+ // JMX Notification listener
+ // -------------------------------------------------------------------------
+
+ /**
+ * Handles notification to refresh. Reacts by refreshing the values of this
+ * GemFireManager's ConfigurationParamaters. Any other notification is
+ * ignored. Given notification is handled only if there is any JMX client
+ * connected to the system.
+ *
+ * @param notification
+ * the JMX notification being received
+ * @param hb
+ * handback object is unused
+ */
+ public void handleNotification(Notification notification, Object hb) {
+ AdminDistributedSystemJmxImpl systemJmx =
+ (AdminDistributedSystemJmxImpl) this.system;
+
+ if (!systemJmx.isRmiClientCountZero()) {
+ Helper.handleNotification(this, notification, hb);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Template methods overriden from superclass...
+ // -------------------------------------------------------------------------
+
+ /**
+ * Template method for creating instance of ConfigurationParameter.
+ * Overridden to return ConfigurationParameterJmxImpl.
+ */
+ @Override
+ protected ConfigurationParameter createConfigurationParameter(String name,
+ String description,
+ Object value,
+ Class type,
+ boolean userModifiable) {
+ return new ConfigurationParameterJmxImpl(
+ name, description, value, type, userModifiable);
+ }
+
+
+
+ /**
+ * Override createStatisticResource by instantiating StatisticResourceJmxImpl
+ * if it was not created earlier otherwise returns the same instance.
+ *
+ * @param stat
+ * StatResource reference for which this JMX resource is to be created
+ * @return StatisticResourceJmxImpl - JMX Implementation of StatisticResource
+ * @throws AdminException
+ * if constructing StatisticResourceJmxImpl instance fails
+ */
+ @Override
+ protected StatisticResource createStatisticResource(StatResource stat)
+ throws com.gemstone.gemfire.admin.AdminException {
+ StatisticResourceJmxImpl managedStatisticResource = null;
+
+ synchronized (this.managedStatisticsResourcesMap) {
+ /*
+ * Ensuring that a single instance of Statistic Resource is created per
+ * StatResource.
+ */
+ StatisticResourceJmxImpl statisticResourceJmxImpl = managedStatisticsResourcesMap.get(stat);
+ if (statisticResourceJmxImpl != null) {
+ managedStatisticResource = statisticResourceJmxImpl;
+ } else {
+ managedStatisticResource = new StatisticResourceJmxImpl(stat, this);
+ managedStatisticResource.getStatistics();//inits timer
+ managedStatisticsResourcesMap.put(stat, managedStatisticResource);
+ }
+ }
+ return managedStatisticResource;
+ }
+
+ /**
+ * Override createSystemMemberCache by instantiating SystemMemberCacheJmxImpl
+ * if it was not created earlier.
+ *
+ * @param vm
+ * GemFireVM reference for which this JMX resource is to be created
+ * @return SystemMemberCacheJmxImpl - JMX Implementation of SystemMemberCache
+ * @throws AdminException
+ * if constructing SystemMemberCacheJmxImpl instance fails
+ */
+ @Override
+ protected SystemMemberCache createSystemMemberCache(GemFireVM vm)
+ throws com.gemstone.gemfire.admin.AdminException {
+ if (managedSystemMemberCache == null) {
+ managedSystemMemberCache = new SystemMemberCacheJmxImpl(vm);
+ }
+ return managedSystemMemberCache;
+ }
+
+ // -------------------------------------------------------------------------
+ // Create MBean attributes for each ConfigurationParameter
+ // -------------------------------------------------------------------------
+
+ /**
+ * Add MBean attribute definitions for each ConfigurationParameter.
+ *
+ * @param managed the mbean definition to add attributes to
+ * @return a new instance of ManagedBean copied from <code>managed</code> but
+ * with the new attributes added
+ */
+ public ManagedBean addDynamicAttributes(ManagedBean managed)
+ throws com.gemstone.gemfire.admin.AdminException {
+ return Helper.addDynamicAttributes(this, managed);
+ }
+
+ /**
+ * Cleans up Managed Resources created for the client that was connected to
+ * the server represented by this class.
+ *
+ * @param clientId
+ * id of the client to be removed
+ * @return List of ManagedResources associated with the client of given client
+ * id
+ */
+ /*
+ * This clean up is for the clients. The clients are started with a loner DM.
+ * Hence the clientId is not supposed to contain '/' as per
+ * InternalDistributedMember.toString().
+ */
+ public List<ManagedResource> cleanupBridgeClientResources(String clientId) {
+ List<ManagedResource> returnedResources = new ArrayList<ManagedResource>();
+
+ String compatibleId = "id_"+MBeanUtil.makeCompliantMBeanNameProperty(clientId);
+ synchronized (this.managedStatisticsResourcesMap) {
+ Set<Entry<StatResource, StatisticResourceJmxImpl>> entrySet = this.managedStatisticsResourcesMap.entrySet();
+
+ for (Iterator<Entry<StatResource, StatisticResourceJmxImpl>> it = entrySet.iterator(); it.hasNext();) {
+ Entry<StatResource, StatisticResourceJmxImpl> entry = it.next();
+ StatisticResourceJmxImpl resource = entry.getValue();
+ if (resource.getMBeanName().contains(compatibleId)) {
+ it.remove(); //remove matching entry
+ returnedResources.add(resource);
+ }
+ }
+ }
+ return returnedResources;
+ }
+
+ /**
+ * Implementation handles client membership changes.
+ *
+ * @param clientId
+ * id of the client for whom membership change happened
+ * @param eventType
+ * membership change type; one of
+ * {@link ClientMembershipMessage#JOINED},
+ * {@link ClientMembershipMessage#LEFT},
+ * {@link ClientMembershipMessage#CRASHED}
+ */
+ public void handleClientMembership(String clientId, int eventType) {
+ String notifType = null;
+ List<ManagedResource> cleanedUp = null;
+
+ if (eventType == ClientMembershipMessage.LEFT) {
+ notifType = NOTIF_CLIENT_LEFT;
+ cleanedUp = cleanupBridgeClientResources(clientId);
+ } else if (eventType == ClientMembershipMessage.CRASHED) {
+ notifType = NOTIF_CLIENT_CRASHED;
+ cleanedUp = cleanupBridgeClientResources(clientId);
+ } else if (eventType == ClientMembershipMessage.JOINED) {
+ notifType = NOTIF_CLIENT_JOINED;
+ }
+
+ if (cleanedUp != null) {
+ for (ManagedResource resource : cleanedUp) {
+ MBeanUtil.unregisterMBean(resource);
+ }
+ }
+
+ Helper.sendNotification(this,
+ new Notification(notifType, this.modelMBean,
+ Helper.getNextNotificationSequenceNumber(),
+ clientId));
+ }
+
+ /**
+ * Implementation handles creation of cache by extracting the details from the
+ * given event object and sending the
+ * {@link SystemMemberJmx#NOTIF_CACHE_CREATED} notification to the connected
+ * JMX Clients.
+ *
+ * @param event
+ * event object corresponding to the creation of the cache
+ */
+ public void handleCacheCreate(SystemMemberCacheEvent event) {
+ Helper.sendNotification(this,
+ new Notification(NOTIF_CACHE_CREATED, this.modelMBean,
+ Helper.getNextNotificationSequenceNumber(),
+ Helper.getCacheEventDetails(event)));
+ }
+
+ /**
+ * Implementation handles closure of cache by extracting the details from the
+ * given event object and sending the
+ * {@link SystemMemberJmx#NOTIF_CACHE_CLOSED} notification to the connected
+ * JMX Clients.
+ *
+ * @param event
+ * event object corresponding to the closure of the cache
+ */
+ public void handleCacheClose(SystemMemberCacheEvent event) {
+ Helper.sendNotification(this,
+ new Notification(NOTIF_CACHE_CLOSED, this.modelMBean,
+ Helper.getNextNotificationSequenceNumber(),
+ Helper.getCacheEventDetails(event)));
+ }
+
+ /**
+ * Implementation handles creation of region by extracting the details from
+ * the given event object and sending the
+ * {@link SystemMemberJmx#NOTIF_REGION_CREATED} notification to the connected
+ * JMX Clients. Region Path is set as User Data in Notification.
+ *
+ * @param event
+ * event object corresponding to the creation of a region
+ */
+ public void handleRegionCreate(SystemMemberRegionEvent event) {
+ Notification notification = new Notification(NOTIF_REGION_CREATED,
+ this.modelMBean,
+ Helper.getNextNotificationSequenceNumber(),
+ Helper.getRegionEventDetails(event));
+
+ notification.setUserData(event.getRegionPath());
+
+ Helper.sendNotification(this, notification);
+ }
+
+ /**
+ * Implementation should handle loss of region by extracting the details from
+ * the given event object and sending the
+ * {@link SystemMemberJmx#NOTIF_REGION_LOST} notification to the connected
+ * JMX Clients. Region Path is set as User Data in Notification. Additionally,
+ * it also clears the ManagedResources created for the region that is lost.
+ *
+ * @param event
+ * event object corresponding to the loss of a region
+ */
+ public void handleRegionLoss(SystemMemberRegionEvent event) {
+ SystemMemberCacheJmxImpl cacheResource = this.managedSystemMemberCache;
+
+ if (cacheResource != null) {
+ ManagedResource cleanedUp =
+ cacheResource.cleanupRegionResources(event.getRegionPath());
+
+ if (cleanedUp != null) {
+ MBeanUtil.unregisterMBean(cleanedUp);
+ }
+ }
+
+ Notification notification = new Notification(NOTIF_REGION_LOST,
+ this.modelMBean,
+ Helper.getNextNotificationSequenceNumber(),
+ Helper.getRegionEventDetails(event));
+
+ notification.setUserData(event.getRegionPath());
+
+ Helper.sendNotification(this, notification);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigAttributeInfo.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigAttributeInfo.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigAttributeInfo.java
new file mode 100755
index 0000000..6b11710
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigAttributeInfo.java
@@ -0,0 +1,69 @@
+/*
+ * =========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ * ========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+//import com.gemstone.gemfire.admin.ConfigurationParameter;
+import com.gemstone.gemfire.internal.Assert;
+
+import javax.management.Descriptor;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.modelmbean.ModelMBeanAttributeInfo;
+
+/**
+ * Subclass of AttributeInfo with {@link
+ * com.gemstone.gemfire.admin.ConfigurationParameter} added for use as the
+ * {@link javax.management.modelmbean.ModelMBeanAttributeInfo} descriptor's
+ * <i>targetObject</i> value.
+ *
+ * @author Kirk Lund
+ * @since 3.5
+ *
+ */
+class ConfigAttributeInfo extends org.apache.commons.modeler.AttributeInfo {
+ private static final long serialVersionUID = -1918437700841687078L;
+
+ private final ConfigurationParameterJmxImpl config;
+
+ public ConfigAttributeInfo(ConfigurationParameterJmxImpl config) {
+ super();
+ this.config = config;
+ }
+
+ public ConfigurationParameterJmxImpl getConfig() {
+ return this.config;
+ }
+
+ @Override
+ public ModelMBeanAttributeInfo createAttributeInfo() {
+ Descriptor desc = new DescriptorSupport(
+ new String[] {
+ "name=" + this.displayName,
+ "descriptorType=attribute",
+ "currencyTimeLimit=-1", // always stale
+ "displayName=" + this.displayName,
+ "getMethod=getJmxValue",
+ "setMethod=setJmxValue"
+ });
+
+ Assert.assertTrue(this.config != null, "Config target object is null!");
+ desc.setField("targetObject", this.config);
+
+ ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo(
+ this.displayName, // name
+ this.type, // type
+ this.description, // description
+ this.readable, // isReadable
+ this.writeable, // isWritable
+ this.is, // isIs
+ desc);
+
+ return info;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigurationParameterJmxImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigurationParameterJmxImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigurationParameterJmxImpl.java
new file mode 100755
index 0000000..e75fa02
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/ConfigurationParameterJmxImpl.java
@@ -0,0 +1,161 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.logging.log4j.Level;
+
+import com.gemstone.gemfire.SystemFailure;
+import com.gemstone.gemfire.admin.UnmodifiableConfigurationException;
+import com.gemstone.gemfire.internal.Assert;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+/**
+ * Provides MBean support for managing accessing a ConfigurationParameter.
+ * <p>
+ * Implements java.io.Serializable because several MBeans have attributes of
+ * type ConfigurationParameter. This means that calls to getMBeanInfo which
+ * may be serialized for remote clients will be broken unless those attributes
+ * support serialization.
+ * <p>
+ * TODO: refactor to implement ConfigurationParameter and delegate to
+ * ConfigurationParameterImpl. Wrap all delegate calls w/ e.printStackTrace()
+ * since the HttpAdaptor devours them
+ *
+ * @author Kirk Lund
+ * @since 3.5
+ *
+ */
+public class ConfigurationParameterJmxImpl
+extends com.gemstone.gemfire.admin.internal.ConfigurationParameterImpl
+implements Serializable {
+
+ private static final long serialVersionUID = -7822171853906772375L;
+ private boolean deserialized = false;
+
+ // -------------------------------------------------------------------------
+ // Constructor(s)
+ // -------------------------------------------------------------------------
+
+ protected ConfigurationParameterJmxImpl(String name,
+ String description,
+ Object value,
+ Class type,
+ boolean userModifiable) {
+ super(name, description, value, type, userModifiable);
+ }
+
+ protected ConfigurationParameterJmxImpl(String name,
+ Object value) {
+ super(name, value);
+ }
+
+ /** Constructor to allow serialization */
+ protected ConfigurationParameterJmxImpl() { super(); }
+
+ @Override
+ public void setValue(Object value) throws UnmodifiableConfigurationException {
+ if (deserialized) {
+ throw new UnsupportedOperationException(LocalizedStrings.ConfigurationParameterJmxImpl_REMOTE_MUTATION_OF_CONFIGURATIONPARAMETER_IS_CURRENTLY_UNSUPPORTED.toLocalizedString());
+ }
+ try {
+ super.setValue(value);
+ } catch (UnmodifiableConfigurationException e) {
+ MBeanUtil.logStackTrace(Level.WARN, e);
+ throw e;
+ } catch (java.lang.RuntimeException e) {
+ MBeanUtil.logStackTrace(Level.WARN, e);
+ throw e;
+ } catch (VirtualMachineError err) {
+ SystemFailure.initiateFailure(err);
+ // If this ever returns, rethrow the error. We're poisoned
+ // now, so don't let this thread continue.
+ throw err;
+ } catch (java.lang.Error e) {
+ // Whenever you catch Error or Throwable, you must also
+ // catch VirtualMachineError (see above). However, there is
+ // _still_ a possibility that you are dealing with a cascading
+ // error condition, so you also need to check to see if the JVM
+ // is still usable:
+ SystemFailure.checkFailure();
+ MBeanUtil.logStackTrace(Level.ERROR, e);
+ throw e;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // HACK
+ // -------------------------------------------------------------------------
+ public void setJmxValue(Integer value) throws UnmodifiableConfigurationException {
+ setValue(value);
+ }
+ public void setJmxValue(String value) throws UnmodifiableConfigurationException {
+ setValue(value);
+ }
+ public void setJmxValue(java.io.File value) throws UnmodifiableConfigurationException {
+ setValue(value);
+ }
+ public void setJmxValue(Boolean value) throws UnmodifiableConfigurationException {
+ setValue(value);
+ }
+
+ public Class getJmxValueType() {
+ if (isInetAddress() || isFile() || isOctal()) {
+ return java.lang.String.class;
+ }
+ return getValueType();
+ }
+
+ public Object getJmxValue() {
+ if (isInetAddress() || isFile() || isOctal()) {
+ return getValueAsString();
+ }
+ return getValue();
+ }
+
+ /**
+ * Override writeObject which is used in serialization. This class is
+ * serialized when JMX client acquires MBeanInfo for ConfigurationParameter
+ * MBean. Super class is not serializable.
+ */
+ private void writeObject(java.io.ObjectOutputStream out)
+ throws IOException {
+ out.writeObject(this.name);
+ out.writeObject(this.description);
+ out.writeObject(this.value);
+ out.writeObject(this.type);
+ out.writeBoolean(this.userModifiable);
+ }
+
+ /**
+ * Override readObject which is used in serialization. Customize
+ * serialization of this exception to avoid escape of InternalRole
+ * which is not Serializable.
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ String inName = (String) in.readObject();
+ String inDescription = (String) in.readObject();
+ Object inValue = in.readObject();
+ Class inClass = (Class) in.readObject();
+ boolean inUserModifiable = in.readBoolean();
+
+ Assert.assertTrue(inName != null);
+ Assert.assertTrue(inDescription != null);
+ Assert.assertTrue(inValue != null);
+ Assert.assertTrue(inClass != null);
+
+ this.deserialized = true;
+ this.name = inName;
+ setInternalState(inDescription, inValue, inClass, inUserModifiable);
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributedSystemHealthConfigJmxImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributedSystemHealthConfigJmxImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributedSystemHealthConfigJmxImpl.java
new file mode 100644
index 0000000..1326aa1
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributedSystemHealthConfigJmxImpl.java
@@ -0,0 +1,99 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+import com.gemstone.gemfire.admin.*;
+import com.gemstone.gemfire.admin.internal.*;
+//import com.gemstone.gemfire.internal.admin.*;
+import javax.management.*;
+import javax.management.modelmbean.*;
+//import org.apache.commons.modeler.ManagedBean;
+
+/**
+ * The JMX "managed resource" that represents the configuration for
+ * the health of a distributed system. Basically, it provides the
+ * behavior of <code>DistributedSystemHealthConfigImpl</code>, but
+ * does some JMX stuff like registering beans with the agent.
+ *
+ * @see GemFireHealthJmxImpl#createDistributedSystemHealthConfig
+ *
+ * @author David Whitlock
+ *
+ * @since 3.5
+ */
+public class DistributedSystemHealthConfigJmxImpl
+ extends DistributedSystemHealthConfigImpl
+ implements ManagedResource {
+
+ /** The <code>GemFireHealth</code> that we help configure */
+ private GemFireHealth health;
+
+ /** The name of the MBean that will manage this resource */
+ private String mbeanName;
+
+ /** The ModelMBean that is configured to manage this resource */
+ private ModelMBean modelMBean;
+
+ /** The JMX object name of the MBean for this managed resource */
+ private final ObjectName objectName;
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>DistributedSystemHealthCOnfigJmxImpl</code>
+ * that configures the health of the distributed system monitored by
+ * <code>health</code>.
+ */
+ DistributedSystemHealthConfigJmxImpl(GemFireHealthJmxImpl health)
+ throws AdminException {
+
+ super();
+ this.health = health;
+ this.mbeanName = new StringBuffer()
+ .append(MBEAN_NAME_PREFIX)
+ .append("DistributedSystemHealthConfig,id=")
+ .append(MBeanUtil.makeCompliantMBeanNameProperty(health.getDistributedSystem().getId()))
+ .toString();
+ this.objectName = MBeanUtil.createMBean(this);
+ }
+
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Applies the changes made to this config back to the health
+ * monitor.
+ *
+ * @see GemFireHealth#setDistributedSystemHealthConfig
+ */
+ public void applyChanges() {
+ this.health.setDistributedSystemHealthConfig(this);
+ }
+
+ public String getMBeanName() {
+ return this.mbeanName;
+ }
+
+ public ModelMBean getModelMBean() {
+ return this.modelMBean;
+ }
+
+ public void setModelMBean(ModelMBean modelMBean) {
+ this.modelMBean = modelMBean;
+ }
+
+ public ManagedResourceType getManagedResourceType() {
+ return ManagedResourceType.DISTRIBUTED_SYSTEM_HEALTH_CONFIG;
+ }
+
+ public ObjectName getObjectName() {
+ return this.objectName;
+ }
+
+ public void cleanupResource() {}
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributionLocatorJmxImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributionLocatorJmxImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributionLocatorJmxImpl.java
new file mode 100755
index 0000000..d3800d0
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DistributionLocatorJmxImpl.java
@@ -0,0 +1,178 @@
+/*=========================================================================
+ *Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *All Rights Reserved.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+//import com.gemstone.gemfire.admin.AdminException;
+//import com.gemstone.gemfire.admin.DistributionLocator;
+import com.gemstone.gemfire.admin.DistributionLocatorConfig;
+import com.gemstone.gemfire.admin.internal.AdminDistributedSystemImpl;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+//import com.gemstone.gemfire.internal.Assert;
+
+//import org.apache.commons.modeler.ManagedBean;
+//import org.apache.commons.modeler.AttributeInfo;
+
+//import java.util.Date;
+//import java.util.Set;
+
+//import javax.management.Attribute;
+//import javax.management.AttributeList;
+//import javax.management.Descriptor;
+//import javax.management.JMException;
+//import javax.management.MBeanServer;
+//import javax.management.MalformedObjectNameException;
+//import javax.management.Notification;
+//import javax.management.NotificationListener;
+import javax.management.ObjectName;
+//import javax.management.modelmbean.DescriptorSupport;
+import javax.management.modelmbean.ModelMBean;
+//import javax.management.modelmbean.ModelMBeanAttributeInfo;
+
+/**
+ * Provides MBean support for managing a distribution locator.
+ *
+ * @author Kirk Lund
+ */
+public class DistributionLocatorJmxImpl
+extends com.gemstone.gemfire.admin.internal.DistributionLocatorImpl
+implements com.gemstone.gemfire.admin.jmx.internal.ManagedResource,
+ DistributionLocatorConfig {
+
+ /** The JMX object name of this managed resource */
+ private ObjectName objectName;
+
+ // -------------------------------------------------------------------------
+ // Constructor(s)
+ // -------------------------------------------------------------------------
+
+ /**
+ * Constructs new instance of DistributionLocatorJmxImpl for managing a
+ * distribution locator service via JMX.
+ */
+ public DistributionLocatorJmxImpl(DistributionLocatorConfig config,
+ AdminDistributedSystemImpl system) {
+ super(config, system);
+ initializeMBean();
+ }
+
+ /** Create and register the MBean to manage this resource */
+ private void initializeMBean() {
+ this.mbeanName = "GemFire:type=DistributionLocator,id=" + MBeanUtil.makeCompliantMBeanNameProperty(getId());
+ this.objectName =
+ MBeanUtil.createMBean(this, MBeanUtil.lookupManagedBean(this));
+ }
+
+ //////////////////////// Configuration ////////////////////////
+
+ public String getHost() {
+ return this.getConfig().getHost();
+ }
+
+ public void setHost(String host) {
+ this.getConfig().setHost(host);
+ }
+
+ public String getWorkingDirectory() {
+ return this.getConfig().getWorkingDirectory();
+ }
+
+ public void setWorkingDirectory(String dir) {
+ this.getConfig().setWorkingDirectory(dir);
+ }
+
+ public String getProductDirectory() {
+ return this.getConfig().getProductDirectory();
+ }
+
+ public void setProductDirectory(String dir) {
+ this.getConfig().setProductDirectory(dir);
+ }
+
+ public String getRemoteCommand() {
+ return this.getConfig().getRemoteCommand();
+ }
+
+ public void setRemoteCommand(String remoteCommand) {
+ this.getConfig().setRemoteCommand(remoteCommand);
+ }
+
+ public java.util.Properties getDistributedSystemProperties() {
+ return this.getConfig().getDistributedSystemProperties();
+ }
+
+ public void setDistributedSystemProperties(java.util.Properties props) {
+ this.getConfig().setDistributedSystemProperties(props);
+ }
+
+ public void validate() {
+ throw new UnsupportedOperationException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString());
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ throw new UnsupportedOperationException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString());
+ }
+
+ public int getPort() {
+ return this.getConfig().getPort();
+ }
+
+ public void setPort(int port) {
+ this.getConfig().setPort(port);
+ }
+
+ public String getBindAddress() {
+ return this.getConfig().getBindAddress();
+ }
+
+ public void setBindAddress(String bindAddress) {
+ this.getConfig().setBindAddress(bindAddress);
+ }
+
+ // -------------------------------------------------------------------------
+ // MBean attributes - accessors/mutators
+ // -------------------------------------------------------------------------
+
+ // -------------------------------------------------------------------------
+ // JMX Notification listener
+ // -------------------------------------------------------------------------
+
+ // -------------------------------------------------------------------------
+ // ManagedResource implementation
+ // -------------------------------------------------------------------------
+
+ /** The name of the MBean that will manage this resource */
+ private String mbeanName;
+
+ /** The ModelMBean that is configured to manage this resource */
+ private ModelMBean modelMBean;
+
+ public String getMBeanName() {
+ return this.mbeanName;
+ }
+
+ public ModelMBean getModelMBean() {
+ return this.modelMBean;
+ }
+ public void setModelMBean(ModelMBean modelMBean) {
+ this.modelMBean = modelMBean;
+ }
+
+ public ObjectName getObjectName() {
+ return this.objectName;
+ }
+
+ public ManagedResourceType getManagedResourceType() {
+ return ManagedResourceType.DISTRIBUTION_LOCATOR;
+ }
+
+ public void cleanupResource() {}
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DynamicManagedBean.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DynamicManagedBean.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DynamicManagedBean.java
new file mode 100755
index 0000000..a54d11a
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/DynamicManagedBean.java
@@ -0,0 +1,134 @@
+/*
+ * =========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ * ========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.modeler.AttributeInfo;
+import org.apache.commons.modeler.OperationInfo;
+import org.apache.commons.modeler.ManagedBean;
+
+/**
+ * Extends ManagedBean to allow for dynamically creating new instances of
+ * ManagedBean based on an existing instance of ManagedBean.
+ *
+ * @author Kirk Lund
+ * @since 5.0.1
+ */
+public class DynamicManagedBean extends org.apache.commons.modeler.ManagedBean {
+ private static final long serialVersionUID = 4051924500150228160L;
+
+ public DynamicManagedBean(ManagedBean managed) {
+ super();
+
+ this.attributes = managed.getAttributes();
+ this.className = managed.getClassName();
+ this.constructors = managed.getConstructors();
+ this.description = managed.getDescription();
+ this.domain = managed.getDomain();
+ this.group = managed.getGroup();
+ this.name = managed.getName();
+ this.fields = managed.getFields();
+ this.notifications = managed.getNotifications();
+ this.operations = managed.getOperations();
+ this.type = managed.getType();
+
+ /* we don't use modelerType and it's nice to remove it to keep the list of
+ attributes cleaned up...*/
+ removeAttribute("modelerType");
+ }
+
+ /**
+ * Removes an attribute from this ManagedBean's attribute descriptor list.
+ *
+ * @param name the attribute to be removed
+ */
+ public void removeAttribute(String name) {
+ if (name == null || name.length() < 1) {
+ return;
+ }
+ synchronized (this.attributes) {
+ List attributesList = new ArrayList(this.attributes.length);
+ for (int i = 0; i < this.attributes.length; i++) {
+ if (!name.equals(this.attributes[i].getName())) {
+ attributesList.add(this.attributes[i]);
+ }
+ }
+ this.attributes = (AttributeInfo[])
+ attributesList.toArray(new AttributeInfo[attributesList.size()]);
+
+ /* super.info should be nulled out anytime the structure is changed,
+ * such as altering the attributes, operations, or notifications
+ *
+ * however super.info is private, so we need the following hack to cause
+ * the super class to null it out for us...
+ */
+ setType(this.type); // causes this in super: "this.info = null;"
+ }
+ }
+
+ /**
+ * Removes the operation with the given name from thie
+ * <code>ManageBean</code>'s operation descriptor list.
+ *
+ * @since 4.0
+ */
+ public void removeOperation(String name) {
+ if (name == null || name.length() < 1) {
+ return;
+ }
+
+ synchronized (operations) {
+ List operationsList = new ArrayList(this.operations.length);
+ for (int i = 0; i < this.operations.length; i++) {
+ if (!name.equals(this.operations[i].getName())) {
+ operationsList.add(this.operations[i]);
+ }
+ }
+ this.operations = (OperationInfo[])
+ operationsList.toArray(new OperationInfo[operationsList.size()]);
+
+ /* super.info should be nulled out anytime the structure is changed,
+ * such as altering the operations, operations, or notifications
+ *
+ * however super.info is private, so we need the following hack to cause
+ * the super class to null it out for us...
+ */
+ setType(this.type); // causes this in super: "this.info = null;"
+ }
+ }
+
+ /**
+ * Return a string representation of this managed bean.
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer("DynamicManagedBean[");
+ sb.append("name=");
+ sb.append(name);
+ sb.append(", className=");
+ sb.append(className);
+ sb.append(", description=");
+ sb.append(description);
+ if (group != null) {
+ sb.append(", group=");
+ sb.append(group);
+ }
+ sb.append(", type=");
+ sb.append(type);
+ sb.append(", attributes=");
+ sb.append(Arrays.asList(attributes));
+ sb.append("]");
+ return (sb.toString());
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/19459053/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/GemFireHealthConfigJmxImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/GemFireHealthConfigJmxImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/GemFireHealthConfigJmxImpl.java
new file mode 100644
index 0000000..478d344
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/admin/jmx/internal/GemFireHealthConfigJmxImpl.java
@@ -0,0 +1,214 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+package com.gemstone.gemfire.admin.jmx.internal;
+
+import com.gemstone.gemfire.admin.*;
+import com.gemstone.gemfire.admin.internal.*;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import javax.management.*;
+import javax.management.modelmbean.*;
+
+/**
+ * The JMX "managed resource" that represents the configuration for
+ * the health of GemFire. Basically, it provides the behavior of
+ * <code>GemFireHealthConfigImpl</code>, but does some JMX stuff like
+ * registering beans with the agent.
+ *
+ * <P>
+ *
+ * Unlike other <code>ManagedResource</code>s this class cannot simply
+ * subclass <code>GemFireHealthImpl</code> because it instances are
+ * serialized and sent to other VMs. This is problematic because the
+ * other VMs most likely do not have JMX classes like
+ * <code>ModelMBean</code> on their classpaths. So, instead we
+ * delegate all of the <code>GemFireHealthConfig</code> behavior to
+ * another object which IS serialized.
+ *
+ * @see GemFireHealthJmxImpl#createDistributedSystemHealthConfig
+ *
+ * @author David Whitlock
+ *
+ * @since 3.5
+ */
+@SuppressFBWarnings(justification="This class is deprecated. Also, any further changes so close to the release is inadvisable.")
+public class GemFireHealthConfigJmxImpl
+ implements GemFireHealthConfig, ManagedResource, java.io.Serializable {
+
+ private static final long serialVersionUID = 1482719647163239953L;
+
+ /** The <code>GemFireHealth</code> that we help configure */
+ private GemFireHealth health;
+
+ /** The name of the MBean that will manage this resource */
+ private String mbeanName;
+
+ /** The ModelMBean that is configured to manage this resource */
+ private ModelMBean modelMBean;
+
+ /** The delegate that contains the real config state */
+ private GemFireHealthConfig delegate;
+
+ /** The object name of this managed resource */
+ private ObjectName objectName;
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>GemFireHealthConfigJmxImpl</code> that
+ * configures the health monitoring of components running on the
+ * given host.
+ */
+ GemFireHealthConfigJmxImpl(GemFireHealthJmxImpl health,
+ String hostName)
+ throws AdminException {
+
+ this.delegate = new GemFireHealthConfigImpl(hostName);
+ this.health = health;
+ this.mbeanName = new StringBuffer()
+ .append(MBEAN_NAME_PREFIX)
+ .append("GemFireHealthConfig,id=")
+ .append(MBeanUtil.makeCompliantMBeanNameProperty(health.getDistributedSystem().getId()))
+ .append(",host=")
+ .append((hostName == null ? "default" : MBeanUtil.makeCompliantMBeanNameProperty(hostName)))
+ .toString();
+ this.objectName = MBeanUtil.createMBean(this);
+ }
+
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Applies the changes made to this config back to the health
+ * monitor.
+ *
+ * @see GemFireHealth#setDistributedSystemHealthConfig
+ */
+ public void applyChanges() {
+ String hostName = this.getHostName();
+ if (hostName == null) {
+ this.health.setDefaultGemFireHealthConfig(this);
+
+ } else {
+ this.health.setGemFireHealthConfig(hostName, this);
+ }
+ }
+
+ public String getMBeanName() {
+ return this.mbeanName;
+ }
+
+ public ModelMBean getModelMBean() {
+ return this.modelMBean;
+ }
+
+ public ObjectName getObjectName() {
+ return this.objectName;
+ }
+
+ public void setModelMBean(ModelMBean modelMBean) {
+ this.modelMBean = modelMBean;
+ }
+
+ public ManagedResourceType getManagedResourceType() {
+ return ManagedResourceType.GEMFIRE_HEALTH_CONFIG;
+ }
+
+ /**
+ * Replace this object with the delegate that can be properly
+ * serialized.
+ */
+ public Object writeReplace() {
+ return this.delegate;
+ }
+
+ ////////////////////// MemberHealthConfig //////////////////////
+
+ public long getMaxVMProcessSize() {
+ return delegate.getMaxVMProcessSize();
+ }
+
+ public void setMaxVMProcessSize(long size) {
+ delegate.setMaxVMProcessSize(size);
+ }
+
+ public long getMaxMessageQueueSize() {
+ return delegate.getMaxMessageQueueSize();
+ }
+
+ public void setMaxMessageQueueSize(long maxMessageQueueSize) {
+ delegate.setMaxMessageQueueSize(maxMessageQueueSize);
+ }
+
+ public long getMaxReplyTimeouts() {
+ return delegate.getMaxReplyTimeouts();
+ }
+
+ public void setMaxReplyTimeouts(long maxReplyTimeouts) {
+ delegate.setMaxReplyTimeouts(maxReplyTimeouts);
+ }
+
+ public double getMaxRetransmissionRatio() {
+ return delegate.getMaxRetransmissionRatio();
+ }
+
+ public void setMaxRetransmissionRatio(double ratio) {
+ delegate.setMaxRetransmissionRatio(ratio);
+ }
+
+ ////////////////////// CacheHealthConfig //////////////////////
+
+ public long getMaxNetSearchTime() {
+ return delegate.getMaxNetSearchTime();
+ }
+
+ public void setMaxNetSearchTime(long maxNetSearchTime) {
+ delegate.setMaxNetSearchTime(maxNetSearchTime);
+ }
+
+ public long getMaxLoadTime() {
+ return delegate.getMaxLoadTime();
+ }
+
+ public void setMaxLoadTime(long maxLoadTime) {
+ delegate.setMaxLoadTime(maxLoadTime);
+ }
+
+ public double getMinHitRatio() {
+ return delegate.getMinHitRatio();
+ }
+
+ public void setMinHitRatio(double minHitRatio) {
+ delegate.setMinHitRatio(minHitRatio);
+ }
+
+ public long getMaxEventQueueSize() {
+ return delegate.getMaxEventQueueSize();
+ }
+
+ public void setMaxEventQueueSize(long maxEventQueueSize) {
+ delegate.setMaxEventQueueSize(maxEventQueueSize);
+ }
+
+ ////////////////////// GemFireHealthConfig //////////////////////
+
+ public String getHostName() {
+ return delegate.getHostName();
+ }
+
+ public void setHealthEvaluationInterval(int interval) {
+ delegate.setHealthEvaluationInterval(interval);
+ }
+
+ public int getHealthEvaluationInterval() {
+ return delegate.getHealthEvaluationInterval();
+ }
+
+ public void cleanupResource() {}
+
+}