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/18 18:57:37 UTC

[07/42] incubator-geode git commit: Move Admin API to internal

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/MemberInfoWithStatsMBean.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MemberInfoWithStatsMBean.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MemberInfoWithStatsMBean.java
new file mode 100644
index 0000000..3066148
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/MemberInfoWithStatsMBean.java
@@ -0,0 +1,1360 @@
+/*
+ * 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 static org.apache.geode.distributed.ConfigurationProperties.*;
+
+import org.apache.geode.internal.admin.api.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.CacheVm;
+import org.apache.geode.internal.admin.api.ConfigurationParameter;
+import org.apache.geode.internal.admin.api.GemFireMemberStatus;
+import org.apache.geode.internal.admin.api.RegionSubRegionSnapshot;
+import org.apache.geode.internal.admin.api.StatisticResource;
+import org.apache.geode.internal.admin.api.SystemMember;
+import org.apache.geode.internal.admin.api.SystemMemberCacheServer;
+import org.apache.geode.internal.admin.api.jmx.Agent;
+import org.apache.geode.cache.InterestPolicy;
+import org.apache.geode.cache.SubscriptionAttributes;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.admin.remote.ClientHealthStats;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+import mx4j.AbstractDynamicMBean;
+import org.apache.logging.log4j.Logger;
+
+import javax.management.*;
+import java.net.InetAddress;
+import java.text.MessageFormat;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This class uses the JMX Attributes/Operations that use (return/throw) 
+ * GemFire types. This is the single MBean accessible with ObjectName string
+ * {@link MemberInfoWithStatsMBean#MBEAN_NAME}}. This MBean can be used to 
+ * retrieve the all member details as plain java types.
+ * 
+ * This MBean also acts as a Notification Hub for all the Notifications that are 
+ * defined for Admin Distributed System. 
+ * 
+ * 
+ * @since GemFire 6.5
+ */
+public class MemberInfoWithStatsMBean extends AbstractDynamicMBean 
+                                 implements NotificationEmitter {
+  private static final Logger logger = LogService.getLogger();
+  
+  /* constants defining max no of attributes/operations/notifications */
+  private static final int MAX_ATTRIBUTES_COUNT    = 3;
+  private static final int MAX_OPERATIONS_COUNT    = 3;
+  private static final int MAX_NOTIFICATIONS_COUNT = 9;
+  
+  private static final String NOT_AVAILABLE_STR = "N/A";
+  private static final String NOT_AVAILABLE = null;
+  private static final Number NOT_AVAILABLE_NUMBER = null;
+
+  /* String constant used for a region that is used on admin side just as a root 
+   * for rootRegions defined on the member */
+  private static final String PLACE_HOLDER_ROOT_REGION = "/Root/";
+
+  /* String that are used to form QueryExp/ObjectName for querying MBeanServer */
+  private static final String REGION_QUERY_EXPRESSION = "*GemFire.Cache*:*,owner={0},type=Region";  
+  private static final String STATS_QUERY_EXPRESSION  = "*GemFire.Statistic*:*,source={0},name={1}";
+  
+  /** mbean name string for this MBean */
+  /*default*/static final String  MBEAN_NAME = "GemFire:type=MemberInfoWithStatsMBean";
+
+  /** ObjectName handle for this MBean */
+  private ObjectName objectName;
+  
+  /** version of the GemFire Enterprise system that is running */
+  private String                        version;
+  private int                           refreshInterval;
+  private String                        id;
+  
+  private Agent agent;
+  private AdminDistributedSystemJmxImpl adminDSJmx;
+  
+  private NotificationForwarder         forwarder;
+  private boolean                       isInitialized;//needs synchronization?
+
+  /**
+   * Default Constructor
+   * 
+   * @param agent Admin Agent instance
+   * @throws OperationsException if ObjectName can't be formed for this MBean
+   * @throws MBeanRegistrationException 
+   * @throws AdminException
+   */
+  MemberInfoWithStatsMBean(Agent agent) throws OperationsException, MBeanRegistrationException, AdminException {
+    this.agent           = agent;
+    this.objectName      = ObjectName.getInstance(MBEAN_NAME);
+    this.version         = GemFireVersion.getGemFireVersion();
+    this.refreshInterval = -1;
+    this.id              = NOT_AVAILABLE_STR;
+    this.forwarder       = new NotificationForwarder(agent.getMBeanServer());
+  }
+
+  /**
+   * Returns attributes defined for this MBean as an array of 
+   * MBeanAttributeInfo objects.
+   * 
+   * @return attributes defined as an array of MBeanAttributeInfo objects.
+   */
+  @Override
+  protected MBeanAttributeInfo[] createMBeanAttributeInfo() {
+    MBeanAttributeInfo[] attributesInfo = new MBeanAttributeInfo[MAX_ATTRIBUTES_COUNT];
+    
+    /* First letter in attribute name has to be 'V' so that getVersion is 
+     * called. With 'v' it looks for getversion, same for others */
+    attributesInfo[0] = new MBeanAttributeInfo("Version", 
+                                               String.class.getName(), 
+                                               "GemFire Enterprise Version", 
+                                               true,  /*readable*/ 
+                                               false, /*writable*/ 
+                                               false);/*has getter with name like 'is****'*/
+    
+    attributesInfo[1] = new MBeanAttributeInfo("RefreshInterval", 
+                                               String.class.getName(), 
+                                               "The interval (in seconds) between auto-polling for updating member & statistics resources. If this is '-1', it means the this MBean has not yet been initialized. First call to getMembers operation will initialize this MBean.", 
+                                               true,  /*readable*/ 
+                                               false, /*writable*/ 
+                                               false);/*has getter with name like 'is****'*/
+    
+    attributesInfo[2] = new MBeanAttributeInfo("Id", 
+                                               String.class.getName(), 
+                                               "Identifier of the GemFire Enterprise. If this is 'N/A', it means the this MBean has not yet been initialized. First call to getMembers operation will initialize this MBean.", 
+                                               true,  /*readable*/ 
+                                               false, /*writable*/ 
+                                               false);/*has getter with name like 'is****'*/   
+    
+    
+    return attributesInfo;
+  }
+  
+  /**
+   * Returns operations defined for this MBean as an array of 
+   * MBeanOperationInfo objects.
+   * 
+   * @return operations defined as an array of MBeanOperationInfo objects. 
+   */
+  @Override
+  protected MBeanOperationInfo[] createMBeanOperationInfo() {
+    MBeanOperationInfo[] operationsInfo = new MBeanOperationInfo[MAX_OPERATIONS_COUNT];
+    
+    operationsInfo[0] = new MBeanOperationInfo("getMembers", 
+                                               "Returns ids as strings for all the members - Application Peers & Cache Servers.", 
+                                               new MBeanParameterInfo[] {}, 
+                                               String[].class.getName(), 
+                                               MBeanOperationInfo.ACTION_INFO);
+    
+    MBeanParameterInfo[] getMemberDetailsArgs = new MBeanParameterInfo[1];
+    getMemberDetailsArgs[0] = new MBeanParameterInfo("memberId", String.class.getName(), "Id of the member for all the details are to be retrieved.");
+    operationsInfo[1] = new MBeanOperationInfo("getMemberDetails", 
+                                                "Returns details for a given member", 
+                                                getMemberDetailsArgs, 
+                                                Map.class.getName(), 
+                                                MBeanOperationInfo.ACTION_INFO);
+    
+    /* For retrieving ObjectNames of existing Region MBeans, MBeanServerConnection.queryMBeans(), could be called */
+    MBeanParameterInfo[] getRegionSnapArgs = new MBeanParameterInfo[1];
+    getRegionSnapArgs[0] = new MBeanParameterInfo("memberId", String.class.getName(), "Id of the member on which we want to discover all the region MBean.");
+    operationsInfo[2] = new MBeanOperationInfo("getRegions", 
+                                                "Returns a java.util.Map of details of regions on a member", 
+                                                getRegionSnapArgs, 
+                                                Map.class.getName(), 
+                                                MBeanOperationInfo.ACTION_INFO);
+
+    
+    return operationsInfo;
+  }
+
+  /**
+   * Returns notifications defined for this MBean as an array of
+   * MBeanNotificationInfo objects.
+   * 
+   * @return notification definitions as an array of MBeanNotificationInfo
+   *         objects.
+   */
+  @Override
+  protected MBeanNotificationInfo[] createMBeanNotificationInfo() {
+    MBeanNotificationInfo[] notificationsInfo = new MBeanNotificationInfo[MAX_NOTIFICATIONS_COUNT];
+    
+    String[] notificationTypes = new String[] {AdminDistributedSystemJmxImpl.NOTIF_MEMBER_JOINED};
+    notificationsInfo[0] = new MBeanNotificationInfo(notificationTypes,
+                                                    Notification.class.getName(), 
+                                                    "A GemFire manager, cache, or other member has joined this distributed system.");
+    
+    notificationTypes = new String[] {AdminDistributedSystemJmxImpl.NOTIF_MEMBER_LEFT};
+    notificationsInfo[1] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A GemFire manager, cache, or other member has left the distributed system.");
+    
+    notificationTypes = new String[] {AdminDistributedSystemJmxImpl.NOTIF_MEMBER_CRASHED};
+    notificationsInfo[2] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A member of this distributed system has crashed instead of leaving cleanly.");
+    
+    notificationTypes = new String[] {AdminDistributedSystemJmxImpl.NOTIF_ALERT};
+    notificationsInfo[3] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A member of this distributed system has generated an alert.");
+    
+    notificationTypes = new String[] {AdminDistributedSystemJmxImpl.NOTIF_ADMIN_SYSTEM_DISCONNECT};
+    notificationsInfo[4] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A GemFire manager, cache, or other member has joined this distributed system.");
+    
+    notificationTypes = new String[] {SystemMemberJmx.NOTIF_CACHE_CREATED};
+    notificationsInfo[5] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A cache got created on a member of this distributed system.");
+    
+    notificationTypes = new String[] {SystemMemberJmx.NOTIF_CACHE_CLOSED};
+    notificationsInfo[6] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A cache is closed on a member of this distributed system.");
+    
+    notificationTypes = new String[] {SystemMemberJmx.NOTIF_REGION_CREATED};
+    notificationsInfo[7] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A region is created in a cache on a member of this distributed system.");
+    
+    notificationTypes = new String[] {SystemMemberJmx.NOTIF_REGION_LOST};
+    notificationsInfo[8] = new MBeanNotificationInfo(notificationTypes, 
+                                                    Notification.class.getName(), 
+                                                    "A region was removed from a cache on a member of this distributed system.");
+
+//  String[] notificationTypes5 = new String[] {AdminDistributedSystemJmxImpl.NOTIF_STAT_ALERT};
+//  notificationsInfo[9] = new MBeanNotificationInfo(notificationTypes5, 
+//                                                  Notification.class.getName(), 
+//                                                  "An alert based on statistic(s) has been raised.");    
+
+    return notificationsInfo;
+  }
+  
+  /**
+   * 
+   * @return ObjectName of this MBean
+   */
+  /*default*/ ObjectName getObjectName() {
+    return objectName;
+  }
+
+  /**
+   * Returns the version of the GemFire Enterprise instance as a string.
+   * 
+   * @return GemFire Enterprise version string derived from {@link GemFireVersion}
+   */
+  /* getter for attribute - Version */
+  public String getVersion() {
+    return version;
+  }
+
+  /**
+   * @return the refreshInterval
+   */
+  public int getRefreshInterval() {
+    return refreshInterval;
+  }
+
+  /**
+   * @return the id
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * Connects the Admin Agent in the DS
+   * 
+   * @return AdminDistributedSystem MBean ObjectName
+   * @throws OperationsException
+   *           if connection to the DS fails
+   * @throws AdminException
+   *           if connection to the DS fails
+   */
+  private ObjectName connectToSystem() throws OperationsException, AdminException {
+    ObjectName adminDsObjName = agent.connectToSystem();
+    
+    AdminDistributedSystem adminDS = agent.getDistributedSystem();
+    if (adminDSJmx == null && adminDS instanceof AdminDistributedSystemJmxImpl) {//instanceof checks for null
+      adminDSJmx      = (AdminDistributedSystemJmxImpl) adminDS;
+      refreshInterval = adminDSJmx.getRefreshInterval();
+      id              = adminDSJmx.getId();
+      forwarder.registerNotificationListener(adminDSJmx.getObjectName());
+    }
+
+    return adminDsObjName;
+  }
+  
+  /**
+   * 
+   * @param memberId
+   * @return SystemMemberJmx instance for given memberId
+   * @throws AdminException
+   */
+  private SystemMemberJmx findMember(String memberId) throws AdminException {
+    SystemMemberJmx foundMember = null;
+    
+    if (agent.isConnected()) {
+      SystemMember[] members = adminDSJmx.getSystemMemberApplications();
+      for (SystemMember app : members) {
+        if (app.getId().equals(memberId)) {
+          foundMember = (SystemMemberJmx) app;
+          break;
+        }
+      }
+      
+      if (foundMember == null) {
+        members = adminDSJmx.getCacheVms();
+        for (SystemMember cacheVm : members) {
+          if (cacheVm.getId().equals(memberId)) {
+            foundMember = (SystemMemberJmx) cacheVm;
+            break;
+          }
+        }
+      }
+    }
+    
+    return foundMember;
+  }
+
+  /**
+   * Return ObjectNames for all the Member MBeans in the DS.
+   * 
+   * @return Array of ObjectNames of all Member MBeans
+   * @throws OperationsException
+   *           if (1)agent could not connect in the DS OR 
+   *           (2)Notification Listener could not be registered for the Admin 
+   *              DS MBean OR
+   *           (3)fails to retrieve information from Admin DS
+   */
+  public String[] getMembers() throws OperationsException {
+    String[] members = new String[0];
+      
+    try {
+      if (!isInitialized) {
+        initializeAll(); //initialize if not yet
+      }
+
+      if (adminDSJmx != null) {
+        CacheVm[]      cacheVms = adminDSJmx.getCacheVms();
+        SystemMember[] appVms   = adminDSJmx.getSystemMemberApplications();
+        
+        List<String> membersList = new ArrayList<String>();
+        if (cacheVms != null && cacheVms.length !=0) {
+          for (SystemMember cacheVm : cacheVms) {
+            membersList.add(cacheVm.getId());
+          }
+        }
+        if (appVms != null && appVms.length !=0) {
+          for (SystemMember appVm : appVms) {
+            membersList.add(appVm.getId());
+          }
+        }
+        members = new String[membersList.size()];
+        members = membersList.toArray(members);
+      }
+    } catch (AdminException e) {
+      logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0, "getMembers"), e);
+      throw new OperationsException(e.getMessage());
+    } catch (Exception e) {
+      logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0, "getMembers"), e);
+      throw new OperationsException(e.getMessage());
+    }
+    
+    return members;
+  }
+
+  /**
+   * Returns information including ObjectNames for all regions on a member with
+   * given member id.
+   * 
+   * @param memberId
+   *          member identifier as a String
+   * @return Map of details of all regions on a member with given id
+   * @throws OperationsException
+   *           if fails to retrieve the regions information
+   */
+  public Map<String, Map<String, ?>> getRegions(String memberId) throws OperationsException {
+    Map<String, Map<String, ?>> regionsInfo = new LinkedHashMap<String, Map<String, ?>>();
+    
+    if (memberId != null) {
+      try {
+        SystemMemberJmx foundMember = findMember(memberId);
+        if (foundMember != null) {
+          SystemMemberCacheJmxImpl cache = (SystemMemberCacheJmxImpl) foundMember.getCache();
+          if (cache != null) {
+            Map<String, ObjectName> existingRegionMbeans = getExistingRegionMbeansFullPaths(memberId);
+            //TODO: this is in-efficient
+            //Can a region.create JMX notification be used?
+            regionsInfo = getAllRegionsDetails(cache, existingRegionMbeans);
+            existingRegionMbeans.clear();
+          }
+        }
+      } catch (AdminException e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0_FOR_MEMBER_1, new Object[]{"getRegions", memberId}), e);
+        throw new OperationsException(e.getMessage());
+      } catch (Exception e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0_FOR_MEMBER_1, new Object[]{"getRegions", memberId}), e);
+        throw new OperationsException(e.getMessage());
+      }
+    }
+    
+    return regionsInfo;
+  }
+  
+  /* **************************************************************************/
+  /* ************* INITIALIZE THE ENTIRE ADMIN DS AT A TIME *******************/
+  /* **************************************************************************/
+  /**
+   * Initializes all the possible MBeans for all the members.
+   * 
+   */
+  private void initializeAll() throws OperationsException {
+    try {
+      connectToSystem();
+      if (adminDSJmx != null) {
+        //Members are already inited after connectToSystem. Now init Cache, Region & Stats MBeans
+        SystemMember[] cacheVms = adminDSJmx.getCacheVms();
+        for (int i = 0; i < cacheVms.length; i++) {
+          try {
+            initializeCacheRegionsAndStats((SystemMemberJmx)cacheVms[i]);
+          } catch (AdminException e) {
+            logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INTIALIZING_0_CONTINUING, 
+                           cacheVms[i].getId()), e);
+          }
+        }
+        SystemMember[] appVms = adminDSJmx.getSystemMemberApplications();
+        for (int i = 0; i < appVms.length; i++) {
+          try {
+            initializeCacheRegionsAndStats((SystemMemberJmx)appVms[i]);
+          } catch (AdminException e) {
+            logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INTIALIZING_0_CONTINUING, 
+                           appVms[i].getId()), e);
+          }
+        }
+      }
+    } catch (AdminException e) {
+      logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INTIALIZING), e);
+      throw new OperationsException(e.getMessage());
+    } catch (Exception e) {
+      logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INTIALIZING), e);
+      throw new OperationsException(e.getMessage());
+    }
+    
+    isInitialized = true;
+  }
+  
+  /**
+   * Initializes Cache, Regions & Statistics Types MBeans for the given Member.
+   * 
+   * @param memberJmx
+   *          Member Mbean instance
+   * @throws OperationsException
+   *           if fails to initialize required MBeans
+   * @throws AdminException
+   *           if fails to initialize required MBeans
+   */
+  private void initializeCacheRegionsAndStats(SystemMemberJmx memberJmx) 
+    throws OperationsException, AdminException {
+    if (memberJmx != null) {
+      SystemMemberCacheJmxImpl cache = (SystemMemberCacheJmxImpl) memberJmx.getCache();
+      if (cache != null) {
+        RegionSubRegionSnapshot regionSnapshot = cache.getRegionSnapshot();
+        initializeRegionSubRegions(cache, regionSnapshot);
+      }
+      initStats(memberJmx);
+    }
+  }
+
+  /**
+   * Initializes statistics for a member with the given mbean.
+   * 
+   * @param memberJmx
+   *          Member Mbean instance
+   * @throws AdminException
+   *           if fails to initialize required statistic MBeans
+   */
+  private void initStats(SystemMemberJmx memberJmx) throws AdminException {
+    StatisticResource[] statResources = memberJmx.getStats();
+    for (StatisticResource statResource : statResources) {
+      statResource.getStatistics();
+    }
+  }
+
+  /**
+   * Initializes all regions & its subregions using the Cache MBean and the
+   * RegionSubRegionSnapshot for this cache MBean.
+   * 
+   * @param cache
+   *          Cache MBean resource
+   * @param regionSnapshot
+   *          RegionSubRegionSnapshot instance for the cache
+   * @throws MalformedObjectNameException
+   *           if fails to initialize the region MBean
+   * @throws AdminException
+   *           if fails to initialize the region MBean
+   */
+  @SuppressWarnings("rawtypes")
+  private void initializeRegionSubRegions(SystemMemberCacheJmxImpl cache, 
+                                 RegionSubRegionSnapshot regionSnapshot) 
+                                   throws MalformedObjectNameException, 
+                                          AdminException {
+    String fullPath = regionSnapshot.getFullPath();
+    if (!fullPath.equals(PLACE_HOLDER_ROOT_REGION)) {
+      fullPath = fullPath.substring(PLACE_HOLDER_ROOT_REGION.length()-1);
+
+      cache.manageRegion(fullPath);
+    }
+    
+    Set subRegionSnapshots = regionSnapshot.getSubRegionSnapshots();
+    
+    for (Iterator iterator = subRegionSnapshots.iterator(); iterator.hasNext();) {
+      RegionSubRegionSnapshot subRegion = (RegionSubRegionSnapshot) iterator.next();
+      try {
+        initializeRegionSubRegions(cache, subRegion);
+      } catch (AdminException e) {
+        logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INTIALIZING_0_CONTINUING, subRegion.getFullPath()), e);
+      }
+    }
+  }
+  
+  
+  /* **************************************************************************/
+  /* ********************** EVERYTHING HYPERIC NEEDS **************************/
+  /* **************************************************************************/
+  
+  /* constants defined that could be used simply retrieve needed info from Map */
+  private static final String TYPE_NAME_CACHESERVER = "Cache Server";
+  private static final String TYPE_NAME_APPLICATION = "Application Peer";
+  /*
+   * NOTE -
+   * (My Understanding about the followings - abhishek)  
+   * 1. CacheVM - a VM started using Cache Server Launcher. This is considered 
+   * to be a dedicated cache VM because there is only GemFire Cache code 
+   * running here.
+   * 2. ApplicationVM - a VM started with a written code using APIs and we can 
+   * not guarantee that there will be ONLY GemFire code running in this VM.
+   * 3. Cache Server - Responsible for serving requests from the clients. There 
+   * could be multiple of these per Cache and hence per VM - one of 1 or 2 above.
+   * These could be specified by <cache-server> (or deprecated <bridge-server>)
+   * element(s) in the cache-xml file or using an API Cache.addCacheServer().
+   */
+
+//  private static final String VERSION          = "gemfire.version.string";
+//  private static final String MEMBER_COUNT     = "gemfire.membercount.int";
+//  private static final String GATEWAYHUB_COUNT = "gemfire.gatewayhubcount.int";
+//  private static final String CLIENT_COUNT     = "gemfire.clientcount.int";
+
+  private static final String MEMBER_ID = DistributionConfig.GEMFIRE_PREFIX + "member.id.string";
+  private static final String MEMBER_NAME = DistributionConfig.GEMFIRE_PREFIX + "member.name.string";
+  private static final String MEMBER_HOST = DistributionConfig.GEMFIRE_PREFIX + "member.host.string";
+  private static final String MEMBER_PORT = DistributionConfig.GEMFIRE_PREFIX + "member.port.int";
+  private static final String MEMBER_UPTIME = DistributionConfig.GEMFIRE_PREFIX + "member.uptime.long";
+  private static final String MEMBER_CLIENTS = DistributionConfig.GEMFIRE_PREFIX + "member.clients.map";
+  private static final String MEMBER_REGIONS = DistributionConfig.GEMFIRE_PREFIX + "member.regions.map";
+  private static final String MEMBER_TYPE = DistributionConfig.GEMFIRE_PREFIX + "member.type.string";
+  private static final String IS_SERVER = DistributionConfig.GEMFIRE_PREFIX + "member.isserver.boolean";
+  private static final String IS_GATEWAY = DistributionConfig.GEMFIRE_PREFIX + "member.isgateway.boolean";
+
+  private static final String MEMBER_STATSAMPLING_ENABLED = DistributionConfig.GEMFIRE_PREFIX + "member.config.statsamplingenabled.boolean";
+  private static final String MEMBER_TIME_STATS_ENABLED = DistributionConfig.GEMFIRE_PREFIX + "member.config.timestatsenabled.boolean";
+
+  private static final String STATS_PROCESSCPUTIME = DistributionConfig.GEMFIRE_PREFIX + "member.stat.processcputime.long";
+  private static final String STATS_CPUS = DistributionConfig.GEMFIRE_PREFIX + "member.stat.cpus.int";
+  private static final String STATS_USEDMEMORY = DistributionConfig.GEMFIRE_PREFIX + "member.stat.usedmemory.long";
+  private static final String STATS_MAXMEMORY = DistributionConfig.GEMFIRE_PREFIX + "member.stat.maxmemory.long";
+  private static final String STATS_GETS = DistributionConfig.GEMFIRE_PREFIX + "member.stat.gets.int";
+  private static final String STATS_GETTIME = DistributionConfig.GEMFIRE_PREFIX + "member.stat.gettime.long";
+  private static final String STATS_PUTS = DistributionConfig.GEMFIRE_PREFIX + "member.stat.puts.int";
+  private static final String STATS_PUTTIME = DistributionConfig.GEMFIRE_PREFIX + "member.stat.puttime.long";
+
+  private static final String REGION_NAME = DistributionConfig.GEMFIRE_PREFIX + "region.name.string";
+  private static final String REGION_PATH = DistributionConfig.GEMFIRE_PREFIX + "region.path.string";
+  private static final String REGION_SCOPE = DistributionConfig.GEMFIRE_PREFIX + "region.scope.string";
+  private static final String REGION_DATAPOLICY = DistributionConfig.GEMFIRE_PREFIX + "region.datapolicy.string";
+  private static final String REGION_INTERESTPOLICY = DistributionConfig.GEMFIRE_PREFIX + "region.interestpolicy.string";
+  private static final String REGION_ENTRYCOUNT = DistributionConfig.GEMFIRE_PREFIX + "region.entrycount.int";
+  private static final String REGION_DISKATTRS = DistributionConfig.GEMFIRE_PREFIX + "region.diskattrs.string";
+
+  private static final String CLIENT_ID = DistributionConfig.GEMFIRE_PREFIX + "client.id.string";
+  private static final String CLIENT_NAME = DistributionConfig.GEMFIRE_PREFIX + "client.name.string";
+  private static final String CLIENT_HOST = DistributionConfig.GEMFIRE_PREFIX + "client.host.string";
+  private static final String CLIENT_QUEUESIZE = DistributionConfig.GEMFIRE_PREFIX + "client.queuesize.int";
+  private static final String CLIENT_STATS_GETS = DistributionConfig.GEMFIRE_PREFIX + "client.stats.gets.int";
+  private static final String CLIENT_STATS_PUTS = DistributionConfig.GEMFIRE_PREFIX + "client.stats.puts.int";
+  private static final String CLIENT_STATS_CACHEMISSES = DistributionConfig.GEMFIRE_PREFIX + "client.stats.cachemisses.int";
+  private static final String CLIENT_STATS_CPUUSAGE = DistributionConfig.GEMFIRE_PREFIX + "client.stats.cpuusage.long";
+  private static final String CLIENT_STATS_CPUS = DistributionConfig.GEMFIRE_PREFIX + "client.stats.cpus.int";
+  private static final String CLIENT_STATS_UPDATETIME = DistributionConfig.GEMFIRE_PREFIX + "client.stats.updatetime.long";
+  private static final String CLIENT_STATS_THREADS = DistributionConfig.GEMFIRE_PREFIX + "client.stats.threads.int";
+  
+  /**
+   * 
+   * @param memberId
+   * @return All the required details for a member with given memberId 
+   * @throws OperationsException
+   */
+  public Map<String, Object> getMemberDetails(String memberId) 
+    throws OperationsException {
+    Map<String, Object> allDetails = new TreeMap<String, Object>();
+
+    if (memberId != null) {
+      try {
+        SystemMemberJmx member = findMember(memberId);
+        if (member != null) {
+          SystemMemberCacheJmxImpl cache = (SystemMemberCacheJmxImpl) member.getCache();
+          GemFireMemberStatus snapshot   = cache.getSnapshot();
+          boolean isServer     = snapshot.getIsServer();
+          boolean isGatewayHub = snapshot.getIsGatewayHub();
+          
+          //1. Member info
+          allDetails.put(MEMBER_ID, member.getId());
+          allDetails.put(MEMBER_NAME, member.getName());
+          String host = member.getHost();//from of GemFireVM.getHost
+          InetAddress hostAddr = member.getHostAddress();
+          //possibility of null host address
+          if (hostAddr != null) {
+            host = hostAddr.getHostName();
+          }
+          allDetails.put(MEMBER_HOST, host);
+          allDetails.put(MEMBER_UPTIME, snapshot.getUpTime());
+          allDetails.put(IS_SERVER, isServer);
+          allDetails.put(IS_GATEWAY, isGatewayHub);
+          
+          String memberType = "";
+          if (member instanceof CacheServerJmxImpl) {
+            memberType = TYPE_NAME_CACHESERVER;
+          } else {//Mark it of Application type if neither a gateway hub nor a server
+            memberType = TYPE_NAME_APPLICATION;
+          }
+//          if (isGatewayHub) {
+//            memberType = TYPE_NAME_GATEWAYHUB;
+//          } else if (isServer) {
+//            memberType = TYPE_NAME_CACHESERVER;
+//          } else {//Mark it of Application type if neither a gateway nor a server
+//            memberType = TYPE_NAME_APPLICATION;
+//          }
+          allDetails.put(MEMBER_TYPE, memberType);
+
+          //2. Region info
+          Map<String, ObjectName> existingRegionMbeans = getExistingRegionMbeansFullPaths(memberId);
+          allDetails.put(MEMBER_REGIONS, getAllRegionsDetails(cache, existingRegionMbeans));
+          existingRegionMbeans.clear();
+
+          //3. Clients info
+          allDetails.put(MEMBER_CLIENTS, getClientDetails(snapshot));
+          
+          boolean statSamplingEnabled = true;
+          //assuming will never return as per current implementation
+          ConfigurationParameter[] configParams = member.getConfiguration();
+          for (ConfigurationParameter configParam : configParams) {
+            if (STATISTIC_SAMPLING_ENABLED.equals(configParam.getName())) {
+              allDetails.put(MEMBER_STATSAMPLING_ENABLED, configParam.getValue());
+              statSamplingEnabled = Boolean.parseBoolean(""+configParam.getValue());
+            } else if (ENABLE_TIME_STATISTICS.equals(configParam.getName())) {
+              allDetails.put(MEMBER_TIME_STATS_ENABLED, configParam.getValue());
+            }
+          }
+          
+          //5. Stats info
+          allDetails.putAll(getRequiredStats(member, statSamplingEnabled));
+
+          SystemMemberCacheServer[] cacheServers = cache.getCacheServers();
+          //attempt refreshing the cache info once
+          if (cacheServers.length == 0) {
+            cache.refresh();
+            cacheServers = cache.getCacheServers();
+          }
+          Integer memberCacheServerPort = Integer.valueOf(0);
+          if (cacheServers.length != 0) {
+            /*
+             * Taking the first cache server port.
+             * We don't recommend multiple cache severs for a cache.
+             */
+            memberCacheServerPort = Integer.valueOf(cacheServers[0].getPort());
+          }
+          allDetails.put(MEMBER_PORT, memberCacheServerPort);
+        }
+        
+      } catch (AdminException e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0_FOR_MEMBER_1, 
+                          new Object[] {"getMemberDetails", memberId}), e);
+        throw new OperationsException(e.getMessage());
+      } catch (Exception e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_FOR_OPERATION_0_FOR_MEMBER_1, 
+                          new Object[] {"getMemberDetails", memberId}), e);
+        throw new OperationsException(e.getMessage());
+      }
+    }
+    
+    return allDetails;
+  }
+  
+  /**
+   * 
+   * @param snapshot
+   * @return Map of client details 
+   */
+  @SuppressWarnings("rawtypes")
+  private Map<String, Map<String, ?>> getClientDetails(GemFireMemberStatus snapshot) {
+    Map<String, Map<String, ?>> clientsInfo = 
+      new LinkedHashMap<String, Map<String, ?>>();
+    
+    Set connectedClients = snapshot.getConnectedClients();
+    if (!connectedClients.isEmpty()) {
+      Map clientHealthStatsMap = snapshot.getClientHealthStats();
+      
+      for (Iterator iterator = connectedClients.iterator(); iterator.hasNext();) {
+        Map<String, Object> clientData = new HashMap<String, Object>();
+        String clientId = (String) iterator.next();
+        String host     = snapshot.getClientHostName(clientId);
+        clientData.put(CLIENT_ID, clientId);
+        clientData.put(CLIENT_NAME, extractClientName(clientId, host));
+        clientData.put(CLIENT_HOST, host);
+        clientData.put(CLIENT_QUEUESIZE, snapshot.getClientQueueSize(clientId));
+  
+        ClientHealthStats clientHealthStats = (ClientHealthStats) clientHealthStatsMap.get(clientId);
+        if (clientHealthStats != null) {
+          clientData.put(CLIENT_STATS_GETS, clientHealthStats.getNumOfGets());
+          clientData.put(CLIENT_STATS_PUTS, clientHealthStats.getNumOfPuts());
+          clientData.put(CLIENT_STATS_CACHEMISSES, clientHealthStats.getNumOfMisses());
+          clientData.put(CLIENT_STATS_CPUUSAGE, clientHealthStats.getProcessCpuTime());
+          clientData.put(CLIENT_STATS_CPUS, clientHealthStats.getCpus());
+          clientData.put(CLIENT_STATS_UPDATETIME, clientHealthStats.getUpdateTime().getTime());
+          clientData.put(CLIENT_STATS_THREADS, clientHealthStats.getNumOfThreads());
+        } else {
+          clientData.put(CLIENT_STATS_GETS, Integer.valueOf(0));
+          clientData.put(CLIENT_STATS_PUTS, Integer.valueOf(0));
+          clientData.put(CLIENT_STATS_CACHEMISSES, Integer.valueOf(0));
+          clientData.put(CLIENT_STATS_CPUUSAGE, Long.valueOf(0));
+          clientData.put(CLIENT_STATS_CPUS, Integer.valueOf(0));
+          clientData.put(CLIENT_STATS_UPDATETIME, Long.valueOf(0));
+          clientData.put(CLIENT_STATS_THREADS, Integer.valueOf(0));
+        }
+        
+        clientsInfo.put(clientId, clientData);
+      }
+    }
+    
+    return clientsInfo;
+  }
+
+  /**
+   * Returns a Map containing information about regions.
+   * 
+   * @param cache
+   *          Reference to an MBean representing a Cache on a member
+   * @param existingRegionMbeans
+   *          Map of Path against Region MBean ObjectNames
+   * @return Map of all region details
+   * @throws OperationsException
+   *           if fails to retrieve
+   */
+  private Map<String, Map<String, ?>> getAllRegionsDetails(
+                                  SystemMemberCacheJmxImpl cache, 
+                                  Map<String, ObjectName> existingRegionMbeans) 
+                                  throws OperationsException {
+    Map<String, Map<String, ?>> regionsInfo = 
+                        new TreeMap<String, Map<String, ?>>();
+    
+    if (cache != null) {
+      try {
+        RegionSubRegionSnapshot regionSnapshot = cache.getRegionSnapshot();
+        collectAllRegionsDetails(cache, regionSnapshot, regionsInfo, existingRegionMbeans);
+      } catch (AdminException e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.ONE_ARG, "Exception occurred while getting region details."), e);
+        throw new OperationsException(e.getMessage());
+      } catch (Exception e) {
+        logger.warn(LocalizedMessage.create(LocalizedStrings.ONE_ARG, "Exception occurred while getting region details."), e);
+        throw new OperationsException(e.getMessage());
+      }
+    }
+    
+    return regionsInfo;
+  }
+
+  /**
+   * Collects all the region details from the RegionSubRegionSnapshot instance
+   * passed and the Cache MBean. Checks in the set of existingRegionMbeans
+   * before initializing Region Mbeans if there are not initialized yet.
+   * 
+   * @param cache
+   *          Cache MBean instance
+   * @param regionSnapshot
+   *          RegionSubRegionSnapshot instance
+   * @param regionsInfo
+   *          Map of regions information that gets populated recursively
+   * @param existingRegionMbeans
+   *          Map of ObjectNames of existing region MBeans
+   * @throws AdminException
+   *           if unable to initialize region MBean
+   * @throws OperationsException
+   *           if fails to retrieve the Region MBean attribute info
+   * @throws MBeanException
+   *           if fails to retrieve the Region MBean attribute info
+   * @throws ReflectionException
+   *           if fails to retrieve the Region MBean attribute info
+   */
+  @SuppressWarnings("rawtypes")
+  private void collectAllRegionsDetails(SystemMemberCacheJmxImpl cache, 
+                                 RegionSubRegionSnapshot regionSnapshot, 
+                                 Map<String, Map<String, ?>> regionsInfo,
+                                 Map<String, ObjectName> existingRegionMbeans) 
+                                 throws AdminException, OperationsException, 
+                                        MBeanException, ReflectionException {
+    String fullPath = regionSnapshot.getFullPath();
+    if (!fullPath.equals(PLACE_HOLDER_ROOT_REGION)) {
+      fullPath = fullPath.substring(PLACE_HOLDER_ROOT_REGION.length()-1);
+      String name = regionSnapshot.getName();
+      Integer entryCount = Integer.valueOf(regionSnapshot.getEntryCount());
+      Map<String, Object> details = new TreeMap<String, Object>();
+      details.put(REGION_NAME, name);
+      details.put(REGION_PATH, fullPath);
+      details.put(REGION_ENTRYCOUNT, entryCount);
+      
+      ObjectName regionObjectName = existingRegionMbeans.get(fullPath);
+      if (regionObjectName == null) {//initialize if has not yet been 
+        regionObjectName = cache.manageRegion(fullPath);
+      }
+
+      Object attribute = getAttribute(regionObjectName, "scope", NOT_AVAILABLE);
+      attribute = attribute != null ? attribute.toString() : attribute;
+      details.put(REGION_SCOPE, attribute);
+      
+      attribute = getAttribute(regionObjectName, "dataPolicy", NOT_AVAILABLE);
+      attribute = attribute != null ? attribute.toString() : attribute;
+      details.put(REGION_DATAPOLICY, attribute);
+
+      SubscriptionAttributes interestPolicyAttr = 
+          (SubscriptionAttributes) getAttribute(regionObjectName, 
+                                                "subscriptionAttributes", null);
+      String interestPolicyStr = NOT_AVAILABLE;
+      if (interestPolicyAttr != null) {
+        InterestPolicy interestPolicy = interestPolicyAttr.getInterestPolicy();
+        if (interestPolicy != null) {
+          interestPolicyStr = interestPolicy.toString();
+        }
+      }
+      details.put(REGION_INTERESTPOLICY, interestPolicyStr);
+
+      attribute = getAttribute(regionObjectName, "diskWriteAttributes", NOT_AVAILABLE);
+      attribute = attribute != null ? attribute.toString() : attribute;
+      details.put(REGION_DISKATTRS, attribute);
+      
+      regionsInfo.put(fullPath, details);
+    }
+    
+    Set subRegionSnapshots = regionSnapshot.getSubRegionSnapshots();
+    
+    for (Iterator iterator = subRegionSnapshots.iterator(); iterator.hasNext();) {
+      RegionSubRegionSnapshot subRegion = (RegionSubRegionSnapshot) iterator.next();
+      collectAllRegionsDetails(cache, subRegion, regionsInfo, existingRegionMbeans);
+    }
+  }
+  
+  /**
+   * Checks if the given host name string contains ':' as in IPv6 host address.
+   * 
+   * @param host
+   *          host name string
+   * @return true if the host string contains ':', false otherwise
+   */
+  private static boolean isIPv6(String host) {
+    return host.contains(":");
+  }
+
+  /**
+   * Checks if the given host name is actually a String representation of an
+   * IPv4 address.
+   * 
+   * @param host
+   *          host name string
+   * @return true if given host name is a String representation of an IPv4
+   *         address, false otherwise
+   */
+  private static boolean isIPv4(String host) {
+    String regex = "\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}";
+    
+    return host.matches(regex);
+  }
+  
+  /**
+   * Excludes the host name from the client id and returns the String. If the
+   * host name can not be detected, returns an empty string. Typically, the
+   * client id looks like: HOST(VM_PID:VM_KIND):PORT:RANDOM_STRING:CLIENT_NAME
+   * 
+   * Extracts the client name from the client id. If the client id is not in the
+   * expected format, returns 'N/A'
+   * 
+   * @param clientId
+   *          string identifier for a client
+   * @param host
+   *          host name (FQDN) the client is running on
+   * @return name extracted from given client id
+   */
+  /*
+   * Some examples of Client Id format: 
+   * (1) Java Client:
+   * nase(21716:loner):51789:42e9a0bf:client_nase_21716
+   * nase(2560:loner):2:7a84729a:Feeder
+   * 
+   * (2) Native Client:
+   * nase(21045:loner):2:GFNative_OnNnEpyRWL:ExampleDistributedSystem
+   * 
+   * (3) IPv6 Host whose name can not be resolved:
+   * fdf0:76cf:a0ed:9449:0:0:0:1001(21716:loner):51789:42e9a0b:client_nase_21716
+   * fdf0:76cf:a0ed:9449:0:0:0:1001:51789:42e9a0b:client_nase_21716 
+   */
+  private static String extractClientName(String clientId, String host) {
+    /* This isIPv6, isIPv4, extractClientName is taken from GFMon code base*/
+    String hostExcludedId = "";
+    if ( (isIPv6(host) || isIPv4(host))&& clientId.startsWith(host)) {
+      hostExcludedId = clientId.substring(host.length());
+    } else {
+      int firstDotIndex = host.indexOf(".");
+      if (firstDotIndex != -1) {
+        String hostShortName = host.substring(0, firstDotIndex);
+        hostExcludedId = clientId.substring(hostShortName.length());
+      }
+    }
+    
+    String vmPIDAndKindRegex = "\\(\\w+:\\w+\\)";
+    String regex             = "(\\<ec\\>)?:[0-9]+(:\\w+){2}+";
+    String name              = NOT_AVAILABLE;
+    String temp              = hostExcludedId;
+
+    int openIndex = temp.indexOf("(");
+    if (openIndex != -1) {      
+      regex = vmPIDAndKindRegex + regex;
+    }
+
+    if (temp.matches(regex)) {
+      String[] splitted = temp.split(":");
+      name = splitted[splitted.length - 1];
+    }
+    
+    return name;
+  }
+
+  /**
+   * Returns a Map of all the statistics required for Hyperic currently. It
+   * relies on the attribute of the StatisticsResource Mbeans.
+   * 
+   * @param member
+   *          instance for which the stats are needed
+   * @return Map of all the statistics required for Hyperic currently.
+   * @throws OperationsException
+   *           exceptions thrown while retrieving the attributes
+   */
+  private Map<String, Object> getRequiredStats(SystemMemberJmx member, boolean statSamplingEnabled) throws OperationsException {
+    Map<String, Object> statDetails = new TreeMap<String, Object>();
+    
+    try {
+      if (!statSamplingEnabled) {
+        statDetails.put(STATS_PROCESSCPUTIME, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_CPUS, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_MAXMEMORY, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_USEDMEMORY, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_GETS, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_GETTIME, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_PUTS, NOT_AVAILABLE_NUMBER);
+        statDetails.put(STATS_PUTTIME, NOT_AVAILABLE_NUMBER);
+      } else {
+        MBeanServer mBeanServer = agent.getMBeanServer();
+        Number defaultVal     = NOT_AVAILABLE_NUMBER;
+        Number processCpuTime = defaultVal;
+        Number cpus           = defaultVal;
+        Number maxMemory      = defaultVal;
+        Number usedMemory     = defaultVal;
+        Number gets           = defaultVal;
+        Number getTime        = defaultVal;
+        Number puts           = defaultVal;
+        Number putTime        = defaultVal;
+        
+        ObjectName[] vmMemoryUsageStats = getExistingStats(member.getId(), "vmHeapMemoryStats");
+        ObjectName[] vmStats            = getExistingStats(member.getId(), "vmStats");
+        ObjectName[] cachePerfStats     = getExistingStats(member.getId(), "cachePerfStats");
+        boolean needToReinit = false;
+        if (vmMemoryUsageStats.length == 0 || vmStats.length == 0 || cachePerfStats.length == 0) {
+          //if the StatisticResource MBeans are not created
+          needToReinit = true;
+        }
+        if(!needToReinit) {
+          /*
+           * To handle a case when the StatisticResource MBeans are created but 
+           * not registered with RefreshTimer. If VMMemoryUsageStats are 
+           * present, maxMemory should always be non-zero. */
+          for (int i = 0; i < vmMemoryUsageStats.length; i++) {//ideally there should be a single instance
+            String type = (String) mBeanServer.getAttribute(vmMemoryUsageStats[i], "type");
+            
+            if ("VMMemoryUsageStats".equals(type)) { //first instance that has Statistics Type name
+              maxMemory  = (Number) getAttribute(vmMemoryUsageStats[i], "maxMemory", defaultVal);
+              break;
+            }
+          }
+          
+          needToReinit = 0 == maxMemory.longValue(); 
+        }
+
+        if(needToReinit) {
+          logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_REINITIALIZING_STATS_FOR_0, member.getId()));
+          initStats(member);
+
+          vmMemoryUsageStats = getExistingStats(member.getId(), "vmHeapMemoryStats");
+          vmStats            = getExistingStats(member.getId(), "vmStats");
+          cachePerfStats     = getExistingStats(member.getId(), "cachePerfStats");
+        }
+        
+        for (int i = 0; i < vmMemoryUsageStats.length; i++) {//ideally there should be a single instance
+          String type = (String) mBeanServer.getAttribute(vmMemoryUsageStats[i], "type");
+          
+          if ("VMMemoryUsageStats".equals(type)) { //first instance that has Statistics Type name
+            maxMemory  = (Number) getAttribute(vmMemoryUsageStats[i], "maxMemory", defaultVal);
+            usedMemory = (Number) getAttribute(vmMemoryUsageStats[i], "usedMemory", defaultVal);
+            break;
+          }
+        }
+
+        for (int i = 0; i < vmStats.length; i++) {//ideally there should be a single instance
+          String type = (String) mBeanServer.getAttribute(vmStats[i], "type");
+          
+          if ("VMStats".equals(type)) { //first instance that has Statistics Type name
+            processCpuTime = (Number) getAttribute(vmStats[i], "processCpuTime", defaultVal);
+            cpus           = (Number) getAttribute(vmStats[i], "cpus", defaultVal);
+            break;
+          }
+        }
+        
+        for (int i = 0; i < cachePerfStats.length; i++) {//ideally there should be a single instance
+          String type = (String) mBeanServer.getAttribute(cachePerfStats[i], "type");
+          
+          if ("CachePerfStats".equals(type)) { //first instance that has Statistics Type name
+            gets    = (Number) getAttribute(cachePerfStats[i], "gets", defaultVal);
+            getTime = (Number) getAttribute(cachePerfStats[i], "getTime", defaultVal);
+            puts    = (Number) getAttribute(cachePerfStats[i], "puts", defaultVal);
+            putTime = (Number) getAttribute(cachePerfStats[i], "putTime", defaultVal);
+            break;
+          }
+        }
+        
+        statDetails.put(STATS_PROCESSCPUTIME, processCpuTime == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : processCpuTime.longValue());
+        statDetails.put(STATS_CPUS, cpus == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : cpus.intValue());
+        statDetails.put(STATS_MAXMEMORY,  maxMemory == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : maxMemory.longValue());
+        statDetails.put(STATS_USEDMEMORY, usedMemory == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : usedMemory.longValue());
+        statDetails.put(STATS_GETS, gets == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : gets.intValue());
+        statDetails.put(STATS_GETTIME, getTime == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : getTime.intValue());
+        statDetails.put(STATS_PUTS, puts == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : puts.intValue());
+        statDetails.put(STATS_PUTTIME, putTime == NOT_AVAILABLE_NUMBER ? NOT_AVAILABLE_NUMBER : putTime.longValue());
+      }
+    } catch (Exception e) {
+      logger.warn(e.getMessage(), e);
+      throw new OperationsException(e.getMessage());
+    }
+    
+    return statDetails;
+  }
+
+  /**
+   * Returns attribute with given attribute name on MBean with given ObjectName.
+   * 
+   * 
+   * @param objectName
+   *          ObjectName for the MBean
+   * @param attribute
+   *          attribute name
+   * @param unavailableValue
+   *          return this value if the attribute value is null
+   * @return value of attribute with given attribute name
+   * @throws OperationsException
+   *           if attribute is not found for MBean with this ObjectName or MBean
+   *           instance is not found
+   * @throws MBeanException
+   *           if MBeans getter throws exception
+   * @throws ReflectionException
+   *           thrown when trying to invoke the setter.
+   */
+  private Object getAttribute(ObjectName objectName, String attribute, 
+      Object unavailableValue) 
+        throws OperationsException, MBeanException, ReflectionException {
+    /* NOTE: callers methods rely on non-null value being returned */
+    Object value = null;
+    
+    MBeanServer mBeanServer = agent.getMBeanServer();
+    value = mBeanServer.getAttribute(objectName, attribute);
+    
+    value = (value != null)? value : unavailableValue;
+    
+    return value;
+  }
+
+  /**
+   * Return Map of region full against the ObjectName of existing region MBeans.
+   * 
+   * @param memberId
+   *          string identifier of a member
+   * @return Map of region path vs ObjectName for existing region MBeans
+   * @throws MalformedObjectNameException
+   *           If the query expression used is not valid
+   */
+  private Map<String, ObjectName> getExistingRegionMbeansFullPaths(String memberId) throws MalformedObjectNameException {
+    Map<String, ObjectName> pathsToObjName = new HashMap<String, ObjectName>();
+
+    if (memberId != null && memberId.trim().length() != 0) {
+      Object[] params = new Object[] {MBeanUtil.makeCompliantMBeanNameProperty(memberId)};
+      Set<ObjectName> queryNames = queryObjectNames(REGION_QUERY_EXPRESSION, params);
+      for (ObjectName objectName : queryNames) {
+        pathsToObjName.put(objectName.getKeyProperty("path"), objectName);
+      }
+    }
+    
+    return pathsToObjName;
+  }
+
+  /**
+   * Returns an array of ObjectNames existing statistics types MBeans
+   * 
+   * @param memberId
+   *          string identifier of a member
+   * @param name
+   *          text id of the stats which appears in the stats ObjectName as name
+   *          keyProperty
+   * @return Array of Stats MBean ObjectNames
+   * @throws MalformedObjectNameException
+   *           If the query expression used is not valid
+   */
+  private ObjectName[] getExistingStats(String memberId, String name) throws MalformedObjectNameException {
+    ObjectName[] statObjectNames = new ObjectName[0];
+    
+    if (memberId != null && memberId.trim().length() != 0) {
+      Object[] params = new Object[] {MBeanUtil.makeCompliantMBeanNameProperty(memberId), name};
+      Set<ObjectName> queryNames = queryObjectNames(STATS_QUERY_EXPRESSION, params);
+      statObjectNames = new ObjectName[queryNames.size()];
+      statObjectNames = queryNames.toArray(statObjectNames);
+    }
+    
+    return statObjectNames;
+  }
+
+  /**
+   * Queries the MBean server with the string formed using placing the params in
+   * the parameterized string passed as queryStr.
+   * 
+   * @param queryStr
+   *          parameterized string
+   * @param params
+   *          params to put in the string
+   * @return results of an ObjectName query
+   * @throws MalformedObjectNameException
+   *           If the query expression ObjectName formed is not valid
+   */
+  private Set<ObjectName> queryObjectNames(String queryStr, Object ... params) 
+    throws MalformedObjectNameException {
+    Set<ObjectName> queried = Collections.emptySet();    
+    
+    queryStr = MessageFormat.format(queryStr, params);    
+    ObjectName queryExp = ObjectName.getInstance(queryStr);
+    queried = agent.getMBeanServer().queryNames(null, queryExp);
+    
+    return queried;
+  }
+  
+  
+  /* *************************************************************************/
+  /* **************** NOTIFICATION EMITTER IMPLEMENTATION ********************/
+  /* *************************************************************************/
+
+  /**
+   * @see NotificationEmitter#addNotificationListener(NotificationListener, NotificationFilter, Object)
+   */
+  public void addNotificationListener(NotificationListener listener,
+      NotificationFilter filter, Object handback)
+      throws IllegalArgumentException {
+    forwarder.addNotificationListener(listener, filter, handback);
+  }
+
+  /**
+   * @see NotificationEmitter#removeNotificationListener(NotificationListener)
+   */
+  public void removeNotificationListener(NotificationListener listener)
+      throws ListenerNotFoundException {
+    forwarder.removeNotificationListener(listener);
+  }
+
+  /**
+   * @see NotificationEmitter#getNotificationInfo()
+   */
+  public MBeanNotificationInfo[] getNotificationInfo() {
+    return getMBeanInfo().getNotifications();
+  }
+  
+  /**
+   * @see NotificationEmitter#removeNotificationListener(NotificationListener, NotificationFilter, Object)
+   */
+  public void removeNotificationListener(NotificationListener listener,
+      NotificationFilter filter, Object handback)
+      throws ListenerNotFoundException {
+    forwarder.removeNotificationListener(listener, filter, handback);
+  }
+  
+}
+
+/**
+ * This class acts as a hub for the Notifications defined on
+ * AdminDistributedSystem & SystemMember MBeans. This acts as a listener for
+ * these notifications and broadcasts them as notifications from the
+ * {@link MemberInfoWithStatsMBean} MBean. This class extends
+ * {@link NotificationBroadcasterSupport} only to have the functionality to send
+ * notifications.
+ * 
+ * 
+ * @since GemFire 6.5
+ */
+class NotificationForwarder extends NotificationBroadcasterSupport 
+  implements NotificationListener {
+  
+  private static final Logger logger = LogService.getLogger();
+  
+  /* sequence generator for notifications from GemFireTypesWrapper MBean */
+  private static AtomicLong notificationSequenceNumber = new AtomicLong();
+
+  /* reference to the MBeanServer instance */
+  private MBeanServer   mBeanServer;
+
+  /**
+   * Default Constructor
+   * 
+   * @param mBeanServer
+   *          reference to the MBeanServer instance
+   */
+  /*default*/NotificationForwarder(MBeanServer mBeanServer) {
+    this.mBeanServer = mBeanServer;
+  }
+
+  /**
+   * Handles notifications as: 1. Member Joined: Registers this
+   * NotificationForwarder as a notification listener for Cache/Region
+   * Notifications. 2. Member Left/Crashed: Unregisters this
+   * NotificationForwarder as a notification listener for Cache/Region
+   * Notifications. 3. AdminDistributedSystem Disconnected: Unregisters this
+   * NotificationForwarder as a notification listener for member Notifications.
+   * 
+   * Forwards the notifications to the JMX Clients that have registered for
+   * notifications on this MBean
+   * 
+   * @param notification
+   *          notification to be handled
+   * @param handback
+   *          handback object used while NotificationForwarder was registered
+   * 
+   * @see NotificationListener#handleNotification(Notification, Object)
+   */
+  public void handleNotification(Notification notification, Object handback) {
+    Object notifSource = notification.getSource();
+    if (AdminDistributedSystemJmxImpl.NOTIF_MEMBER_JOINED.equals(notification.getType())) {
+      ObjectName source = (ObjectName) notifSource;
+      //initialize statistics/register with refreshTimer for new member
+      String[] noArgs = {};
+      try {
+        ObjectName[] stats = (ObjectName[]) mBeanServer.invoke(source, "manageStats", noArgs, noArgs);
+        if (stats != null) {
+          for (ObjectName stat : stats) {
+            mBeanServer.invoke(stat, "getStatistics", noArgs, noArgs);
+          }
+        }
+        logger.debug("getStatistics call completed with no exceptions.");
+      } catch (ReflectionException e) {
+        logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INITIALIZING_STATISICS_FOR_0, source.toString()), e);
+      } catch (MBeanException e) {
+        logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INITIALIZING_STATISICS_FOR_0, source.toString()), e);
+      } catch (InstanceNotFoundException e) {
+        logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_INITIALIZING_STATISICS_FOR_0, source.toString()), e);
+      }
+      //register this listener for joined member's cache/region notifications
+      try {
+        registerNotificationListener(source);
+      } catch (OperationsException e) {
+        logger.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_REGISTERING_NOTIFICATION_LISTENER_FOR_0, source.toString()), e);
+      }
+    } /*else if (AdminDistributedSystemJmxImpl.NOTIF_MEMBER_LEFT.equals(notification.getType()) || 
+               AdminDistributedSystemJmxImpl.NOTIF_MEMBER_CRASHED.equals(notification.getType())) {
+      ObjectName source = (ObjectName) notifSource;
+      //unregister this listener from left member's cache/region notifications
+      try {
+        unregisterNotificationListener(source);
+      } catch (OperationsException e) {
+        logwriter.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_UNREGISTERING_NOTIFICATION_LISTENER_FOR_0, source.toString(), e);
+      }
+    } else if (AdminDistributedSystemJmxImpl.NOTIF_ADMIN_SYSTEM_DISCONNECT.equals(notification.getType())) {
+      String source = (String) notifSource;
+      //This notification does not have ObjectName as a source. 
+      try {
+        ObjectName instance = ObjectName.getInstance(source);
+        unregisterNotificationListener(instance);
+      } catch (OperationsException e) {
+        logwriter.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_UNREGISTERING_NOTIFICATION_LISTENER_FOR_0, source.toString(), e);
+      } catch (NullPointerException e) {
+        logwriter.info(LocalizedMessage.create(LocalizedStrings.MemberInfoWithStatsMBean_EXCEPTION_WHILE_UNREGISTERING_NOTIFICATION_LISTENER_FOR_0, source.toString(), e);
+      }
+    } */
+    //NOTIF_ALERT is sent as is
+    
+    //TODO: Check if same notification instance can be reused by simply changing the sequence number 
+    notification = new Notification(notification.getType(), notifSource, 
+                                    notificationSequenceNumber.addAndGet(1L), 
+                                    notification.getTimeStamp(), 
+                                    notification.getMessage());
+    
+    sendNotification(notification);
+  }
+
+  /**
+   * Registers itself as a NotificationListener for Notifications sent from
+   * MBean with the ObjectName given as source.
+   * 
+   * @param source
+   *          source of notifications
+   * @throws InstanceNotFoundException
+   *           The MBean name provided does not match any of the registered
+   *           MBeans.
+   */
+  /*default*/void registerNotificationListener(ObjectName source) 
+    throws InstanceNotFoundException {
+    mBeanServer.addNotificationListener(source, this, null/*handback*/, source);
+  }
+
+  /**
+   * Unregisters itself as a NotificationListener for Notifications sent from
+   * MBean with the ObjectName given as source.
+   * 
+   * @param source source of notifications
+   * @throws InstanceNotFoundException
+   *           The MBean name provided does not match any of the registered
+   *           MBeans.
+   * @throws ListenerNotFoundException
+   *           The listener is not registered in the MBean.
+   */
+  /*default*/void unregisterNotificationListener(ObjectName source) 
+    throws InstanceNotFoundException, ListenerNotFoundException {
+    mBeanServer.removeNotificationListener(source, this);
+  }
+}

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/RMIRegistryService.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryService.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryService.java
new file mode 100644
index 0000000..3e0a385
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryService.java
@@ -0,0 +1,237 @@
+/*
+ * 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.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ * This MBean is an implementation of {@link RMIRegistryServiceMBean}.
+ * 
+ */
+public class RMIRegistryService implements RMIRegistryServiceMBean {
+  /* RMI Registry host */
+  private String host;
+  /* RMI Registry port */
+  private int port;
+  /* RMI Registry */
+  private Registry registry;
+  /* RMI Server Socket Factory */
+  private RMIServerSocketFactory ssf;
+  /* Whether RMI Registry is started & running */
+  private boolean isRunning;
+
+  /**
+   * Constructor to configure RMI Registry to start using default RMI Registry 
+   * port: {@link Registry#REGISTRY_PORT}
+   */
+  public RMIRegistryService() {
+    this(Registry.REGISTRY_PORT);
+  }
+
+  /**
+   * Constructor to configure RMI Registry to start using given RMI Registry
+   * port.
+   * 
+   * @param port
+   *          to run RMI Registry on
+   */
+  public RMIRegistryService(int port) {
+    setPort(port);
+  }
+
+  /**
+   * Constructor to configure RMI Registry to start using given RMI Registry
+   * port & host bind address.
+   * 
+   * @param host
+   *          to bind RMI Registry to
+   * @param port
+   *          to run RMI Registry on
+   * 
+   * @throws UnknownHostException
+   *           if IP Address can not be resolved for the given host string while
+   *           creating the RMIServerSocketFactory
+   */
+  public RMIRegistryService(String host, int port) throws UnknownHostException {
+    setPort(port);
+    setHost(host);
+    if (host != null && !host.trim().equals("")) {
+      ssf = new RMIServerSocketFactoryImpl(host);
+    }
+  }
+  
+  /**
+   * Returns the host on which rmiregistry listens for incoming connections
+   *
+   * @return the host on which rmiregistry listens for incoming connections
+   */
+  public String getHost() {
+    return host;
+  }
+
+  /**
+   * Sets the host on which rmiregistry listens for incoming connections
+   * 
+   * @param host
+   *          the host on which rmiregistry listens for incoming connections
+   */
+  protected void setHost(String host) {
+    if (isRunning()) { 
+      throw new IllegalStateException("RMIRegistryService is running, cannot change the host");
+    }
+    this.host = host;
+  }
+  
+  /**
+   * Returns the port on which rmiregistry listens for incoming connections
+   * 
+   * @return the port on which rmiregistry listens for incoming connections
+   */
+  public int getPort() {
+    return port;
+  }
+
+  /**
+   * Sets the port on which rmiregistry listens for incoming connections
+   * 
+   * @param port
+   *          the port on which rmiregistry listens for incoming connections
+   */
+  protected void setPort(int port) {
+    if (isRunning()) { 
+      throw new IllegalStateException("RMIRegistryService is running, cannot change the port");
+    }
+    this.port = port;
+  }
+
+  /**
+   * Starts this MBean: rmiregistry can now accept incoming calls
+   * 
+   * @see #stop
+   * @see #isRunning
+   */
+  public synchronized void start() throws RemoteException {
+    if (!isRunning()) {
+      if (ssf != null) {
+        registry = LocateRegistry.createRegistry(port, 
+                                                 null, //RMIClientSocketFactory 
+                                                 ssf); //RMIServerSocketFactory
+      } else {
+        registry = LocateRegistry.createRegistry(port);
+      }
+      
+      isRunning = true;
+    }
+  }
+
+  /**
+   * Returns whether this MBean has been started and not yet stopped.
+   * 
+   * @return whether this MBean has been started and not yet stopped.
+   * @see #start
+   */
+  public synchronized boolean isRunning() {
+    return isRunning;
+  }
+
+  /**
+   * Stops this MBean: rmiregistry cannot accept anymore incoming calls
+   * 
+   * @see #start
+   */
+  public synchronized void stop() throws NoSuchObjectException {
+    if (isRunning()) {
+      isRunning = !UnicastRemoteObject.unexportObject(registry, true);
+    }
+  }
+
+  /**
+   * Returns an array of the names bound in the rmiregistry
+   * 
+   * @return an array of the names bound in the rmiregistry
+   * @see java.rmi.registry.Registry#list()
+   */
+  public String[] list() throws RemoteException {
+    if (!isRunning()) {
+      throw new IllegalStateException("RMIRegistryService is not running");
+    }
+    return registry.list();
+  }
+
+  /**
+   * Removes the binding for the specified <code>name</code> in the rmiregistry
+   * 
+   * @see java.rmi.registry.Registry#unbind(String)
+   */
+  public void unbind(String name) throws RemoteException, NotBoundException {
+    if (!isRunning()) {
+      throw new IllegalStateException("RMIRegistryService is not running");
+    }
+    registry.unbind(name);
+  }
+}
+
+/**
+ * Custom implementation of the {@link RMIServerSocketFactory}
+ * 
+ */
+class RMIServerSocketFactoryImpl implements RMIServerSocketFactory {
+  /* IP address to use for creating ServerSocket */
+  private InetAddress bindAddress;
+
+  /**
+   * Constructs a RMIServerSocketFactory. The given rmiBindAddress is used to
+   * bind the ServerSockets created from this factory.
+   * 
+   * @param rmiBindAddress
+   *          String representation of the address to bind the ServerSockets to
+   * 
+   * @throws UnknownHostException
+   *           if IP Address can not be resolved for the given host string
+   */
+  /*default */RMIServerSocketFactoryImpl(String rmiBindAddress) 
+    throws UnknownHostException {
+    this.bindAddress = InetAddress.getByName(rmiBindAddress);
+  }
+
+  /**
+   * Create a server socket on the specified port (port 0 indicates an anonymous
+   * port).
+   * 
+   * @param port
+   *          the port number
+   * @return the server socket on the specified port
+   * @exception IOException
+   *              if an I/O error occurs during server socket creation
+   */
+  public ServerSocket createServerSocket(int port) throws IOException {
+    return new ServerSocket(port, 
+                            0/*backlog - for '0' internally uses the default*/, 
+                            bindAddress);
+  }
+}
+

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/RMIRegistryServiceMBean.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryServiceMBean.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryServiceMBean.java
new file mode 100644
index 0000000..5fbe62e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RMIRegistryServiceMBean.java
@@ -0,0 +1,84 @@
+/*
+ * 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.rmi.NoSuchObjectException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+
+/**
+ * This interface is similar to mx4j.tools.naming.NamingServiceMBean.
+ * Features that differ are:
+ * 1. This MBean interface additionally provides a way to specify the host that 
+ * the RMI Registry should get bound to.
+ * 2. Port property can not be changed once set.
+ * 
+ */
+public interface RMIRegistryServiceMBean {
+
+  /**
+   * Returns the host on which rmiregistry listens for incoming connections
+   *
+   * @return the host on which rmiregistry listens for incoming connections
+   */
+  public String getHost();
+
+  /**
+   * Returns the port on which rmiregistry listens for incoming connections
+   * 
+   * @return the port on which rmiregistry listens for incoming connections
+   */
+  public int getPort();
+
+  /**
+   * Returns whether this MBean has been started and not yet stopped.
+   * 
+   * @return whether this MBean has been started and not yet stopped.
+   * @see #start
+   */
+  public boolean isRunning();
+
+  /**
+   * Starts this MBean: rmiregistry can now accept incoming calls
+   * 
+   * @see #stop
+   * @see #isRunning
+   */
+  public void start() throws RemoteException;
+
+  /**
+   * Stops this MBean: rmiregistry cannot accept anymore incoming calls
+   * 
+   * @see #start
+   */
+  public void stop() throws NoSuchObjectException;
+
+  /**
+   * Returns an array of the names bound in the rmiregistry
+   * 
+   * @return an array of the names bound in the rmiregistry
+   * @see java.rmi.registry.Registry#list()
+   */
+  public String[] list() throws RemoteException;
+
+  /**
+   * Removes the binding for the specified <code>name</code> in the rmiregistry
+   * 
+   * @see java.rmi.registry.Registry#unbind(String)
+   */
+  public void unbind(String name) throws RemoteException, NotBoundException;
+}

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/RefreshNotificationType.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RefreshNotificationType.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RefreshNotificationType.java
new file mode 100755
index 0000000..d0cabfd
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/RefreshNotificationType.java
@@ -0,0 +1,130 @@
+/*
+ * 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.commons.lang.StringUtils;
+
+/**
+ * Type-safe definition for refresh notifications.
+ *
+ * @since GemFire     3.5
+ *
+ */
+public class RefreshNotificationType implements java.io.Serializable {
+  private static final long serialVersionUID = 4376763592395613794L;
+    
+  /** Notify StatisticResource to refresh statistics */
+  public static final RefreshNotificationType STATISTIC_RESOURCE_STATISTICS = 
+      new RefreshNotificationType(
+          "GemFire.Timer.StatisticResource.statistics.refresh", 
+          "refresh");
+
+  /** Notify SystemMember to refresh config */
+  public static final RefreshNotificationType SYSTEM_MEMBER_CONFIG = 
+      new RefreshNotificationType(
+          "GemFire.Timer.SystemMember.config.refresh", 
+          "refresh");
+
+  /** Notification type for the javax.management.Notification */
+  private final transient String type;
+  
+  /** Notification msg for the javax.management.Notification */
+  private final transient String msg;
+  
+  // The 4 declarations below are necessary for serialization
+  /** int used as ordinal to represent this Scope */
+  public final int ordinal = nextOrdinal++;
+
+  private static int nextOrdinal = 0;
+  
+  private static final RefreshNotificationType[] VALUES =
+    { STATISTIC_RESOURCE_STATISTICS, SYSTEM_MEMBER_CONFIG };
+
+  private Object readResolve() throws java.io.ObjectStreamException {
+    return VALUES[ordinal];  // Canonicalize
+  }
+  
+  /** Creates a new instance of RefreshNotificationType. */
+  private RefreshNotificationType(String type, String msg) {
+    this.type = type;
+    this.msg = msg;
+  }
+    
+  /** Return the RefreshNotificationType represented by specified ordinal */
+  public static RefreshNotificationType fromOrdinal(int ordinal) {
+    return VALUES[ordinal];
+  }
+
+	public String getType() {
+		return this.type;
+	}
+
+	public String getMessage() {
+		return this.msg;
+	}
+  
+  /** 
+   * Returns a string representation for this notification type.
+   *
+   * @return the type string for this Notification
+   */
+  @Override
+  public String toString() {
+      return this.type;
+  }
+
+	/**
+	 * Indicates whether some other object is "equal to" this one.
+	 *
+	 * @param  other  the reference object with which to compare.
+	 * @return true if this object is the same as the obj argument;
+	 *         false otherwise.
+	 */
+  @Override
+	public boolean equals(Object other) {
+		if (other == this) return true;
+		if (other == null) return false;
+		if (!(other instanceof RefreshNotificationType)) return  false;
+		final RefreshNotificationType that = (RefreshNotificationType) other;
+
+		if (!StringUtils.equals(this.type, that.type)) return false;
+		if (!StringUtils.equals(this.msg, that.msg)) return false;
+
+		return true;
+	}
+  
+	/**
+	 * Returns a hash code for the object. This method is supported for the
+	 * benefit of hashtables such as those provided by java.util.Hashtable.
+	 *
+	 * @return the integer 0 if description is null; otherwise a unique integer.
+	 */
+  @Override
+	public int hashCode() {
+		int result = 17;
+		final int mult = 37;
+
+		result = mult * result + 
+			(this.type == null ? 0 : this.type.hashCode());
+		result = mult * result + 
+			(this.msg == null ? 0 : this.msg.hashCode());
+
+		return result;
+	}
+  
+}
+

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/StatAlertNotification.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertNotification.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertNotification.java
new file mode 100644
index 0000000..ceb2787
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/jmx/impl/StatAlertNotification.java
@@ -0,0 +1,161 @@
+/*
+ * 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.io.DataInput;
+import java.io.DataOutput;
+import java.io.Serializable;
+import java.io.IOException;
+
+import org.apache.geode.DataSerializer;
+import org.apache.geode.DataSerializable;
+import org.apache.geode.internal.DataSerializableFixedID;
+import org.apache.geode.internal.Version;
+import org.apache.geode.internal.admin.StatAlert;
+import org.apache.geode.internal.admin.StatAlertDefinition;
+
+/**
+ * Notification to be sent to clients (e.g GFMon2.0 ). It incorporates
+ * 
+ * @see StatAlert raised and also Gemfire member id which raised the alert
+ * 
+ * 
+ * @since GemFire 5.7
+ */
+public class StatAlertNotification extends StatAlert implements Serializable, DataSerializable, DataSerializableFixedID {
+  private static final long serialVersionUID = -1634729103430107871L;
+  private String memberId;
+
+  public StatAlertNotification() {
+  }
+
+  public StatAlertNotification(StatAlert statAlert, String memberId) {
+    this.setDefinitionId(statAlert.getDefinitionId());
+    this.setValues(statAlert.getValues());
+    this.setTime(statAlert.getTime());
+    this.memberId = memberId;
+  }
+
+  public int getDSFID() {
+    return DataSerializableFixedID.STAT_ALERT_NOTIFICATION;
+  }
+
+  /**
+   * @return the memberId
+   */
+  public String getMemberId() {
+    return memberId;
+  }
+
+  /**
+   * 
+   * @param id
+   *                of gemfire member which raised the alert
+   */
+  public void setMemberId(String id) {
+    memberId = id;
+  }
+
+  /**
+   * @return String representation of this object
+   */
+  @Override
+  public String toString() {
+    StringBuffer buf = new StringBuffer();
+    buf.append("[");
+    for (int i = 0; i < getValues().length; i++) {
+      buf.append(getValues()[i] + ", ");
+    }
+    buf.append("]");
+    return Integer.valueOf(getDefinitionId()) + ":" + buf.toString();
+  }
+
+  /**
+   * The notification is something like this
+   * "For Member ID: <ID>
+   * [
+   *  <StatName> = <Value>
+   *  .. 
+   * ]"
+   * @param defn
+   *                {@link StatAlertDefinition}
+   * @return String representation of this object based on
+   *         {@link StatAlertDefinition}
+   */
+  public String toString(StatAlertDefinition defn) {
+    StringBuffer buf = new StringBuffer();
+    buf.append("For Member ID: ");
+    buf.append(this.memberId);
+    buf.append("\n");
+    buf.append("[ ");
+    for (int i = 0; i < getValues().length; i++) {
+      buf.append(defn.getStatisticInfo()[i].toString() + "=" + getValues()[i]
+          + "\n");
+    }
+    buf.append("]");
+    return getTime().toString() + ":" + buf.toString();
+  }
+
+  @Override
+  public boolean equals(Object object) {
+    if (object != null && !(object instanceof StatAlertNotification)) {
+      return false;
+    }
+
+    StatAlertNotification other = (StatAlertNotification)object;
+
+    int defId = getDefinitionId();
+
+    if (defId != -1 && defId == other.getDefinitionId() && memberId != null
+        && memberId.equals(other.getMemberId())) {
+      return true;
+    }
+
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return memberId.hashCode();
+  }
+
+  public void toData(DataOutput out) throws IOException {
+    // Do not modify StatAlert to allow 57 cacheservers to function with 57+ agent
+    // However, update of a new StatAlertDefn on 57 server from 57+ agent not covered with this
+    DataSerializer.writePrimitiveInt(this.getDefinitionId(), out);
+    DataSerializer.writeDate(this.getTime(), out);
+    DataSerializer.writeObjectArray(this.getValues(), out);
+
+    DataSerializer.writeString(this.memberId, out);
+  }
+
+  public void fromData(DataInput in)
+    throws IOException, ClassNotFoundException {
+    // Do not modify StatAlert to allow 57 cacheservers to function with 57+ agent
+    // However, update of a new StatAlertDefn on 57 server from 57+ agent not covered with this
+    this.setDefinitionId(DataSerializer.readPrimitiveInt(in));
+    this.setTime(DataSerializer.readDate(in));
+    this.setValues((Number[])DataSerializer.readObjectArray(in));
+
+    this.memberId = DataSerializer.readString(in);
+  }
+
+  @Override
+  public Version[] getSerializationVersions() {
+    return null;
+  }
+}