geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [60/93] incubator-geode git commit: GEODE-288: move admin package to internal
Date Wed, 26 Oct 2016 22:49:26 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthConfigJmxImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthConfigJmxImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthConfigJmxImpl.java
new file mode 100644
index 0000000..23e9038
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthConfigJmxImpl.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.admin.api.jmx.impl;
+
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.GemFireHealth;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.internal.admin.api.impl.GemFireHealthConfigImpl;
+
+/**
+ * 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
+ *
+ *
+ * @since GemFire 3.5
+ */
+@edu.umd.cs.findbugs.annotations.SuppressWarnings(
+    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() {}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthJmxImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthJmxImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthJmxImpl.java
new file mode 100644
index 0000000..fcff9be
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthJmxImpl.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.admin.api.jmx.impl;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.DistributedSystemHealthConfig;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.internal.admin.api.RuntimeAdminException;
+import org.apache.geode.internal.admin.api.impl.GemFireHealthImpl;
+import org.apache.geode.internal.admin.GfManagerAgent;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+// import org.apache.commons.modeler.ManagedBean;
+
+/**
+ * The JMX "managed resource" that represents the health of GemFire. Basically, it provides the
+ * behavior of <code>GemFireHealthImpl</code>, but does some JMX stuff like registering beans with
+ * the agent.
+ *
+ * @see AdminDistributedSystemJmxImpl#createGemFireHealth
+ *
+ *
+ * @since GemFire 3.5
+ */
+public class GemFireHealthJmxImpl extends GemFireHealthImpl implements ManagedResource {
+
+  private static final Logger logger = LogService.getLogger();
+
+  /** 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 object name of the MBean created for this managed resource */
+  private final ObjectName objectName;
+
+  /////////////////////// Constructors ///////////////////////
+
+  /**
+   * Creates a new <code>GemFireHealthJmxImpl</code> that monitors the health of the given
+   * distributed system and uses the given JMX agent.
+   */
+  GemFireHealthJmxImpl(GfManagerAgent agent, AdminDistributedSystemJmxImpl system)
+      throws AdminException {
+
+    super(agent, system);
+    this.mbeanName = new StringBuffer().append(MBEAN_NAME_PREFIX).append("GemFireHealth,id=")
+        .append(MBeanUtil.makeCompliantMBeanNameProperty(system.getId())).toString();
+    this.objectName = MBeanUtil.createMBean(this);
+  }
+
+  ////////////////////// Instance Methods //////////////////////
+
+  public String getHealthStatus() {
+    return getHealth().toString();
+  }
+
+  public ObjectName manageGemFireHealthConfig(String hostName) throws MalformedObjectNameException {
+    try {
+      GemFireHealthConfig config = getGemFireHealthConfig(hostName);
+      GemFireHealthConfigJmxImpl jmx = (GemFireHealthConfigJmxImpl) config;
+      return new ObjectName(jmx.getMBeanName());
+    } // catch (AdminException e) { logWriter.warning(e); throw e; }
+    catch (RuntimeException e) {
+      logger.warn(e.getMessage(), 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 (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();
+      logger.error(e.getMessage(), e);
+      throw e;
+    }
+  }
+
+  /**
+   * Creates a new {@link DistributedSystemHealthConfigJmxImpl}
+   */
+  @Override
+  protected DistributedSystemHealthConfig createDistributedSystemHealthConfig() {
+
+    try {
+      return new DistributedSystemHealthConfigJmxImpl(this);
+
+    } catch (AdminException ex) {
+      throw new RuntimeAdminException(
+          LocalizedStrings.GemFireHealthJmxImpl_WHILE_GETTING_THE_DISTRIBUTEDSYSTEMHEALTHCONFIG
+              .toLocalizedString(),
+          ex);
+    }
+  }
+
+  /**
+   * Creates a new {@link GemFireHealthConfigJmxImpl}
+   */
+  @Override
+  protected GemFireHealthConfig createGemFireHealthConfig(String hostName) {
+
+    try {
+      return new GemFireHealthConfigJmxImpl(this, hostName);
+
+    } catch (AdminException ex) {
+      throw new RuntimeAdminException(
+          LocalizedStrings.GemFireHealthJmxImpl_WHILE_GETTING_THE_GEMFIREHEALTHCONFIG
+              .toLocalizedString(),
+          ex);
+    }
+  }
+
+  /**
+   * Ensures that the three primary Health MBeans are registered and returns their ObjectNames.
+   */
+  protected void ensureMBeansAreRegistered() {
+    MBeanUtil.ensureMBeanIsRegistered(this);
+    MBeanUtil.ensureMBeanIsRegistered((ManagedResource) this.defaultConfig);
+    MBeanUtil.ensureMBeanIsRegistered((ManagedResource) this.dsHealthConfig);
+  }
+
+  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.GEMFIRE_HEALTH;
+  }
+
+  public ObjectName getObjectName() {
+    return this.objectName;
+  }
+
+  public void cleanupResource() {
+    close();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GenerateMBeanHTML.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GenerateMBeanHTML.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GenerateMBeanHTML.java
new file mode 100644
index 0000000..bdf4d36
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GenerateMBeanHTML.java
@@ -0,0 +1,500 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.admin.api.jmx.impl;
+
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+import java.io.*;
+
+/**
+ * A tool that reads the XML description of MBeans used with the Jakarta Commons Modeler and
+ * generates an HTML file that documents each MBean.
+ *
+ * @since GemFire 3.5
+ */
+public class GenerateMBeanHTML extends DefaultHandler {
+
+  /** The location of the DTD for the MBean descriptions */
+  private static final String DTD_LOCATION = "/org/apache/geode/internal/admin/api/jmx/impl/doc-files/mbeans-descriptors.dtd";
+
+  // /** The system id of MBean description's DTD */
+  // private static final String SYSTEM_ID =
+  // "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd";
+
+  // /** The public id for the DTD */
+  // private static final String PUBLIC_ID =
+  // "-//Apache Software Foundation//DTD Model MBeans Configuration File";
+
+  /** The name of the "mbean-descriptors" element */
+  private static final String MBEANS_DESCRIPTORS = "mbeans-descriptors";
+
+  /** The name of the "mbean" element */
+  private static final String MBEAN = "mbean";
+
+  /** The name of the "name" attribute */
+  private static final String NAME = "name";
+
+  /** The name of the "description" attribute */
+  private static final String DESCRIPTION = "description";
+
+  /** The name of the "type" attribute */
+  private static final String TYPE = "type";
+
+  /** The name of the "attribute" element */
+  private static final String ATTRIBUTE = "attribute";
+
+  /** The name of the "writeable" attribute */
+  private static final String WRITEABLE = "writeable";
+
+  /** The name of the "operation" element */
+  private static final String OPERATION = "operation";
+
+  /** The name of the "returnType" attribute */
+  private static final String RETURN_TYPE = "returnType";
+
+  /** The name of the "paremeter" element */
+  private static final String PARAMETER = "parameter";
+
+  /** The name of the "notification" element */
+  private static final String NOTIFICATION = "notification";
+
+  // /** The name of the "description" element */
+  // private static final String DESCRIPTOR = "descriptor";
+
+  /** The name of the "field" element */
+  private static final String FIELD = "field";
+
+  /** The name of the "value" attribute */
+  private static final String VALUE = "value";
+
+  ////////////////////// Instance Fields ///////////////////////
+
+  /** Where the generated HTML data is written */
+  private PrintWriter pw;
+
+  /** Have we seen attributes for the current MBean? */
+  private boolean seenAttribute = false;
+
+  /** Have we seen operations for the current MBean? */
+  private boolean seenOperation = false;
+
+  /** Have we seen notifications for the current MBean? */
+  private boolean seenNotifications = false;
+
+  /////////////////////// Static Methods ///////////////////////
+
+  /**
+   * Converts data from the given <code>InputStream</code> into HTML that is written to the given
+   * <code>PrintWriter</code>
+   */
+  private static void convert(InputStream in, PrintWriter out) throws Exception {
+
+    SAXParserFactory factory = SAXParserFactory.newInstance();
+    factory.setValidating(true);
+    SAXParser parser = factory.newSAXParser();
+    DefaultHandler handler = new GenerateMBeanHTML(out);
+    parser.parse(in, handler);
+  }
+
+  //////////////////////// Constructors ////////////////////////
+
+  /**
+   * Creates a new <code>GenerateMBeanHTML</code> that writes to the given <code>PrintWriter</code>.
+   */
+  private GenerateMBeanHTML(PrintWriter pw) {
+    this.pw = pw;
+  }
+
+  ////////////////////// Instance Methods //////////////////////
+
+  /**
+   * Given a public id, attempt to resolve it to a DTD. Returns an <code>InputSoure</code> for the
+   * DTD.
+   */
+  @Override
+  public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
+
+    if (publicId == null || systemId == null) {
+      throw new SAXException(LocalizedStrings.GenerateMBeanHTML_PUBLIC_ID_0_SYSTEM_ID_1
+          .toLocalizedString(new Object[] {publicId, systemId}));
+    }
+
+    // Figure out the location for the publicId.
+    String location = DTD_LOCATION;
+
+    InputSource result;
+    // if (location != null) (cannot be null)
+    {
+      InputStream stream = ClassPathLoader.getLatest().getResourceAsStream(getClass(), location);
+      if (stream != null) {
+        result = new InputSource(stream);
+      } else {
+        throw new SAXNotRecognizedException(
+            LocalizedStrings.GenerateMBeanHTML_DTD_NOT_FOUND_0.toLocalizedString(location));
+      }
+
+      // } else {
+      // throw new
+      // SAXNotRecognizedException(LocalizedStrings.GenerateMBeanHTML_COULD_NOT_FIND_DTD_FOR_0_1.toLocalizedString(new
+      // Object[] {publicId, systemId}));
+    }
+
+    return result;
+  }
+
+  /**
+   * Warnings are ignored
+   */
+  @Override
+  public void warning(SAXParseException ex) throws SAXException {
+
+  }
+
+  /**
+   * Rethrow the <code>SAXParseException</code>
+   */
+  @Override
+  public void error(SAXParseException ex) throws SAXException {
+    throw ex;
+  }
+
+  /**
+   * Rethrow the <code>SAXParseException</code>
+   */
+  @Override
+  public void fatalError(SAXParseException ex) throws SAXException {
+    throw ex;
+  }
+
+  /**
+   * Starts the HTML document
+   */
+  private void startMBeansDescriptors() {
+    pw.println("<HTML>");
+    pw.println("<HEAD>");
+    pw.println("<TITLE>GemFire MBeans Interface</TITLE>");
+    pw.println("</HEAD>");
+    pw.println("");
+    pw.println("<h1>GemFire Management Beans</h1>");
+    pw.println("");
+    pw.println("<P>This document describes the attributes, operations,");
+    pw.println("and notifications of the GemFire Administration");
+    pw.println("Management Beans (MBeans).</P>");
+    pw.println("");
+  }
+
+  /**
+   * Ends the HTML document
+   */
+  private void endMBeansDescriptors() {
+    pw.println("</HTML>");
+  }
+
+  /**
+   * Generates a heading and a table declaration for an MBean
+   */
+  private void startMBean(Attributes atts) {
+    String name = atts.getValue(NAME);
+    /* String description = */ atts.getValue(DESCRIPTION);
+    pw.println("<h2><b>" + name + "</b> MBean</h2>");
+    pw.println("<table border=\"0\" cellpadding=\"3\">");
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <th align=\"left\">Description:</th>");
+    pw.println("  <td colspan=\"4\">GemFire distributed system</td>");
+    pw.println("</tr>");
+  }
+
+  /**
+   * Ends the MBean table
+   */
+  private void endMBean() {
+    this.seenAttribute = false;
+    this.seenOperation = false;
+    this.seenNotifications = false;
+
+    pw.println("</table>");
+    pw.println("");
+
+    pw.println("<P></P>");
+    pw.println("");
+  }
+
+  /**
+   * Generates a table row for an MBean attribute
+   */
+  private void startAttribute(Attributes atts) {
+    if (!this.seenAttribute) {
+      // Print header row
+      pw.println("<tr valign=\"top\">");
+      pw.println("  <th align=\"left\">Attributes</th>");
+      pw.println("  <th align=\"left\" colspan=\"2\">Name</th>");
+      pw.println("  <th align=\"left\">Type</th>");
+      pw.println("  <th align=\"left\">Description</th>");
+      pw.println("  <th align=\"left\">Writable</th>");
+      pw.println("</tr>");
+
+    }
+
+    this.seenAttribute = true;
+
+    String name = atts.getValue(NAME);
+    String description = atts.getValue(DESCRIPTION);
+    String type = atts.getValue(TYPE);
+    String writeable = atts.getValue(WRITEABLE);
+
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <td></td>");
+    pw.println("  <td colspan=\"2\">" + name + "</td>");
+    pw.println("  <td>" + type + "</td>");
+    pw.println("  <td>" + description + "</td>");
+    pw.println("  <td>" + writeable + "</td>");
+    pw.println("</tr>");
+  }
+
+  /**
+   * Generates a table row for an MBean operation
+   */
+  private void startOperation(Attributes atts) {
+    if (!this.seenOperation) {
+      if (!this.seenAttribute) {
+        pw.println("<tr valign=\"top\">");
+        pw.println("  <th align=\"left\">Operations</th>");
+        pw.println("  <th align=\"left\" colspan=\"2\">Name</th>");
+        pw.println("  <th align=\"left\">Type</th>");
+        pw.println("  <th align=\"left\">Description</th>");
+        pw.println("  <th align=\"left\"></th>");
+        pw.println("</tr>");
+
+      } else {
+        String title = "Operations and Parameters";
+        pw.println("<tr valign=\"top\">");
+        pw.println("  <th align=\"left\" colspan=\"6\">" + title + "</th>");
+        pw.println("</tr>");
+      }
+    }
+
+    this.seenOperation = true;
+
+    String name = atts.getValue(NAME);
+    String type = atts.getValue(RETURN_TYPE);
+    String description = atts.getValue(DESCRIPTION);
+
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <td></td>");
+    pw.println("  <td colspan=\"2\">" + name + "</td>");
+    pw.println("  <td>" + type + "</td>");
+    pw.println("  <td colspan=\"2\">" + description + "</td>");
+    pw.println("</tr>");
+
+  }
+
+  /**
+   * Generates a table row for the parameter of an MBean operation
+   */
+  private void startParameter(Attributes atts) {
+    String name = atts.getValue(NAME);
+    String description = atts.getValue(DESCRIPTION);
+    String type = atts.getValue(TYPE);
+
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <td></td>");
+    pw.println("  <td width=\"10\"></td>");
+    pw.println("  <td>" + name + "</td>");
+    pw.println("  <td>" + type + "</td>");
+    pw.println("  <td colspan=\"2\">" + description + "</td>");
+    pw.println("</tr>");
+  }
+
+  /**
+   * Generates a row in a table for an MBean notification
+   */
+  private void startNotification(Attributes atts) {
+    if (!this.seenNotifications) {
+      if (!this.seenAttribute && !this.seenOperation) {
+        pw.println("<tr valign=\"top\">");
+        pw.println("  <th align=\"left\">Notifications</th>");
+        pw.println("  <th align=\"left\" colspan=\"2\">Name</th>");
+        pw.println("  <th align=\"left\">Type</th>");
+        pw.println("  <th align=\"left\">Description</th>");
+        pw.println("  <th align=\"left\"></th>");
+        pw.println("</tr>");
+        pw.println("</tr>");
+
+      } else {
+        pw.println("<tr valign=\"top\">");
+        pw.println("  <th align=\"left\" colspan=\"6\">Notifications and Fields</th>");
+        pw.println("</tr>");
+      }
+    }
+
+    this.seenNotifications = true;
+
+    String name = atts.getValue(NAME);
+    String description = atts.getValue(DESCRIPTION);
+
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <td></td>");
+    pw.println("  <td colspan=\"3\">" + name + "</td>");
+    pw.println("  <td colspan=\"3\">" + description + "</td>");
+    pw.println("</tr>");
+
+  }
+
+  /**
+   * Generates a table row for a descriptor field
+   */
+  private void startField(Attributes atts) {
+    String name = atts.getValue(NAME);
+    String value = atts.getValue(VALUE);
+
+    pw.println("<tr valign=\"top\">");
+    pw.println("  <td></td>");
+    pw.println("  <td width=\"10\"></td>");
+    pw.println("  <td colspan=\"2\">" + name + "</td>");
+    pw.println("  <td colspan=\"2\">" + value + "</td>");
+    pw.println("</tr>");
+
+  }
+
+  @Override
+  public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
+      throws SAXException {
+
+    if (qName.equals(MBEANS_DESCRIPTORS)) {
+      startMBeansDescriptors();
+
+    } else if (qName.equals(MBEAN)) {
+      startMBean(atts);
+
+    } else if (qName.equals(ATTRIBUTE)) {
+      startAttribute(atts);
+
+    } else if (qName.equals(OPERATION)) {
+      startOperation(atts);
+
+    } else if (qName.equals(PARAMETER)) {
+      startParameter(atts);
+
+    } else if (qName.equals(NOTIFICATION)) {
+      startNotification(atts);
+
+    } else if (qName.equals(FIELD)) {
+      startField(atts);
+    }
+
+  }
+
+
+  @Override
+  public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+
+    if (qName.equals(MBEANS_DESCRIPTORS)) {
+      endMBeansDescriptors();
+
+    } else if (qName.equals(MBEAN)) {
+      endMBean();
+    }
+
+  }
+
+  ////////// Inherited methods that don't do anything //////////
+
+  @Override
+  public void characters(char[] ch, int start, int length) throws SAXException {
+
+  }
+
+  @Override
+  public void setDocumentLocator(Locator locator) {}
+
+  @Override
+  public void startDocument() throws SAXException {}
+
+  @Override
+  public void endDocument() throws SAXException {}
+
+  @Override
+  public void startPrefixMapping(String prefix, String uri) throws SAXException {}
+
+  @Override
+  public void endPrefixMapping(String prefix) throws SAXException {}
+
+  @Override
+  public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {}
+
+  @Override
+  public void processingInstruction(String target, String data) throws SAXException {}
+
+  @Override
+  public void skippedEntity(String name) throws SAXException {}
+
+  //////////////////////// Main Program ////////////////////////
+
+  // private static final PrintStream out = System.out;
+  private static final PrintStream err = System.err;
+
+  /**
+   * Prints usage information about this program
+   */
+  private static void usage(String s) {
+    err.println("\n** " + s + "\n");
+    err.println("usage: java GenerateMBeanHTML xmlFile htmlFile");
+    err.println("");
+    err.println("Converts an MBeans description XML file into an HTML");
+    err.println("file suitable for documentation");
+
+    err.println("");
+
+    System.exit(1);
+  }
+
+  public static void main(String[] args) throws Exception {
+    String xmlFileName = null;
+    String htmlFileName = null;
+
+    for (int i = 0; i < args.length; i++) {
+      if (xmlFileName == null) {
+        xmlFileName = args[i];
+
+      } else if (htmlFileName == null) {
+        htmlFileName = args[i];
+
+      } else {
+        usage("Extraneous command line argument: " + args[i]);
+      }
+    }
+
+    if (xmlFileName == null) {
+      usage("Missing XML file name");
+
+    } else if (htmlFileName == null) {
+      usage("Missing HTML file name");
+    }
+
+    File xmlFile = new File(xmlFileName);
+    if (!xmlFile.exists()) {
+      usage("XML file \"" + xmlFile + "\" does not exist");
+    }
+
+    File htmlFile = new File(htmlFileName);
+    convert(new FileInputStream(xmlFile), new PrintWriter(new FileWriter(htmlFile), true));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MBeanUtil.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MBeanUtil.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MBeanUtil.java
new file mode 100755
index 0000000..9e4ad36
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MBeanUtil.java
@@ -0,0 +1,765 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.admin.api.jmx.impl;
+
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.JMException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.timer.TimerMBean;
+
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.internal.admin.api.RuntimeAdminException;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+
+/**
+ * Common support for MBeans and {@link ManagedResource}s. Static loading of this class creates the
+ * MBeanServer and Modeler Registry.
+ *
+ * @since GemFire 3.5
+ *
+ */
+public class MBeanUtil {
+
+  private static final Logger logger = LogService.getLogger();
+
+  /** The default MBeanServer domain name is "GemFire" */
+  private static final String DEFAULT_DOMAIN = "GemFire";
+
+  /** MBean Name for refreshTimer */
+  private static String REFRESH_TIMER_NAME = DEFAULT_DOMAIN + ":type=RefreshTimer";
+
+  /* indicates whether the mbeanServer, registry & refreshTimer are started */
+  private static boolean isStarted;
+
+  /** The Commons-Modeler configuration registry for our managed beans */
+  private static Registry registry;
+
+  /** The <code>MBeanServer</code> for this application */
+  private static MBeanServer mbeanServer;
+
+  /** MBean name of the Timer which handles refresh notifications */
+  private static ObjectName refreshTimerObjectName;
+
+  /** Actual TimerMBean responsible for refresh notifications */
+  private static TimerMBean refreshTimer;
+
+  /**
+   * Map of ObjectNames to current timerNotificationIds
+   * <p>
+   * map: key=ObjectName, value=map: key=RefreshNotificationType, value=timerNotificationId
+   */
+  private static Map<NotificationListener, Map<RefreshNotificationType, Integer>> refreshClients =
+      new HashMap<NotificationListener, Map<RefreshNotificationType, Integer>>();
+
+  /** key=ObjectName, value=ManagedResource */
+  private final static Map<ObjectName, ManagedResource> managedResources =
+      new HashMap<ObjectName, ManagedResource>();
+
+  static {
+    try {
+      refreshTimerObjectName = ObjectName.getInstance(REFRESH_TIMER_NAME);
+    } catch (Exception e) {
+      logStackTrace(Level.ERROR, e);
+    }
+  }
+
+  /**
+   * Initializes Mbean Server, Registry, Refresh Timer & registers Server Notification Listener.
+   * 
+   * @return reference to the mbeanServer
+   */
+  static MBeanServer start() {
+    if (!isStarted) {
+      mbeanServer = createMBeanServer();
+      registry = createRegistry();
+
+      registerServerNotificationListener();
+      createRefreshTimer();
+      isStarted = true;
+    }
+
+    return mbeanServer;
+  }
+
+  /**
+   * Stops Registry, Refresh Timer. Releases Mbean Server after.
+   */
+  static void stop() {
+    if (isStarted) {
+      stopRefreshTimer();
+
+      registry.stop();
+      registry = null;
+      releaseMBeanServer();// makes mbeanServer null
+      isStarted = false;
+    }
+  }
+
+  /**
+   * Create and configure (if necessary) and return the <code>MBeanServer</code> with which we will
+   * be registering our <code>ModelMBean</code> implementations.
+   *
+   * @see javax.management.MBeanServer
+   */
+  static synchronized MBeanServer createMBeanServer() {
+    if (mbeanServer == null) {
+      mbeanServer = MBeanServerFactory.createMBeanServer(DEFAULT_DOMAIN);
+    }
+    return mbeanServer;
+  }
+
+  /**
+   * Create and configure (if necessary) and return the Commons-Modeler registry of managed object
+   * descriptions.
+   *
+   * @see org.apache.commons.modeler.Registry
+   */
+  static synchronized Registry createRegistry() {
+    if (registry == null) {
+      try {
+        registry = Registry.getRegistry(null, null);
+        if (mbeanServer == null) {
+          throw new IllegalStateException(
+              LocalizedStrings.MBeanUtil_MBEAN_SERVER_NOT_INITIALIZED_YET.toLocalizedString());
+        }
+        registry.setMBeanServer(mbeanServer);
+  
+        String mbeansResource = getOSPath("/org/apache/geode/internal/admin/api/jmx/mbeans-descriptors.xml");
+        //System.out.println(LocalizedStrings.MBeanUtil_LOADING_RESOURCE_0.toLocalizedString(mbeansResource));
+        
+        URL url = ClassPathLoader.getLatest().getResource(MBeanUtil.class, mbeansResource);
+        raiseOnFailure(url != null, LocalizedStrings.MBeanUtil_FAILED_TO_FIND_0
+            .toLocalizedString(new Object[] {mbeansResource}));
+        registry.loadMetadata(url);
+
+        // simple test to make sure the xml was actually loaded and is valid...
+        String[] test = registry.findManagedBeans();
+        raiseOnFailure(test != null && test.length > 0, LocalizedStrings.MBeanUtil_FAILED_TO_LOAD_0
+            .toLocalizedString(new Object[] {mbeansResource}));
+      } catch (Exception e) {
+        logStackTrace(Level.WARN, e);
+        throw new RuntimeAdminException(
+            LocalizedStrings.MBeanUtil_FAILED_TO_GET_MBEAN_REGISTRY.toLocalizedString(), e);
+      }
+    }
+    return registry;
+  }
+
+  /**
+   * Creates and registers a <code>ModelMBean</code> for the specified <code>ManagedResource</code>.
+   * State changing callbacks into the <code>ManagedResource</code> will also be made.
+   *
+   * @param resource the ManagedResource to create a managing MBean for
+   *
+   * @return The object name of the newly-created MBean
+   *
+   * @see ManagedResource#setModelMBean
+   */
+  static ObjectName createMBean(ManagedResource resource) {
+    return createMBean(resource, lookupManagedBean(resource));
+  }
+
+  /**
+   * Creates and registers a <code>ModelMBean</code> for the specified <code>ManagedResource</code>.
+   * State changing callbacks into the <code>ManagedResource</code> will also be made.
+   *
+   * @param resource the ManagedResource to create a managing MBean for
+   * @param managed the ManagedBean definition to create the MBean with
+   * @see ManagedResource#setModelMBean
+   */
+  static ObjectName createMBean(ManagedResource resource, ManagedBean managed) {
+
+    try {
+      DynamicManagedBean mb = new DynamicManagedBean(managed);
+      resource.setModelMBean(mb.createMBean(resource));
+
+      // create the ObjectName and register the MBean...
+      final ObjectName objName;
+      try {
+        objName = ObjectName.getInstance(resource.getMBeanName());
+      } catch (MalformedObjectNameException e) {
+        throw new MalformedObjectNameException(LocalizedStrings.MBeanUtil_0_IN_1
+            .toLocalizedString(new Object[] {e.getMessage(), resource.getMBeanName()}));
+      }
+
+      synchronized (MBeanUtil.class) {
+        // Only register a bean once. Otherwise, you risk race
+        // conditions with things like the RMI connector accessing it.
+
+        if (mbeanServer != null && !mbeanServer.isRegistered(objName)) {
+          mbeanServer.registerMBean(resource.getModelMBean(), objName);
+          synchronized (managedResources) {
+            managedResources.put(objName, resource);
+          }
+        }
+      }
+      return objName;
+    } catch (java.lang.Exception e) {
+      throw new RuntimeAdminException(LocalizedStrings.MBeanUtil_FAILED_TO_CREATE_MBEAN_FOR_0
+          .toLocalizedString(new Object[] {resource.getMBeanName()}), e);
+    }
+  }
+
+  /**
+   * Ensures that an MBean is registered for the specified <code>ManagedResource</code>. If an MBean
+   * cannot be found in the <code>MBeanServer</code>, then this creates and registers a
+   * <code>ModelMBean</code>. State changing callbacks into the <code>ManagedResource</code> will
+   * also be made.
+   *
+   * @param resource the ManagedResource to create a managing MBean for
+   *
+   * @return The object name of the MBean that manages the ManagedResource
+   *
+   * @see ManagedResource#setModelMBean
+   */
+  static ObjectName ensureMBeanIsRegistered(ManagedResource resource) {
+    try {
+      ObjectName objName = ObjectName.getInstance(resource.getMBeanName());
+      synchronized (MBeanUtil.class) {
+        if (mbeanServer != null && !mbeanServer.isRegistered(objName)) {
+          return createMBean(resource);
+        }
+      }
+      raiseOnFailure(mbeanServer.isRegistered(objName),
+          LocalizedStrings.MBeanUtil_COULDNT_FIND_MBEAN_REGISTERED_WITH_OBJECTNAME_0
+              .toLocalizedString(new Object[] {objName.toString()}));
+      return objName;
+    } catch (java.lang.Exception e) {
+      throw new RuntimeAdminException(e);
+    }
+  }
+
+  /**
+   * Retrieves the <code>ManagedBean</code> configuration from the Registry for the specified
+   * <code>ManagedResource</code>
+   *
+   * @param resource the ManagedResource to find the configuration for
+   */
+  static ManagedBean lookupManagedBean(ManagedResource resource) {
+    // find the registry defn for our MBean...
+    ManagedBean managed = null;
+    if (registry != null) {
+      managed = registry.findManagedBean(resource.getManagedResourceType().getClassTypeName());
+    } else {
+      throw new IllegalArgumentException(
+          LocalizedStrings.MBeanUtil_MANAGEDBEAN_IS_NULL.toLocalizedString());
+    }
+
+    if (managed == null) {
+      throw new IllegalArgumentException(
+          LocalizedStrings.MBeanUtil_MANAGEDBEAN_IS_NULL.toLocalizedString());
+    }
+
+    // customize the defn...
+    managed.setClassName(
+        "MX4JModelMBean");
+
+    return managed;
+  }
+
+  /**
+   * Registers a refresh notification for the specified client MBean. Specifying zero for the
+   * refreshInterval disables notification for the refresh client. Note: this does not currently
+   * support remote connections.
+   *
+   * @param client client to listen for refresh notifications
+   * @param userData userData to register with the Notification
+   * @param type refresh notification type the client will use
+   * @param refreshInterval the seconds between refreshes
+   */
+  static void registerRefreshNotification(NotificationListener client, Object userData,
+      RefreshNotificationType type, int refreshInterval) {
+    if (client == null) {
+      throw new IllegalArgumentException(
+          LocalizedStrings.MBeanUtil_NOTIFICATIONLISTENER_IS_REQUIRED.toLocalizedString());
+    }
+    if (type == null) {
+      throw new IllegalArgumentException(
+          LocalizedStrings.MBeanUtil_REFRESHNOTIFICATIONTYPE_IS_REQUIRED.toLocalizedString());
+    }
+    if (refreshTimerObjectName == null || refreshTimer == null) {
+      throw new IllegalStateException(
+          LocalizedStrings.MBeanUtil_REFRESHTIMER_HAS_NOT_BEEN_PROPERLY_INITIALIZED
+              .toLocalizedString());
+    }
+
+    try {
+      // get the notifications for the specified client...
+      Map<RefreshNotificationType, Integer> notifications = null;
+      synchronized (refreshClients) {
+        notifications = (Map<RefreshNotificationType, Integer>) refreshClients.get(client);
+      }
+
+      if (notifications == null) {
+        // If refreshInterval is being set to zero and notifications is removed return
+        if (refreshInterval <= 0) {
+          return;
+        }
+
+        // never registered before, so add client...
+        notifications = new HashMap<RefreshNotificationType, Integer>();
+        synchronized (refreshClients) {
+          refreshClients.put(client, notifications);
+        }
+        validateRefreshTimer();
+        try {
+          // register client as a listener with MBeanServer...
+          mbeanServer.addNotificationListener(refreshTimerObjectName, // timer to listen to
+              client, // the NotificationListener object
+              null, // optional NotificationFilter TODO: convert to using
+              new Object() // not used but null throws IllegalArgumentException
+          );
+        } catch (InstanceNotFoundException e) {
+          // should not happen since we already checked refreshTimerObjectName
+          logStackTrace(Level.WARN, e,
+              LocalizedStrings.MBeanUtil_COULD_NOT_FIND_REGISTERED_REFRESHTIMER_INSTANCE
+                  .toLocalizedString());
+        }
+      }
+
+      // TODO: change to manipulating timer indirectly thru mserver...
+
+      // check for pre-existing refresh notification entry...
+      Integer timerNotificationId = (Integer) notifications.get(type);
+      if (timerNotificationId != null) {
+        try {
+          // found one, so let's remove it...
+          refreshTimer.removeNotification(timerNotificationId);
+        } catch (InstanceNotFoundException e) {
+          // that's ok cause we just wanted to remove it anyway
+        } finally {
+          // null out the map entry for that notification type...
+          notifications.put(type, null);
+        }
+      }
+
+      if (refreshInterval > 0) {
+        // add notification to the refresh timer...
+        timerNotificationId = refreshTimer.addNotification(type.getType(), // type
+            type.getMessage(), // message = "refresh"
+            userData, // userData
+            new Date(System.currentTimeMillis() + refreshInterval * 1000), // first occurence
+            refreshInterval * 1000); // period to repeat
+
+        // put an entry into the map for the listener...
+        notifications.put(type, timerNotificationId);
+      } else {
+        // do nothing! refreshInterval must be over 0 to do anything...
+      }
+    } catch (java.lang.RuntimeException e) {
+      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();
+      logStackTrace(Level.ERROR, e);
+      throw e;
+    }
+  }
+
+  /**
+   * Verifies a refresh notification for the specified client MBean. If notification is not
+   * registered, then returns a false
+   *
+   * @param client client to listen for refresh notifications
+   * @param type refresh notification type the client will use
+   *
+   * @return isRegistered boolean indicating if a notification is registered
+   */
+  static boolean isRefreshNotificationRegistered(NotificationListener client,
+      RefreshNotificationType type) {
+    boolean isRegistered = false;
+
+    // get the notifications for the specified client...
+    Map<RefreshNotificationType, Integer> notifications = null;
+    synchronized (refreshClients) {
+      notifications = (Map<RefreshNotificationType, Integer>) refreshClients.get(client);
+    }
+
+    // never registered before if null ...
+    if (notifications != null) {
+      // check for pre-existing refresh notification entry...
+      Integer timerNotificationId = notifications.get(type);
+      if (timerNotificationId != null) {
+        isRegistered = true;
+      }
+    }
+
+    return isRegistered;
+  }
+
+  /**
+   * Validates refreshTimer has been registered without problems and attempts to re-register if
+   * there is a problem.
+   */
+  static void validateRefreshTimer() {
+    if (refreshTimerObjectName == null || refreshTimer == null) {
+      // if (refreshTimerObjectName == null) System.out.println("refreshTimerObjectName is null");
+      // if (refreshTimer == null) System.out.println("refreshTimer is null");
+      // System.out.println("[validateRefreshTimer] createRefreshTimer");
+      createRefreshTimer();
+    }
+
+    raiseOnFailure(refreshTimer != null, "Failed to validate Refresh Timer");
+
+    if (mbeanServer != null && !mbeanServer.isRegistered(refreshTimerObjectName)) {
+      // System.out.println("[validateRefreshTimer] registerMBean");
+      try {
+        mbeanServer.registerMBean(refreshTimer, refreshTimerObjectName);
+      } catch (JMException e) {
+        logStackTrace(Level.WARN, e);
+      } catch (JMRuntimeException e) {
+        logStackTrace(Level.WARN, e);
+      }
+    }
+  }
+
+  /**
+   * Initializes the timer for sending refresh notifications.
+   */
+  static void createRefreshTimer() {
+    try {
+      refreshTimer = new javax.management.timer.Timer();
+      mbeanServer.registerMBean(refreshTimer, refreshTimerObjectName);
+
+      refreshTimer.start();
+    } catch (JMException e) {
+      logStackTrace(Level.WARN, e,
+          LocalizedStrings.MBeanUtil_FAILED_TO_CREATE_REFRESH_TIMER.toLocalizedString());
+    } catch (JMRuntimeException e) {
+      logStackTrace(Level.WARN, e,
+          LocalizedStrings.MBeanUtil_FAILED_TO_CREATE_REFRESH_TIMER.toLocalizedString());
+    } catch (Exception e) {
+      logStackTrace(Level.WARN, e,
+          LocalizedStrings.MBeanUtil_FAILED_TO_CREATE_REFRESH_TIMER.toLocalizedString());
+    }
+  }
+
+  /**
+   * Initializes the timer for sending refresh notifications.
+   */
+  static void stopRefreshTimer() {
+    try {
+      if (refreshTimer != null && mbeanServer != null) {
+        mbeanServer.unregisterMBean(refreshTimerObjectName);
+
+        refreshTimer.stop();
+      }
+    } catch (JMException e) {
+      logStackTrace(Level.WARN, e);
+    } catch (JMRuntimeException e) {
+      logStackTrace(Level.WARN, e);
+    } catch (Exception e) {
+      logStackTrace(Level.DEBUG, e, "Failed to stop refresh timer for MBeanUtil");
+    }
+  }
+
+  /**
+   * Return a String that been modified to be compliant as a property of an ObjectName.
+   * <p>
+   * The property name of an ObjectName may not contain any of the following characters: <b><i>: , =
+   * * ?</i></b>
+   * <p>
+   * This method will replace the above non-compliant characters with a dash: <b><i>-</i></b>
+   * <p>
+   * If value is empty, this method will return the string "nothing".
+   * <p>
+   * Note: this is <code>public</code> because certain tests call this from outside of the package.
+   * TODO: clean this up
+   *
+   * @param value the potentially non-compliant ObjectName property
+   * @return the value modified to be compliant as an ObjectName property
+   */
+  public static String makeCompliantMBeanNameProperty(String value) {
+    value = value.replace(':', '-');
+    value = value.replace(',', '-');
+    value = value.replace('=', '-');
+    value = value.replace('*', '-');
+    value = value.replace('?', '-');
+    if (value.length() < 1) {
+      value = "nothing";
+    }
+    return value;
+  }
+
+  /**
+   * Unregisters all GemFire MBeans and then releases the MBeanServer for garbage collection.
+   */
+  static void releaseMBeanServer() {
+    try {
+      // unregister all GemFire mbeans...
+      Iterator iter = mbeanServer.queryNames(null, null).iterator();
+      while (iter.hasNext()) {
+        ObjectName name = (ObjectName) iter.next();
+        if (name.getDomain().startsWith(DEFAULT_DOMAIN)) {
+          unregisterMBean(name);
+        }
+      }
+
+      // last, release the mbean server...
+      MBeanServerFactory.releaseMBeanServer(mbeanServer);
+      mbeanServer = null;
+    } catch (JMRuntimeException e) {
+      logStackTrace(Level.WARN, e);
+    }
+    /*
+     * See #42391. Cleaning up the static maps which might be still holding references to
+     * ManagedResources
+     */
+    synchronized (MBeanUtil.managedResources) {
+      MBeanUtil.managedResources.clear();
+    }
+    synchronized (refreshClients) {
+      refreshClients.clear();
+    }
+    /*
+     * See #42391. Cleaning up the static maps which might be still holding references to
+     * ManagedResources
+     */
+    synchronized (MBeanUtil.managedResources) {
+      MBeanUtil.managedResources.clear();
+    }
+    synchronized (refreshClients) {
+      refreshClients.clear();
+    }
+  }
+
+  /**
+   * Returns true if a MBean with given ObjectName is registered.
+   * 
+   * @param objectName ObjectName to use for checking if MBean is registered
+   * @return true if MBeanServer is not null & MBean with given ObjectName is registered with the
+   *         MBeanServer
+   */
+  static boolean isRegistered(ObjectName objectName) {
+    return mbeanServer != null && mbeanServer.isRegistered(objectName);
+  }
+
+  /**
+   * Unregisters the identified MBean if it's registered.
+   */
+  static void unregisterMBean(ObjectName objectName) {
+    try {
+      if (mbeanServer != null && mbeanServer.isRegistered(objectName)) {
+        mbeanServer.unregisterMBean(objectName);
+      }
+    } catch (MBeanRegistrationException e) {
+      logStackTrace(Level.WARN, null,
+          LocalizedStrings.MBeanUtil_FAILED_WHILE_UNREGISTERING_MBEAN_WITH_OBJECTNAME_0
+              .toLocalizedString(new Object[] {objectName}));
+    } catch (InstanceNotFoundException e) {
+      logStackTrace(Level.WARN, null,
+          LocalizedStrings.MBeanUtil_WHILE_UNREGISTERING_COULDNT_FIND_MBEAN_WITH_OBJECTNAME_0
+              .toLocalizedString(new Object[] {objectName}));
+    } catch (JMRuntimeException e) {
+      logStackTrace(Level.WARN, null,
+          LocalizedStrings.MBeanUtil_COULD_NOT_UNREGISTER_MBEAN_WITH_OBJECTNAME_0
+              .toLocalizedString(new Object[] {objectName}));
+    }
+  }
+
+  static void unregisterMBean(ManagedResource resource) {
+    if (resource != null) {
+      unregisterMBean(resource.getObjectName());
+
+      // call cleanup on managedResource here and not rely on listener
+      // since it is possible that notification listener not deliver
+      // all notifications of un-registration. If resource is
+      // cleaned here, another call from the listener should be as good as a no-op
+      cleanupResource(resource);
+    }
+  }
+
+  // cleanup resource
+  private static void cleanupResource(ManagedResource resource) {
+    synchronized (MBeanUtil.managedResources) {
+      MBeanUtil.managedResources.remove(resource.getObjectName());
+    }
+    resource.cleanupResource();
+
+    // get the notifications for the specified client...
+    Map<RefreshNotificationType, Integer> notifications = null;
+    synchronized (refreshClients) {
+      notifications = (Map<RefreshNotificationType, Integer>) refreshClients.remove(resource);
+    }
+
+    // never registered before if null ...
+    // Also as of current, there is ever only 1 Notification type per
+    // MBean, so we do need need a while loop here
+    if (notifications != null) {
+
+      // Fix for findbugs reported inefficiency with keySet().
+      Set<Map.Entry<RefreshNotificationType, Integer>> entries = notifications.entrySet();
+
+      for (Map.Entry<RefreshNotificationType, Integer> e : entries) {
+        Integer timerNotificationId = e.getValue();
+        if (null != timerNotificationId) {
+          try {
+            // found one, so let's remove it...
+            refreshTimer.removeNotification(timerNotificationId);
+          } catch (InstanceNotFoundException xptn) {
+            // that's ok cause we just wanted to remove it anyway
+            logStackTrace(Level.DEBUG, xptn);
+          }
+        }
+      }
+
+      try {
+        if (mbeanServer != null && mbeanServer.isRegistered(refreshTimerObjectName)) {
+          // remove client as a listener with MBeanServer...
+          mbeanServer.removeNotificationListener(refreshTimerObjectName, // timer to listen to
+              (NotificationListener) resource // the NotificationListener object
+          );
+        }
+      } catch (ListenerNotFoundException xptn) {
+        // should not happen since we already checked refreshTimerObjectName
+        logStackTrace(Level.WARN, null, xptn.getMessage());
+      } catch (InstanceNotFoundException xptn) {
+        // should not happen since we already checked refreshTimerObjectName
+        logStackTrace(Level.WARN, null,
+            LocalizedStrings.MBeanUtil_WHILE_UNREGISTERING_COULDNT_FIND_MBEAN_WITH_OBJECTNAME_0
+                .toLocalizedString(new Object[] {refreshTimerObjectName}));
+      }
+    }
+  }
+  
+  // ----- borrowed the following from RemoteCommand -----
+  /** Translates the path between Windows and UNIX. */
+  static String getOSPath(String path) {
+    if (pathIsWindows(path)) {
+      return path.replace('/', '\\');
+    } else {
+      return path.replace('\\', '/');
+    }
+  }
+
+  /** Returns true if the path is on Windows. */
+  static boolean pathIsWindows(String path) {
+    if (path != null && path.length() > 1) {
+      return (Character.isLetter(path.charAt(0)) && path.charAt(1) == ':')
+          || (path.startsWith("//") || path.startsWith("\\\\"));
+    }
+    return false;
+  }
+
+  static void registerServerNotificationListener() {
+    if (mbeanServer == null) {
+      return;
+    }
+    try {
+      // the MBeanServerDelegate name is spec'ed as the following...
+      ObjectName delegate = ObjectName.getInstance("JMImplementation:type=MBeanServerDelegate");
+      mbeanServer.addNotificationListener(delegate, new NotificationListener() {
+        public void handleNotification(Notification notification, Object handback) {
+          MBeanServerNotification serverNotification = (MBeanServerNotification) notification;
+          if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION
+              .equals(serverNotification.getType())) {
+            ObjectName objectName = serverNotification.getMBeanName();
+            synchronized (MBeanUtil.managedResources) {
+              Object entry = MBeanUtil.managedResources.get(objectName);
+              if (entry == null)
+                return;
+              if (!(entry instanceof ManagedResource)) {
+                throw new ClassCastException(LocalizedStrings.MBeanUtil_0_IS_NOT_A_MANAGEDRESOURCE
+                    .toLocalizedString(new Object[] {entry.getClass().getName()}));
+              }
+              ManagedResource resource = (ManagedResource) entry;
+              {
+                // call cleanup on managedResource
+                cleanupResource(resource);
+              }
+            }
+          }
+        }
+      }, null, null);
+    } catch (JMException e) {
+      logStackTrace(Level.WARN, e,
+          LocalizedStrings.MBeanUtil_FAILED_TO_REGISTER_SERVERNOTIFICATIONLISTENER
+              .toLocalizedString());
+    } catch (JMRuntimeException e) {
+      logStackTrace(Level.WARN, e,
+          LocalizedStrings.MBeanUtil_FAILED_TO_REGISTER_SERVERNOTIFICATIONLISTENER
+              .toLocalizedString());
+    }
+  }
+
+  /**
+   * Logs the stack trace for the given Throwable if logger is initialized else prints the stack
+   * trace using System.out.
+   * 
+   * @param level severity level to log at
+   * @param throwable Throwable to log stack trace for
+   */
+  public static void logStackTrace(Level level, Throwable throwable) {
+    logStackTrace(level, throwable, null);
+  }
+
+  /**
+   * Logs the stack trace for the given Throwable if logger is initialized else prints the stack
+   * trace using System.out.
+   * 
+   * @param level severity level to log at
+   * @param throwable Throwable to log stack trace for
+   * @param message user friendly error message to show
+   */
+  public static void logStackTrace(Level level, Throwable throwable, String message) {
+    logger.log(level, message, throwable);
+  }
+
+  /**
+   * Raises RuntimeAdminException with given 'message' if given 'condition' is false.
+   * 
+   * @param condition condition to evaluate
+   * @param message failure message
+   */
+  private static void raiseOnFailure(boolean condition, String message) {
+    if (!condition) {
+      throw new RuntimeAdminException(message);
+    }
+  }
+}
+


Mime
View raw message