Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6BBA4200BA6 for ; Tue, 18 Oct 2016 20:59:08 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 6A36F160AFD; Tue, 18 Oct 2016 18:59:08 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id BD9AC160ACE for ; Tue, 18 Oct 2016 20:59:05 +0200 (CEST) Received: (qmail 76195 invoked by uid 500); 18 Oct 2016 18:59:04 -0000 Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.incubator.apache.org Delivered-To: mailing list commits@geode.incubator.apache.org Received: (qmail 76186 invoked by uid 99); 18 Oct 2016 18:59:04 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd3-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Oct 2016 18:59:04 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd3-us-west.apache.org (ASF Mail Server at spamd3-us-west.apache.org) with ESMTP id 50A0718068A for ; Tue, 18 Oct 2016 18:59:04 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd3-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -6.219 X-Spam-Level: X-Spam-Status: No, score=-6.219 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd3-us-west.apache.org [10.40.0.10]) (amavisd-new, port 10024) with ESMTP id PLyGPs7nKvRo for ; Tue, 18 Oct 2016 18:58:51 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with SMTP id 7FC905F647 for ; Tue, 18 Oct 2016 18:58:46 +0000 (UTC) Received: (qmail 64218 invoked by uid 99); 18 Oct 2016 18:57:31 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Oct 2016 18:57:31 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3D167E69B2; Tue, 18 Oct 2016 18:57:31 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: klund@apache.org To: commits@geode.incubator.apache.org Date: Tue, 18 Oct 2016 18:57:36 -0000 Message-Id: In-Reply-To: <0cf5a50d71bb49f8b94bbdf30a4e4c93@git.apache.org> References: <0cf5a50d71bb49f8b94bbdf30a4e4c93@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [06/42] incubator-geode git commit: Move Admin API to internal archived-at: Tue, 18 Oct 2016 18:59:08 -0000 http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertsAggregator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertsAggregator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertsAggregator.java new file mode 100644 index 0000000..8edce21 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertsAggregator.java @@ -0,0 +1,124 @@ +/* + * 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.admin.GemFireVM; +import org.apache.geode.internal.admin.StatAlert; +import org.apache.geode.internal.admin.StatAlertDefinition; + +/** + * This interface represents an Aggregator entity and resides in JMXAgent. + * Responsibilities are as follows: + *
    + *
  1. set AlertsManager in the newly joined members + *
  2. create/update/remove alert + *
  3. manage refresh interval + *
  4. process notification from members + *
  5. Aggregate stats & make available for clients thro' JMXAgent + *
+ * + */ +public interface StatAlertsAggregator { + + /** + * This method can be used to get an alert definition. + * + * @param alertDefinition + * StatAlertDefinition to retrieve + * @return StatAlertDefinition + */ + public StatAlertDefinition getAlertDefinition( + StatAlertDefinition alertDefinition); + + /** + * This method can be used to retrieve all available stat alert definitions. + * + * @return An array of all available StatAlertDefinition objects + */ + public StatAlertDefinition[] getAllStatAlertDefinitions(); + + /** + * This method can be used to update alert definition for the Stat mentioned. + * This method should update the collection maintained at the aggregator and + * should notify members for the newly added alert definitions. + *

+ * A new alert definition will be created if matching one not found. + * + * @param alertDefinition + * alertDefinition to be updated + */ + public void updateAlertDefinition(StatAlertDefinition alertDefinition); + + /** + * This method can be used to remove alert definition for the Stat mentioned. + *

+ * This method should update the collection maintained at the aggregator and + * should notify members for the newly added alert definitions. + * + * @param defId + * id of the alert definition to be removed + */ + public void removeAlertDefinition(Integer defId); + + /** + * Convenience method to check whether an alert definition is created. + * + * @param alert + * alert definition to check whether already created + * @return true if the alert definition is already created, false otherwise + */ + public boolean isAlertDefinitionCreated(StatAlertDefinition alert); + + /** + * This method can be used to set the AlertManager for the newly joined member + * VM. + * + * @param memberVM + * Member VM to set AlertsManager for + */ + public void setAlertsManager(GemFireVM memberVM); + + /** + * Returns the refresh interval for the Stats in seconds. + * + * @return refresh interval for the Stats(in seconds) + */ + public int getRefreshIntervalForStatAlerts(); + + /** + * This method is used to set the refresh interval for the Stats Alerts in + * seconds + * + * @param refreshInterval + * refresh interval for the Stats(in seconds) + */ + public void setRefreshIntervalForStatAlerts(int refreshInterval); + + /** + * This method can be used to process the notifications sent by the member(s). + * Actual aggregation of stats can occur here. The array contains alert + * objects with alert def. ID & value. AlertHelper class can be used to + * retrieve the corresponding alert definition. + * + * @param alerts + * array of Alert class(contains alert def. ID & value) + * @param remoteVM + */ + public void processNotifications(StatAlert[] alerts, GemFireVM remoteVM); + + public void processSystemwideNotifications(); +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticAttributeInfo.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticAttributeInfo.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticAttributeInfo.java new file mode 100755 index 0000000..987dd25 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticAttributeInfo.java @@ -0,0 +1,78 @@ +/* + * 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.admin.api.Statistic; +import org.apache.geode.internal.Assert; + +import javax.management.Descriptor; +import javax.management.modelmbean.DescriptorSupport; +import javax.management.modelmbean.ModelMBeanAttributeInfo; + +/** + * Subclass of AttributeInfo with {@link Statistic} + * added for use as the {@link + * javax.management.modelmbean.ModelMBeanAttributeInfo} descriptor's + * targetObject value. + * + * @since GemFire 3.5 + * + */ +class StatisticAttributeInfo extends org.apache.commons.modeler.AttributeInfo { + private static final long serialVersionUID = 28022387514935560L; + + private Statistic stat; + + public StatisticAttributeInfo() { + super(); + } + + public Statistic getStat() { + return this.stat; + } + public void setStat(Statistic stat) { + //System.out.println(">> stat = " + stat); + Assert.assertTrue(stat != null, "Attempting to set stat to null"); + this.stat = stat; + } + + @Override + public ModelMBeanAttributeInfo createAttributeInfo() { + Descriptor desc = new DescriptorSupport( + new String[] { + "name=" + this.displayName, + "descriptorType=attribute", + "currencyTimeLimit=-1", // always stale + "displayName=" + this.displayName, + "getMethod=getValue" }); + + Assert.assertTrue(this.stat != null, "Stat target object is null!"); + desc.setField("targetObject", this.stat); + + ModelMBeanAttributeInfo info = new ModelMBeanAttributeInfo( + this.displayName, // name + this.type, // type + this.description, // description + this.readable, // isReadable + this.writeable, // isWritable + this.is, // isIs + desc); + + return info; + } +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticResourceJmxImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticResourceJmxImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticResourceJmxImpl.java new file mode 100755 index 0000000..ddd0cb7 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatisticResourceJmxImpl.java @@ -0,0 +1,360 @@ +/* + * 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.Notification; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; +import javax.naming.OperationNotSupportedException; + +import org.apache.commons.modeler.ManagedBean; +import org.apache.logging.log4j.Logger; + +import org.apache.geode.CancelException; +import org.apache.geode.SystemFailure; +import org.apache.geode.internal.admin.api.AdminException; +import org.apache.geode.internal.admin.api.OperationCancelledException; +import org.apache.geode.internal.admin.api.Statistic; +import org.apache.geode.internal.admin.StatResource; +import org.apache.geode.internal.admin.api.impl.StatisticResourceImpl; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.LogService; + +/** + * Provides MBean support for the monitoring of a statistic resource. + * + * @since GemFire 3.5 + * + */ +public class StatisticResourceJmxImpl +extends StatisticResourceImpl +implements javax.management.NotificationListener, ManagedResource { + + private static final Logger logger = LogService.getLogger(); + + /** + * Interval in seconds between refreshes. Values less than one results in no + * refreshing . + */ + private int refreshInterval = 0; + + /** The JMX object name of this managed resource */ + private ObjectName objectName; + + /** A flag to indicate if time is inited. MBeanUtil lookup is costly */ + private boolean timerInited = false; + + // ------------------------------------------------------------------------- + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Constructor for the StatisticResource object + * + * @param statResource the admin StatResource to manage/monitor + * @param member the SystemMember owning this resource + * @exception AdminException + * if unable to create this StatisticResource for administration + */ + public StatisticResourceJmxImpl(StatResource statResource, + SystemMemberJmx member) + throws AdminException { + super(statResource, member); + initializeMBean(); + } + + /** Create and register the MBean to manage this resource */ + private void initializeMBean() + throws AdminException { + this.mbeanName = new StringBuffer("GemFire.Statistic:") + .append("source=").append(MBeanUtil.makeCompliantMBeanNameProperty(this.member.getId())) + .append(",type=").append(MBeanUtil.makeCompliantMBeanNameProperty(getType())) + .append(",name=").append(MBeanUtil.makeCompliantMBeanNameProperty(getName())) + .append(",uid=").append(getUniqueId()).toString(); + + this.objectName = + MBeanUtil.createMBean(this, + addDynamicAttributes(MBeanUtil.lookupManagedBean(this))); + + // Refresh Interval + AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl)this.member.getDistributedSystem(); + if (sysJmx.getRefreshInterval()>0) + this.refreshInterval = sysJmx.getRefreshInterval(); + } + + // ------------------------------------------------------------------------- + // MBean attributes - accessors/mutators + // ------------------------------------------------------------------------- + + /** + * Gets the interval in seconds between statistics refreshes + * + * @return the current refresh interval in seconds + */ + public int getRefreshInterval() { + return this.refreshInterval; + } + + /** + * Sets interval in seconds between statistic refreshes; zero or less turns + * off auto refreshing. Manual refreshing has no effect on when the next + * scheduled refresh will occur. + * + * @param refreshInterval the new refresh interval in seconds + */ + private void _setRefreshInterval(int refreshInterval) { + boolean isRegistered = MBeanUtil.isRefreshNotificationRegistered(this, + RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS); + + if (isRegistered && (getRefreshInterval() == refreshInterval)) + return; + + try { + MBeanUtil.registerRefreshNotification( + this, // NotificationListener + getMBeanName(), // User Data as MBean Name + RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS, + refreshInterval); // int + + this.refreshInterval = refreshInterval; + timerInited = true; + } catch (RuntimeException e) { + logger.warn(e.getMessage(), e); // dead in water, print, and then ignore + this.refreshInterval = 0; // zero out to avoid more exceptions + } 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); // dead in water, print, and then ignore + this.refreshInterval = 0; // zero out to avoid more exceptions + } + } + + /** + * RefreshInterval is now set only through the AdminDistributedSystem property + * refreshInterval. Attempt to set refreshInterval on StatisticResourceJmx + * MBean would result in an OperationNotSupportedException + * Auto-refresh is enabled on demand when a call to getStatistics is made + * + * @param refreshInterval + * the new refresh interval in seconds + * @deprecated since 6.0 use DistributedSystemConfig.refreshInterval instead + */ + @Deprecated + public void setRefreshInterval(int refreshInterval) + throws OperationNotSupportedException { + throw new OperationNotSupportedException( + LocalizedStrings.MANAGED_RESOURCE_REFRESH_INTERVAL_CANT_BE_SET_DIRECTLY.toLocalizedString()); + } + + // ------------------------------------------------------------------------- + // JMX Notification listener + // ------------------------------------------------------------------------- + + /** + * Handles notification to refresh. Reacts by refreshing the values of this + * SystemMember's ConfigurationParamaters. Any other notification is ignored. + * Given notification is handled only if there is any JMX client connected to + * the system. + *

+ * TODO: investigate use of NotificationFilter instead of explicit check... + * + * @param notification + * the JMX notification being received + * @param hb + * handback object is unused + */ + public void handleNotification(Notification notification, Object hb) { + AdminDistributedSystemJmxImpl adminDSJmx = + (AdminDistributedSystemJmxImpl) this.member.getDistributedSystem(); + + String typeStatResourceStats = + RefreshNotificationType.STATISTIC_RESOURCE_STATISTICS.getType(); + + if (typeStatResourceStats.equals(notification.getType()) && + getMBeanName().equals(notification.getUserData()) && + !adminDSJmx.isRmiClientCountZero()) { + try { + refresh(); + + } catch (AdminException e) { + logger.warn(e.getMessage(), e); + } catch (OperationCancelledException e) { + // underlying resource is no longer reachable by remote admin + logger.warn(e.getMessage(), e); + _setRefreshInterval(0); + } catch (CancelException e) { + // shutting down - okay to ignore + } catch (java.lang.RuntimeException e) { + logger.debug(e.getMessage(), e); // dead in water, print, and then ignore + _setRefreshInterval(0); // zero out to avoid more exceptions + } 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(); + logger.error(e.getMessage(), e); // dead in water, print, and then ignore + this.refreshInterval = 0; // zero out to avoid more exceptions + } + } + } + + // ------------------------------------------------------------------------- + // Create MBean attributes for each Statistic + // ------------------------------------------------------------------------- + + /** + * Add MBean attribute definitions for each Statistic. + * + * @param managed the mbean definition to add attributes to + * @return a new instance of ManagedBean copied from managed but + * with the new attributes added + */ + ManagedBean addDynamicAttributes(ManagedBean managed) + throws AdminException { + if (managed == null) { + throw new IllegalArgumentException(LocalizedStrings.StatisticResourceJmxImpl_MANAGEDBEAN_IS_NULL.toLocalizedString()); + } + + refresh(); // to get the stats... + + // need to create a new instance of ManagedBean to clean the "slate"... + ManagedBean newManagedBean = new DynamicManagedBean(managed); + for (int i = 0; i < this.statistics.length; i++) { + StatisticAttributeInfo attrInfo = new StatisticAttributeInfo(); + + attrInfo.setName(this.statistics[i].getName()); + attrInfo.setDisplayName(this.statistics[i].getName()); + attrInfo.setDescription(this.statistics[i].getDescription()); + attrInfo.setType("java.lang.Number"); + + attrInfo.setIs(false); + attrInfo.setReadable(true); + attrInfo.setWriteable(false); + + attrInfo.setStat(this.statistics[i]); + + newManagedBean.addAttribute(attrInfo); + } + return newManagedBean; + } + + public Statistic[] getStatistics() { + if (!timerInited) { + // 1st call to getStatistics would trigger + // the auto-refresh if an interval is set + if (this.refreshInterval>0) { + this._setRefreshInterval(this.refreshInterval); + } + } + + if (this.statistics == null) { + try { + this.refresh(); + } + catch (AdminException e) { + this.statistics = new Statistic[0]; + } + } + + return this.statistics; + } + + // ------------------------------------------------------------------------- + // ManagedResource implementation + // ------------------------------------------------------------------------- + + /** The name of the MBean that will manage this resource */ + private String mbeanName; + + /** The ModelMBean that is configured to manage this resource */ + private ModelMBean modelMBean; + + public String getMBeanName() { + return this.mbeanName; + } + + public ModelMBean getModelMBean() { + return this.modelMBean; + } + public void setModelMBean(ModelMBean modelMBean) { + this.modelMBean = modelMBean; + } + + public ObjectName getObjectName() { + return this.objectName; + } + + public ManagedResourceType getManagedResourceType() { + return ManagedResourceType.STATISTIC_RESOURCE; + } + + public void cleanupResource() { + this.modelMBean = null; + this.member = null; + this.statistics = null; + this.statResource = null; + } + + /** + * Checks equality of the given object with this based on the + * type (Class) and the MBean Name returned by getMBeanName() + * methods. + * + * @param obj + * object to check equality with + * @return true if the given object is if the same type and its MBean Name is + * same as this object's MBean Name, false otherwise + */ + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof StatisticResourceJmxImpl) ) { + return false; + } + + StatisticResourceJmxImpl other = (StatisticResourceJmxImpl) obj; + + return this.getMBeanName().equals(other.getMBeanName()); + } + + /** + * Returns hash code for this object which is based on the MBean + * Name generated. + * + * @return hash code for this object + */ + @Override + public int hashCode() { + return this.getMBeanName().hashCode(); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberBridgeServerJmxImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberBridgeServerJmxImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberBridgeServerJmxImpl.java new file mode 100644 index 0000000..3e16605 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberBridgeServerJmxImpl.java @@ -0,0 +1,135 @@ +/* + * 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.admin.api.AdminException; +import org.apache.geode.internal.admin.api.SystemMemberBridgeServer; +import org.apache.geode.internal.admin.api.impl.SystemMemberBridgeServerImpl; +import org.apache.geode.internal.admin.api.impl.SystemMemberCacheImpl; +import org.apache.geode.internal.admin.AdminBridgeServer; +import org.apache.geode.internal.admin.GemFireVM; + +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; + +/** + * MBean representation of a {@link + * SystemMemberBridgeServer}. + * + * @since GemFire 4.0 + */ +public class SystemMemberBridgeServerJmxImpl + extends SystemMemberBridgeServerImpl implements ManagedResource { + + /** The object name of this managed resource */ + private ObjectName objectName; + + /** The name of the MBean that will manage this resource */ + private String mbeanName; + + /** The ModelMBean that is configured to manage this resource */ + private ModelMBean modelMBean; + + ////////////////////// Constructors ////////////////////// + + /** + * Creates a new SystemMemberBridgeServerJmxImpl that + * serves the contents of the given cache. + */ + SystemMemberBridgeServerJmxImpl(SystemMemberCacheImpl cache, + AdminBridgeServer bridgeInfo) + throws AdminException { + + super(cache, bridgeInfo); + initializeMBean(cache); + } + + ////////////////////// Instance Methods ////////////////////// + + /** + * Creates and registers the MBean to manage this resource + */ + private void initializeMBean(SystemMemberCacheImpl cache) + throws AdminException { + + GemFireVM vm = cache.getVM(); + this.mbeanName = new StringBuffer("GemFire.Cache:") + .append("name=") + .append(MBeanUtil.makeCompliantMBeanNameProperty(cache.getName())) + .append(",id=") + .append(this.getBridgeId()) + .append(",owner=") + .append(MBeanUtil.makeCompliantMBeanNameProperty(vm.getId().toString())) + .append(",type=CacheServer").toString(); + + this.objectName = MBeanUtil.createMBean(this); + } + + public String getMBeanName() { + return this.mbeanName; + } + + public ModelMBean getModelMBean() { + return this.modelMBean; + } + public void setModelMBean(ModelMBean modelMBean) { + this.modelMBean = modelMBean; + } + + public ObjectName getObjectName() { + return this.objectName; + } + + public ManagedResourceType getManagedResourceType() { + return ManagedResourceType.SYSTEM_MEMBER_CACHE_SERVER; + } + + public void cleanupResource() {} + + /** + * Checks equality of the given object with this based on the + * type (Class) and the MBean Name returned by getMBeanName() + * methods. + * + * @param obj + * object to check equality with + * @return true if the given object is if the same type and its MBean Name is + * same as this object's MBean Name, false otherwise + */ + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof SystemMemberBridgeServerJmxImpl) ) { + return false; + } + + SystemMemberBridgeServerJmxImpl other = + (SystemMemberBridgeServerJmxImpl) obj; + + return this.getMBeanName().equals(other.getMBeanName()); + } + + /** + * Returns hash code for this object which is based on the MBean + * Name generated. + * + * @return hash code for this object + */ + @Override + public int hashCode() { + return this.getMBeanName().hashCode(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberCacheJmxImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberCacheJmxImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberCacheJmxImpl.java new file mode 100644 index 0000000..8426ff1 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberCacheJmxImpl.java @@ -0,0 +1,474 @@ +/* + * 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.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; + +import org.apache.commons.modeler.ManagedBean; +import org.apache.logging.log4j.Level; + +import org.apache.geode.SystemFailure; +import org.apache.geode.internal.admin.api.AdminException; +import org.apache.geode.internal.admin.api.SystemMemberCache; +import org.apache.geode.internal.admin.api.SystemMemberCacheServer; +import org.apache.geode.internal.admin.api.SystemMemberRegion; +import org.apache.geode.internal.admin.api.impl.SystemMemberBridgeServerImpl; +import org.apache.geode.cache.Region; +import org.apache.geode.internal.admin.AdminBridgeServer; +import org.apache.geode.internal.admin.GemFireVM; +import org.apache.geode.internal.admin.api.impl.SystemMemberCacheImpl; +import org.apache.geode.internal.i18n.LocalizedStrings; + +/** + * MBean representation of {@link SystemMemberCache}. + * + * @since GemFire 3.5 + */ +public class SystemMemberCacheJmxImpl +extends SystemMemberCacheImpl +implements ManagedResource { + + /** The object name of this managed resource */ + private ObjectName objectName; + + /** collection to collect all the resources created for this member */ + private Map managedRegionResourcesMap = new HashMap(); + private Map managedCacheServerResourcesMap = new HashMap(); + + // ------------------------------------------------------------------------- + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Constructs an instance of SystemMemberCacheJmxImpl. + * + * @param vm + * The vm owning the cache this object will manage + */ + public SystemMemberCacheJmxImpl(GemFireVM vm) + throws AdminException { + super(vm); + initializeMBean(); + } + + /** Create and register the MBean to manage this resource */ + private void initializeMBean() + throws AdminException { + this.mbeanName = new StringBuffer("GemFire.Cache:") + .append("name=") + .append(MBeanUtil.makeCompliantMBeanNameProperty(getName())) + .append(",id=") + .append(getId()) + .append(",owner=") + .append(MBeanUtil.makeCompliantMBeanNameProperty(vm.getId().toString())) + .append(",type=Cache").toString(); + + this.objectName = + MBeanUtil.createMBean(this, + addDynamicAttributes(MBeanUtil.lookupManagedBean(this))); + } + + // ------------------------------------------------------------------------- + // Template methods overriden from superclass... + // ------------------------------------------------------------------------- + + /** + * Override createSystemMemberRegion by instantiating + * SystemMemberRegionJmxImpl. This instance is also added to the + * managedResources collection. + * + * @param r + * reference to Region instance for which this JMX resource is to be + * created + * @return SystemMemberRegionJmxImpl - JMX Implementation of + * SystemMemberRegion + * @throws AdminException + * if constructing SystemMemberRegionJmxImpl instance fails + */ + @Override + protected SystemMemberRegion createSystemMemberRegion(Region r) + throws AdminException { + SystemMemberRegionJmxImpl managedSystemMemberRegion = null; + boolean needsRefresh = false; + synchronized (this.managedRegionResourcesMap) { + /* + * Ensuring that a single instance of System Member Region is created + * per Region. + */ + SystemMemberRegionJmxImpl managedResource = managedRegionResourcesMap.get(r.getFullPath()); + if (managedResource != null) { + managedSystemMemberRegion = managedResource; + } else { + managedSystemMemberRegion = new SystemMemberRegionJmxImpl(this, r); + managedRegionResourcesMap.put(r.getFullPath(), managedSystemMemberRegion); + needsRefresh = true; + } + } + if (needsRefresh) { + managedSystemMemberRegion.refresh(); + } + return managedSystemMemberRegion; + } + + /** + * Creates a SystemMemberBridgeServerJmxImpl instance. This instance is also + * added to the managedResources collection. + * + * @param bridge + * reference to AdminBridgeServer for which this JMX resource is to + * be created + * @return SystemMemberBridgeServerJmxImpl - JMX Implementation of + * SystemMemberBridgeServerImpl + * @throws AdminException + * if constructing SystemMemberBridgeServerJmxImpl instance fails + */ + @Override + protected SystemMemberBridgeServerImpl + createSystemMemberBridgeServer(AdminBridgeServer bridge) + throws AdminException { + SystemMemberBridgeServerJmxImpl managedSystemMemberBridgeServer = null; + synchronized (this.managedCacheServerResourcesMap) { + /* + * Ensuring that a single instance of SystemMember BridgeServer is + * created per AdminBridgeServer. + */ + SystemMemberBridgeServerJmxImpl managedCacheServerResource = managedCacheServerResourcesMap.get(bridge.getId()); + if (managedCacheServerResource != null) { + managedSystemMemberBridgeServer = managedCacheServerResource; + } else { + managedSystemMemberBridgeServer = new SystemMemberBridgeServerJmxImpl(this, bridge); + managedCacheServerResourcesMap.put(bridge.getId(), managedSystemMemberBridgeServer); + } + } + return managedSystemMemberBridgeServer; + } + + // ------------------------------------------------------------------------- + // Create MBean attributes for each Statistic + // ------------------------------------------------------------------------- + + /** + * Add MBean attribute definitions for each Statistic. + * + * @param managed the mbean definition to add attributes to + * @return a new instance of ManagedBean copied from managed but + * with the new attributes added + */ + ManagedBean addDynamicAttributes(ManagedBean managed) + throws AdminException { + if (managed == null) { + throw new IllegalArgumentException(LocalizedStrings.SystemMemberCacheJmxImpl_MANAGEDBEAN_IS_NULL.toLocalizedString()); + } + + refresh(); // to get the stats... + + // need to create a new instance of ManagedBean to clean the "slate"... + ManagedBean newManagedBean = new DynamicManagedBean(managed); + for (int i = 0; i < this.statistics.length; i++) { + StatisticAttributeInfo attrInfo = new StatisticAttributeInfo(); + + attrInfo.setName(this.statistics[i].getName()); + attrInfo.setDisplayName(this.statistics[i].getName()); + attrInfo.setDescription(this.statistics[i].getDescription()); + attrInfo.setType("java.lang.Number"); + + attrInfo.setIs(false); + attrInfo.setReadable(true); + attrInfo.setWriteable(false); + + attrInfo.setStat(this.statistics[i]); + + newManagedBean.addAttribute(attrInfo); + } + + return newManagedBean; + } + + // ------------------------------------------------------------------------- + // MBean Operations + // ------------------------------------------------------------------------- + + /** + * Returns the ObjectName of the Region for the specified path. + * + * @throws AdminException + * If no region with path path exists + */ + public ObjectName manageRegion(String path) + throws AdminException, MalformedObjectNameException { + try { + SystemMemberRegionJmxImpl region = null; + + try { + region = (SystemMemberRegionJmxImpl) getRegion(path); + + } catch (AdminException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } + + if (region == null) { + throw new AdminException(LocalizedStrings.SystemMemberCacheJmxImpl_THIS_CACHE_DOES_NOT_CONTAIN_REGION_0.toLocalizedString(path)); + + } else { + return ObjectName.getInstance(region.getMBeanName()); + } + } catch (RuntimeException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } catch (VirtualMachineError err) { + SystemFailure.initiateFailure(err); + // If this ever returns, rethrow the error. We're poisoned + // now, so don't let this thread continue. + throw err; + } catch (Error e) { + // Whenever you catch Error or Throwable, you must also + // catch VirtualMachineError (see above). However, there is + // _still_ a possibility that you are dealing with a cascading + // error condition, so you also need to check to see if the JVM + // is still usable: + SystemFailure.checkFailure(); + MBeanUtil.logStackTrace(Level.ERROR, e); + throw e; + } + } + + /** + * Creates a new cache server MBean and returns its + * ObjectName. + * + * @since GemFire 5.7 + */ + public ObjectName manageCacheServer() + throws AdminException, MalformedObjectNameException { + + try { + SystemMemberBridgeServerJmxImpl bridge = + (SystemMemberBridgeServerJmxImpl) addCacheServer(); + return ObjectName.getInstance(bridge.getMBeanName()); + } catch (AdminException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } catch (RuntimeException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } catch (VirtualMachineError err) { + SystemFailure.initiateFailure(err); + // If this ever returns, rethrow the error. We're poisoned + // now, so don't let this thread continue. + throw err; + } catch (Error e) { + // Whenever you catch Error or Throwable, you must also + // catch VirtualMachineError (see above). However, there is + // _still_ a possibility that you are dealing with a cascading + // error condition, so you also need to check to see if the JVM + // is still usable: + SystemFailure.checkFailure(); + MBeanUtil.logStackTrace(Level.ERROR, e); + throw e; + } + } + + /** + * Returns the MBean ObjectNames for all cache servers + * that serve this cache to clients. + * + * @since GemFire 4.0 + */ + public ObjectName[] manageCacheServers() + throws AdminException, MalformedObjectNameException { + + try { + SystemMemberCacheServer[] bridges = getCacheServers(); + ObjectName[] names = new ObjectName[bridges.length]; + for (int i = 0; i < bridges.length; i++) { + SystemMemberBridgeServerJmxImpl bridge = + (SystemMemberBridgeServerJmxImpl) bridges[i]; + names[i] = ObjectName.getInstance(bridge.getMBeanName()); + } + + return names; + } catch (AdminException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } catch (RuntimeException e) { + MBeanUtil.logStackTrace(Level.WARN, e); + throw e; + } catch (VirtualMachineError err) { + SystemFailure.initiateFailure(err); + // If this ever returns, rethrow the error. We're poisoned + // now, so don't let this thread continue. + throw err; + } catch (Error e) { + // Whenever you catch Error or Throwable, you must also + // catch VirtualMachineError (see above). However, there is + // _still_ a possibility that you are dealing with a cascading + // error condition, so you also need to check to see if the JVM + // is still usable: + SystemFailure.checkFailure(); + MBeanUtil.logStackTrace(Level.ERROR, e); + throw e; + } + } + + /** + * Returns the MBean ObjectNames for all bridge servers + * that serve this cache. + * + * @since GemFire 4.0 + * @deprecated as of 5.7 + */ + @Deprecated + public ObjectName[] manageBridgeServers() + throws AdminException, MalformedObjectNameException { + return manageCacheServers(); + } + + // ------------------------------------------------------------------------- + // ManagedResource implementation + // ------------------------------------------------------------------------- + + /** The name of the MBean that will manage this resource */ + private String mbeanName; + + /** The ModelMBean that is configured to manage this resource */ + private ModelMBean modelMBean; + + public String getMBeanName() { + return this.mbeanName; + } + + public ModelMBean getModelMBean() { + return this.modelMBean; + } + public void setModelMBean(ModelMBean modelMBean) { + this.modelMBean = modelMBean; + } + + public ObjectName getObjectName() { + return this.objectName; + } + + public ManagedResourceType getManagedResourceType() { + return ManagedResourceType.SYSTEM_MEMBER_CACHE; + } + + + /** + * Un-registers all the statistics & cache managed resource created for this + * member. After un-registering the resource MBean instances, clears + * this.memberResources collection. + * + * Creates ConfigurationParameterJmxImpl, StatisticResourceJmxImpl and + * SystemMemberCacheJmxImpl. But cleans up only StatisticResourceJmxImpl and + * SystemMemberCacheJmxImpl which are of type ManagedResource. + */ + public void cleanupResource() { + synchronized (this.managedRegionResourcesMap) { + Collection values = managedRegionResourcesMap.values(); + + for (SystemMemberRegionJmxImpl systemMemberRegionJmxImpl : values) { + MBeanUtil.unregisterMBean(systemMemberRegionJmxImpl); + } + + this.managedRegionResourcesMap.clear(); + } + + synchronized (this.managedCacheServerResourcesMap) { + Collection values = managedCacheServerResourcesMap.values(); + + for (SystemMemberBridgeServerJmxImpl SystemMemberBridgeServerJmxImpl : values) { + MBeanUtil.unregisterMBean(SystemMemberBridgeServerJmxImpl); + } + + this.managedCacheServerResourcesMap.clear(); + } + } + + /** + * Cleans up managed resources created for the region that was (created and) + * destroyed in a cache represented by this Managed Resource. + * + * @param regionPath + * path of the region that got destroyed + * @return a managed resource related to this region path + */ + public ManagedResource cleanupRegionResources(String regionPath) { + ManagedResource cleaned = null; + + synchronized (this.managedRegionResourcesMap) { + Set> entries = managedRegionResourcesMap.entrySet(); + for (Iterator> it = entries.iterator(); it.hasNext();) { + Entry entry = it.next(); + SystemMemberRegionJmxImpl managedResource = entry.getValue(); + ObjectName objName = managedResource.getObjectName(); + + String pathProp = objName.getKeyProperty("path"); + if (pathProp != null && pathProp.equals(regionPath)) { + cleaned = managedResource; + it.remove(); + + break; + } + } + } + + return cleaned; + } + + /** + * Checks equality of the given object with this based on the + * type (Class) and the MBean Name returned by getMBeanName() + * methods. + * + * @param obj + * object to check equality with + * @return true if the given object is if the same type and its MBean Name is + * same as this object's MBean Name, false otherwise + */ + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof SystemMemberCacheJmxImpl) ) { + return false; + } + + SystemMemberCacheJmxImpl other = (SystemMemberCacheJmxImpl) obj; + + return this.getMBeanName().equals(other.getMBeanName()); + } + + /** + * Returns hash code for this object which is based on the MBean + * Name generated. + * + * @return hash code for this object + */ + @Override + public int hashCode() { + return this.getMBeanName().hashCode(); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c0221bed/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberJmx.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberJmx.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberJmx.java new file mode 100644 index 0000000..afd6c7d --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/SystemMemberJmx.java @@ -0,0 +1,501 @@ +/* + * 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.SystemFailure; +import org.apache.geode.cache.Operation; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.internal.admin.ClientMembershipMessage; +import org.apache.geode.internal.admin.api.AdminException; +import org.apache.geode.internal.admin.api.ConfigurationParameter; +import org.apache.geode.internal.admin.api.OperationCancelledException; +import org.apache.geode.internal.admin.api.StatisticResource; +import org.apache.geode.internal.admin.api.SystemMember; +import org.apache.geode.internal.admin.api.SystemMemberCache; +import org.apache.geode.internal.admin.api.SystemMemberCacheEvent; +import org.apache.geode.internal.admin.api.SystemMemberRegionEvent; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.log4j.LocalizedMessage; +import org.apache.commons.modeler.ManagedBean; +import org.apache.logging.log4j.Logger; + +import javax.management.*; +import javax.naming.OperationNotSupportedException; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Defines methods that all SystemMember MBeans should + * implement. + * + * @since GemFire 4.0 + */ +public interface SystemMemberJmx + extends SystemMember, NotificationListener { + /** + * Notification type for indicating a cache got created on a member of this + * distributed system. + */ + public static final String NOTIF_CACHE_CREATED = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.created"; + /** + * Notification type for indicating a cache is closed on a member of this + * distributed system. + */ + public static final String NOTIF_CACHE_CLOSED = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.closed"; + /** + * Notification type for indicating a region is created in a cache on a member + * of this distributed system. + */ + public static final String NOTIF_REGION_CREATED = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.region.created"; + /** + * Notification type for indicating a region was removed from a cache on a + * member of this distributed system. + */ + public static final String NOTIF_REGION_LOST = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.region.lost"; + + /** Notification type for indicating client joined */ + public static final String NOTIF_CLIENT_JOINED = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.joined"; + + /** Notification type for indicating client left */ + public static final String NOTIF_CLIENT_LEFT = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.left"; + + /** Notification type for indicating client crashed */ + public static final String NOTIF_CLIENT_CRASHED = + DistributionConfig.GEMFIRE_PREFIX + "distributedsystem.cache.client.crashed"; + + /** + * Gets the interval in seconds between config refreshes + * + * @return the current refresh interval in seconds + */ + public int getRefreshInterval(); + + /** + * RefreshInterval is now set only through the AdminDistributedSystem property + * refreshInterval. Attempt to set refreshInterval on SystemMemberJmx MBean + * would result in an OperationNotSupportedException Auto-refresh is enabled + * on demand when a call to refreshConfig is made + * + * @param refreshInterval + * the new refresh interval in seconds + * @deprecated since 6.0 use DistributedSystemConfig.refreshInterval instead + */ + @Deprecated + public void setRefreshInterval(int refreshInterval) throws OperationNotSupportedException; + + /** + * Sets the refresh interval field. + * Sets interval in seconds between config refreshes; zero or less turns + * off auto refreshing. Manual refreshing has no effect on when the next + * scheduled refresh will occur. + */ + public void _setRefreshInterval(int refreshInterval); + + /** + * Gets this member's cache. + * + * @return ObjectName for this member's cache + * + * @throws AdminException + * If this system member does not host a cache + */ + public ObjectName manageCache() + throws AdminException, MalformedObjectNameException; + + /** + * Gets all active StatisticResources for this manager. + * + * @return array of ObjectName instances + */ + public ObjectName[] manageStats() + throws AdminException, MalformedObjectNameException; + + /** + * Gets the active StatisticResources for this manager, based on the + * typeName as the key + * + * @return ObjectName of StatisticResourceJMX instance + */ + public ObjectName[] manageStat(String statisticsTypeName) + throws AdminException, MalformedObjectNameException; + + /** + * Handles notification to refresh. Reacts by refreshing the values of this + * GemFireManager's ConfigurationParamaters. Any other notification is + * ignored. + * + * @param notification the JMX notification being received + * @param hb handback object is unused + */ + public void handleNotification(Notification notification, Object hb); + + /** + * Add MBean attribute definitions for each ConfigurationParameter. + * + * @param managed the mbean definition to add attributes to + * @return a new instance of ManagedBean copied from managed but + * with the new attributes added + */ + public ManagedBean addDynamicAttributes(ManagedBean managed) + throws AdminException; + + + /** + * Implementation should handle creation of cache by extracting the details + * from the given event object. + * + * @param event + * event object corresponding to the creation of the cache + */ + public void handleCacheCreate(SystemMemberCacheEvent event); + + /** + * Implementation should handle closure of cache by extracting the details + * from the given event object. + * + * @param event + * event object corresponding to the closure of the cache + */ + public void handleCacheClose(SystemMemberCacheEvent event); + + /** + * Implementation should handle creation of region by extracting the details + * from the given event object. + * + * @param event + * event object corresponding to the creation of a region + */ + public void handleRegionCreate(SystemMemberRegionEvent event); + + /** + * Implementation should handle loss of region by extracting the details + * from the given event object. + * + * @param event + * event object corresponding to the loss of a region + */ + public void handleRegionLoss(SystemMemberRegionEvent event); + + /** + * Implementation should handle client membership changes. + * + * @param clientId + * id of the client for whom membership change happened + * @param eventType + * membership change type; one of + * {@link ClientMembershipMessage#JOINED}, + * {@link ClientMembershipMessage#LEFT}, + * {@link ClientMembershipMessage#CRASHED} + */ + public void handleClientMembership(String clientId, int eventType); + + ////////////////////// Inner Classess ////////////////////// + + /** + * A helper class that provides implementation of the + * SystemMemberJmx interface as static methods. + */ + public static class Helper { + private static final Logger logger = LogService.getLogger(); + + private static AtomicInteger notificationSequenceNumber = new AtomicInteger(); + + public static int setAndReturnRefreshInterval(SystemMemberJmx member, + int refreshInterval) { + int ret = refreshInterval; + + try { + MBeanUtil.registerRefreshNotification( + member, // NotificationListener + ((ManagedResource)member).getMBeanName(), // User Data + RefreshNotificationType.SYSTEM_MEMBER_CONFIG, + refreshInterval); // int + + } catch (RuntimeException e) { + logger.warn(e.getMessage(), e); // dead in water, print, and then ignore + ret = 0; // zero out to avoid more exceptions + + } 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); // dead in water, print, and then ignore + ret = 0; // zero out to avoid more exceptions + } + + return ret; + } + + public static ObjectName manageCache(SystemMemberJmx member) + throws AdminException, MalformedObjectNameException { + boolean IthrewIt = false; + try { + SystemMemberCache cache = member.getCache(); + if (cache == null) { + IthrewIt = true; + throw new AdminException(LocalizedStrings.SystemMemberJmx_THIS_SYSTEM_MEMBER_DOES_NOT_HAVE_A_CACHE.toLocalizedString()); + } +// Assert.assertTrue(cache != null); (cannot be null) + SystemMemberCacheJmxImpl cacheJmx = (SystemMemberCacheJmxImpl) cache; + return ObjectName.getInstance(cacheJmx.getMBeanName()); + } catch (AdminException e) { + if (!IthrewIt) { + logger.warn(e.getMessage(), 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; + } + } + + public static ObjectName[] manageStats(SystemMemberJmx member) + throws AdminException, MalformedObjectNameException { + try { + StatisticResource[] stats = member.getStats(); + ObjectName[] onames = new ObjectName[stats.length]; + for (int i = 0; i < stats.length; i++) { + StatisticResourceJmxImpl stat = + (StatisticResourceJmxImpl) stats[i]; + onames[i] = ObjectName.getInstance(stat.getMBeanName()); + } + return onames; + } catch (AdminException e) { + logger.warn(e.getMessage(), 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; + } + } + + public static ObjectName[] manageStat(SystemMemberJmx member, String statisticsTypeName) + throws AdminException, MalformedObjectNameException { + try { + StatisticResource[] stats = member.getStat(statisticsTypeName); + if (stats==null) + return null; + else { + ObjectName[] statNames = new ObjectName[stats.length]; + for (int i=0; i + * TODO: refactor to implement SystemMember and delegate to SystemMemberImpl. + * Wrap all delegate calls w/ e.printStackTrace() since the HttpAdaptor devours + * them + * + * @since GemFire 3.5 + * + */ +public class SystemMemberJmxImpl +extends SystemMemberImpl +implements SystemMemberJmx, javax.management.NotificationListener, ManagedResource { + + private static final Logger logger = LogService.getLogger(); + + /** + * Interval in seconds between refreshes. Value less than one results in no + * refreshing + */ + private int refreshInterval = 0; + + /** The JMX object name of this managed resource */ + private ObjectName objectName; + + /** Reference to the cache MBean representing a Cache in the Cache VM Member */ + private SystemMemberCacheJmxImpl managedSystemMemberCache; + + /** collection to collect all the resources created for this member */ + private Map managedStatisticsResourcesMap = new HashMap(); + + + // ------------------------------------------------------------------------- + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Constructs an instance of SystemMemberJmxImpl. + * + * @param system the distributed system this SystemMember is a member of + * @param application the internal admin application to delegate actual work + */ + public SystemMemberJmxImpl(AdminDistributedSystemJmxImpl system, + ApplicationVM application) + throws AdminException { + super(system, application); + initializeMBean(); + } + + /** + * Constructs the instance of SystemMember using the corresponding + * InternalDistributedMember instance of a DS member for the given + * AdminDistributedSystem. + * + * @param system + * Current AdminDistributedSystem instance + * @param member + * InternalDistributedMember instance for which a SystemMember + * instance is to be constructed. + * @throws AdminException + * if construction of SystemMember fails + * + * @since GemFire 6.5 + */ + protected SystemMemberJmxImpl(AdminDistributedSystemJmxImpl system, + InternalDistributedMember member) throws AdminException { + super(system, member); + initializeMBean(); + } + + /** Create and register the MBean to manage this resource */ + private void initializeMBean() + throws AdminException { + //initialize Managed Resources for stats & cache first. +// initializeManagedResources(); + + this.mbeanName = new StringBuffer("GemFire.Member:id=") + .append(MBeanUtil.makeCompliantMBeanNameProperty(getId())) + .append(",type=").append(MBeanUtil.makeCompliantMBeanNameProperty(getType().getName())).toString(); + + this.objectName = + MBeanUtil.createMBean(this, + addDynamicAttributes(MBeanUtil.lookupManagedBean(this))); + + // Refresh Interval + AdminDistributedSystemJmxImpl sysJmx = (AdminDistributedSystemJmxImpl)system; + if (sysJmx.getRefreshInterval() > 0) + this.refreshInterval = sysJmx.getRefreshInterval(); + } + + // ------------------------------------------------------------------------- + // MBean attributes - accessors/mutators + // ------------------------------------------------------------------------- + + /** + * Gets the interval in seconds between config refreshes + * + * @return the current refresh interval in seconds + */ + public int getRefreshInterval() { + return this.refreshInterval; + } + + /** + * RefreshInterval is now set only through the AdminDistributedSystem property + * refreshInterval. Attempt to set refreshInterval on SystemMemberJmx MBean + * would result in an OperationNotSupportedException Auto-refresh is enabled + * on demand when a call to refreshConfig is made + * + * @param refreshInterval + * the new refresh interval in seconds + * @deprecated since 6.0 use DistributedSystemConfig.refreshInterval instead + */ + @Deprecated + public void setRefreshInterval(int refreshInterval) + throws OperationNotSupportedException { + throw new OperationNotSupportedException( + LocalizedStrings.MANAGED_RESOURCE_REFRESH_INTERVAL_CANT_BE_SET_DIRECTLY.toLocalizedString()); + } + + /** + * Sets interval in seconds between member config refreshes; zero or less + * turns off auto refreshing. Manual refreshing has no effect on when the next + * scheduled refresh will occur. + * + * @param refreshInterval + * the new refresh interval in seconds + */ + public void _setRefreshInterval(int refreshInterval) { + boolean isRegistered = MBeanUtil.isRefreshNotificationRegistered(this, + RefreshNotificationType.SYSTEM_MEMBER_CONFIG); + + if (isRegistered && (getRefreshInterval() == refreshInterval)) + return; + + this.refreshInterval = Helper.setAndReturnRefreshInterval(this, + refreshInterval); + } + + // ------------------------------------------------------------------------- + // MBean Operations + // ------------------------------------------------------------------------- + + public void refreshConfig() throws AdminException { + // 1st call to refreshConfig would trigger + // the auto-refresh if an interval is set + if (this.refreshInterval > 0) { + this._setRefreshInterval(this.refreshInterval); + } + + super.refreshConfig(); + } + + /** + * Initializes Cache & Statistics managed resources. + * + * @throws AdminException + * if initialization of managed resources fails + */ +// private void initializeManagedResources() throws AdminException { +// try { +// manageCache(); +// } catch (MalformedObjectNameException e) { +// throw new AdminException(LocalizedStrings.SystemMemberJmxImpl_EXCEPTION_OCCURRED_WHILE_INITIALIZING_0_MBEANS_FOR_1.toLocalizedString( +// new Object[] {"Cache", getId()}), +// e); +// } catch (AdminException ae) { +// if (LocalizedStrings.SystemMemberJmx_THIS_SYSTEM_MEMBER_DOES_NOT_HAVE_A_CACHE.toLocalizedString().equals(ae.getMessage())) { +// //ignore this exception for a cache-less peer +// } else { +// throw ae; +// } +// } +// try { +// manageStats(); +// } catch (MalformedObjectNameException e) { +// throw new AdminException(LocalizedStrings.SystemMemberJmxImpl_EXCEPTION_OCCURRED_WHILE_INITIALIZING_0_MBEANS_FOR_1.toLocalizedString( +// new Object[] {"Statistics", getId()}), +// e); +// } +// } + + /** + * Gets this member's cache. + * + * @return ObjectName for this member's cache + * + * @throws AdminException + * If this system member does not host a cache + */ + public ObjectName manageCache() + throws AdminException, MalformedObjectNameException { + + return Helper.manageCache(this); + } + + /** + * Gets all active StatisticResources for this manager. + * + * @return array of ObjectName instances + */ + public ObjectName[] manageStats() + throws AdminException, MalformedObjectNameException { + + return Helper.manageStats(this); + } + + /** + * Gets the active StatisticResources for this manager, based on the + * typeName as the key + * + * @return ObjectName of StatisticResourceJMX instance + */ + public ObjectName[] manageStat(String statisticsTypeName) + throws AdminException, MalformedObjectNameException { + + return Helper.manageStat(this, statisticsTypeName); + } + + // ------------------------------------------------------------------------- + // JMX Notification listener + // ------------------------------------------------------------------------- + + /** + * Handles notification to refresh. Reacts by refreshing the values of this + * SystemMember's ConfigurationParamaters. Any other notification is ignored. + * Given notification is handled only if there is any JMX client connected to + * the system. + * + * @param notification + * the JMX notification being received + * @param hb + * handback object is unused + */ + public void handleNotification(Notification notification, Object hb) { + AdminDistributedSystemJmxImpl systemJmx = + (AdminDistributedSystemJmxImpl) this.system; + + if (!systemJmx.isRmiClientCountZero()) { + Helper.handleNotification(this, notification, hb); + } + } + + // ------------------------------------------------------------------------- + // Template methods overriden from superclass... + // ------------------------------------------------------------------------- + + /** + * Template method for creating instance of ConfigurationParameter. + * Overridden to return ConfigurationParameterJmxImpl. + */ + @Override + protected ConfigurationParameter createConfigurationParameter(String name, + String description, + Object value, + Class type, + boolean userModifiable) { + return new ConfigurationParameterJmxImpl( + name, description, value, type, userModifiable); + } + + /** + * Override createStatisticResource by instantiating StatisticResourceJmxImpl + * if it was not created earlier otherwise returns the same instance. + * + * @param stat + * StatResource reference for which this JMX resource is to be created + * @return StatisticResourceJmxImpl - JMX Implementation of StatisticResource + * @throws AdminException + * if constructing StatisticResourceJmxImpl instance fails + */ + @Override + protected StatisticResource createStatisticResource(StatResource stat) + throws AdminException { + StatisticResourceJmxImpl managedStatisticResource = null; + + synchronized (this.managedStatisticsResourcesMap) { + /* + * Ensuring that a single instance of Statistic Resource is created per + * StatResource. + */ + StatisticResourceJmxImpl statisticResourceJmxImpl = managedStatisticsResourcesMap.get(stat); + if (statisticResourceJmxImpl != null) { + managedStatisticResource = statisticResourceJmxImpl; + } else { + managedStatisticResource = new StatisticResourceJmxImpl(stat, this); + managedStatisticResource.getStatistics();//inits timer + managedStatisticsResourcesMap.put(stat, managedStatisticResource); + } + } + return managedStatisticResource; + } + + /** + * Override createSystemMemberCache by instantiating SystemMemberCacheJmxImpl + * if it was not created earlier. + * + * @param vm + * GemFireVM reference for which this JMX resource is to be created + * @return SystemMemberCacheJmxImpl - JMX Implementation of SystemMemberCache + * @throws AdminException + * if constructing SystemMemberCacheJmxImpl instance fails + */ + @Override + protected SystemMemberCache createSystemMemberCache(GemFireVM vm) + throws AdminException { + if (managedSystemMemberCache == null) { + managedSystemMemberCache = new SystemMemberCacheJmxImpl(vm); + } + return managedSystemMemberCache; + } + + // ------------------------------------------------------------------------- + // Create MBean attributes for each ConfigurationParameter + // ------------------------------------------------------------------------- + + /** + * Add MBean attribute definitions for each ConfigurationParameter. + * + * @param managed the mbean definition to add attributes to + * @return a new instance of ManagedBean copied from managed but + * with the new attributes added + */ + public ManagedBean addDynamicAttributes(ManagedBean managed) + throws AdminException { + + return Helper.addDynamicAttributes(this, managed); + } + + // ------------------------------------------------------------------------- + // ManagedResource implementation + // ------------------------------------------------------------------------- + + /** The name of the MBean that will manage this resource */ + private String mbeanName; + + /** The ModelMBean that is configured to manage this resource */ + private ModelMBean modelMBean; + + public String getMBeanName() { + return this.mbeanName; + } + + public ModelMBean getModelMBean() { + return this.modelMBean; + } + public void setModelMBean(ModelMBean modelMBean) { + this.modelMBean = modelMBean; + } + + public ObjectName getObjectName() { + return this.objectName; + } + + public ManagedResourceType getManagedResourceType() { + return ManagedResourceType.SYSTEM_MEMBER; + } + + /** + * Un-registers all the statistics & cache managed resource created for this + * member. After un-registering the resource MBean instances, clears + * managedStatisticsResourcesMap collection. + */ + public void cleanupResource() { + synchronized (this.managedStatisticsResourcesMap) { + ConfigurationParameter[] names = getConfiguration(); + if (names != null) { + for (int i = 0; i < names.length; i++) { + ConfigurationParameter parm = names[i]; + ((ConfigurationParameterImpl) parm).removeConfigurationParameterListener(this); + } + } + this.parms.clear(); + + Collection statisticResources = managedStatisticsResourcesMap.values(); + + for (StatisticResourceJmxImpl statisticResource : statisticResources) { + MBeanUtil.unregisterMBean(statisticResource); + } + + this.managedStatisticsResourcesMap.clear(); + } + MBeanUtil.unregisterMBean(managedSystemMemberCache); + } + + + /** + * Cleans up Managed Resources created for the client that was connected to + * the server represented by this class. + * + * @param clientId + * id of the client to be removed + * @return List of ManagedResources associated with the client of given client + * id + */ + /* + * This clean up is for the clients. The clients are started with a loner DM. + * Hence the clientId is not supposed to contain '/' as per + * InternalDistributedMember.toString(). + */ + public List cleanupBridgeClientResources(String clientId) { + List returnedResources = new ArrayList(); + + String compatibleId = "id_"+MBeanUtil.makeCompliantMBeanNameProperty(clientId); + synchronized (this.managedStatisticsResourcesMap) { + Set> entrySet = this.managedStatisticsResourcesMap.entrySet(); + + for (Iterator> it = entrySet.iterator(); it.hasNext();) { + Entry entry = it.next(); + StatisticResourceJmxImpl resource = entry.getValue(); + if (resource.getMBeanName().contains(compatibleId)) { + it.remove(); //remove matching entry + returnedResources.add(resource); + } + } + } + return returnedResources; + } + + /** + * Implementation handles client membership changes. + * + * @param clientId + * id of the client for whom membership change happened + * @param eventType + * membership change type; one of + * {@link ClientMembershipMessage#JOINED}, + * {@link ClientMembershipMessage#LEFT}, + * {@link ClientMembershipMessage#CRASHED} + */ + public void handleClientMembership(String clientId, int eventType) { + String notifType = null; + List cleanedUp = null; + + if (eventType == ClientMembershipMessage.LEFT) { + notifType = NOTIF_CLIENT_LEFT; + cleanedUp = cleanupBridgeClientResources(clientId); + } else if (eventType == ClientMembershipMessage.CRASHED) { + notifType = NOTIF_CLIENT_CRASHED; + cleanedUp = cleanupBridgeClientResources(clientId); + } else if (eventType == ClientMembershipMessage.JOINED) { + notifType = NOTIF_CLIENT_JOINED; + } + + if (cleanedUp != null) { + for (ManagedResource resource : cleanedUp) { + MBeanUtil.unregisterMBean(resource); + } + } + + Helper.sendNotification(this, + new Notification(notifType, this.modelMBean, + Helper.getNextNotificationSequenceNumber(), + clientId)); + } + + /** + * Implementation handles creation of cache by extracting the details from the + * given event object and sending the + * {@link SystemMemberJmx#NOTIF_CACHE_CREATED} notification to the connected + * JMX Clients. + * + * @param event + * event object corresponding to the creation of the cache + */ + public void handleCacheCreate(SystemMemberCacheEvent event) { + Helper.sendNotification(this, + new Notification(NOTIF_CACHE_CREATED, this.modelMBean, + Helper.getNextNotificationSequenceNumber(), + Helper.getCacheEventDetails(event))); + } + + /** + * Implementation handles closure of cache by extracting the details from the + * given event object and sending the + * {@link SystemMemberJmx#NOTIF_CACHE_CLOSED} notification to the connected + * JMX Clients. + * + * @param event + * event object corresponding to the closure of the cache + */ + public void handleCacheClose(SystemMemberCacheEvent event) { + Helper.sendNotification(this, + new Notification(NOTIF_CACHE_CLOSED, this.modelMBean, + Helper.getNextNotificationSequenceNumber(), + Helper.getCacheEventDetails(event))); + } + + /** + * Implementation handles creation of region by extracting the details from + * the given event object and sending the + * {@link SystemMemberJmx#NOTIF_REGION_CREATED} notification to the connected + * JMX Clients. Region Path is set as User Data in Notification. + * + * @param event + * event object corresponding to the creation of a region + */ + public void handleRegionCreate(SystemMemberRegionEvent event) { + Notification notification = new Notification(NOTIF_REGION_CREATED, this.modelMBean, + Helper.getNextNotificationSequenceNumber(), + Helper.getRegionEventDetails(event)); + + notification.setUserData(event.getRegionPath()); + + Helper.sendNotification(this, notification); + } + + /** + * Implementation should handle loss of region by extracting the details from + * the given event object and sending the + * {@link SystemMemberJmx#NOTIF_REGION_LOST} notification to the connected + * JMX Clients. Region Path is set as User Data in Notification. Additionally, + * it also clears the ManagedResources created for the region that is lost. + * + * @param event + * event object corresponding to the loss of a region + */ + public void handleRegionLoss(SystemMemberRegionEvent event) { + SystemMemberCacheJmxImpl cacheResource = this.managedSystemMemberCache; + + if (cacheResource != null) { + ManagedResource cleanedUp = + cacheResource.cleanupRegionResources(event.getRegionPath()); + + if (cleanedUp != null) { + MBeanUtil.unregisterMBean(cleanedUp); + } + } + + Notification notification = new Notification(NOTIF_REGION_LOST, this.modelMBean, + Helper.getNextNotificationSequenceNumber(), + Helper.getRegionEventDetails(event)); + + notification.setUserData(event.getRegionPath()); + + Helper.sendNotification(this, notification); + } +} +