You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/10/26 22:11:31 UTC
[09/42] incubator-geode git commit: GEODE-288: move admin package to
internal
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/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..2969608
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthConfigJmxImpl.java
@@ -0,0 +1,222 @@
+/*
+ * 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/096b622d/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..8de503f
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GemFireHealthJmxImpl.java
@@ -0,0 +1,178 @@
+/*
+ * 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/096b622d/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..c25fdfa
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/GenerateMBeanHTML.java
@@ -0,0 +1,511 @@
+/*
+ * 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/096b622d/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..2c1465e
--- /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);
+ }
+ }
+}
+