http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java
new file mode 100644
index 0000000..bf2d484
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.impl;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.DistributedLockService;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.internal.Assert;
+
+public class BackupDataStoreHelper {
+
+  public static String LOCK_SERVICE_NAME = 
BackupDataStoreHelper.class.getSimpleName();
+
+  private static String LOCK_NAME = LOCK_SERVICE_NAME + "_token";
+
+  private static Object LOCK_SYNC = new Object();
+
+  @SuppressWarnings("rawtypes")
+  public static BackupDataStoreResult backupAllMembers(DM dm, Set recipients, 
File targetDir,
+      File baselineDir) {
+    FlushToDiskRequest.send(dm, recipients);
+
+    boolean abort = true;
+    Map<DistributedMember, Set<PersistentID>> successfulMembers;
+    Map<DistributedMember, Set<PersistentID>> existingDataStores;
+    try {
+      existingDataStores = PrepareBackupRequest.send(dm, recipients);
+      abort = false;
+    } finally {
+      successfulMembers = FinishBackupRequest.send(dm, recipients, targetDir, 
baselineDir, abort);
+    }
+    return new BackupDataStoreResult(existingDataStores, successfulMembers);
+  }
+
+  private static DistributedLockService getLockService(DM dm) {
+    DistributedLockService dls = 
DistributedLockService.getServiceNamed(LOCK_SERVICE_NAME);
+    if (dls == null) {
+      synchronized (LOCK_SYNC) {
+        dls = DistributedLockService.getServiceNamed(LOCK_SERVICE_NAME);
+        if (dls == null) {
+          // Create the DistributedLockService
+          dls = DistributedLockService.create(LOCK_SERVICE_NAME, 
dm.getSystem());
+        }
+      }
+    }
+    Assert.assertTrue(dls != null);
+    return dls;
+  }
+
+  public static boolean obtainLock(DM dm) {
+    return getLockService(dm).lock(LOCK_NAME, 0, -1);
+  }
+
+  public static void releaseLock(DM dm) {
+    getLockService(dm).unlock(LOCK_NAME);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java
new file mode 100644
index 0000000..b61e5c8
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java
@@ -0,0 +1,48 @@
+/*
+ * 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.impl;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.DistributedMember;
+
+public class BackupDataStoreResult {
+
+  private Map<DistributedMember, Set<PersistentID>> existingDataStores;
+
+  private Map<DistributedMember, Set<PersistentID>> successfulMembers;
+
+  public BackupDataStoreResult(Map<DistributedMember, Set<PersistentID>> 
existingDataStores,
+      Map<DistributedMember, Set<PersistentID>> successfulMembers) {
+    this.existingDataStores = existingDataStores;
+    this.successfulMembers = successfulMembers;
+  }
+
+  public Map<DistributedMember, Set<PersistentID>> getExistingDataStores() {
+    return this.existingDataStores;
+  }
+
+  public Map<DistributedMember, Set<PersistentID>> getSuccessfulMembers() {
+    return this.successfulMembers;
+  }
+
+  public String toString() {
+    return new StringBuilder().append(getClass().getSimpleName()).append("[")
+        .append("existingDataStores=").append(this.existingDataStores)
+        .append("; 
successfulMembers=").append(this.successfulMembers).append("]").toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java
new file mode 100644
index 0000000..78736f7
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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.impl;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geode.internal.admin.api.BackupStatus;
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.DistributedMember;
+
+/**
+ * Holds the result of a backup operation.
+ * 
+ *
+ */
+public class BackupStatusImpl implements BackupStatus, Serializable {
+  private static final long serialVersionUID = 3704162840296921840L;
+
+  private Map<DistributedMember, Set<PersistentID>> backedUpDiskStores;
+  private Set<PersistentID> offlineDiskStores;
+
+  public BackupStatusImpl(Map<DistributedMember, Set<PersistentID>> 
backedUpDiskStores,
+      Set<PersistentID> offlineDiskStores) {
+    super();
+    this.backedUpDiskStores = backedUpDiskStores;
+    this.offlineDiskStores = offlineDiskStores;
+  }
+
+  public Map<DistributedMember, Set<PersistentID>> getBackedUpDiskStores() {
+    return backedUpDiskStores;
+  }
+
+  public Set<PersistentID> getOfflineDiskStores() {
+    return offlineDiskStores;
+  }
+
+  @Override
+  public String toString() {
+    return "BackupStatus[backedUpDiskStores=" + backedUpDiskStores + ", 
offlineDiskStores="
+        + offlineDiskStores + "]";
+  }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java
new file mode 100644
index 0000000..a6c2257
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java
@@ -0,0 +1,91 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.internal.admin.api.CacheHealthConfig;
+
+/**
+ * The implementation of <code>CacheHealthConfig</code>
+ *
+ *
+ * @since GemFire 3.5
+ */
+public abstract class CacheHealthConfigImpl extends MemberHealthConfigImpl
+    implements CacheHealthConfig {
+
+  /**
+   * The maximum number of milliseconds a <code>netSearch</code> operation can 
take before the cache
+   * member is considered to be unhealthy.
+   */
+  private long maxNetSearchTime = DEFAULT_MAX_NET_SEARCH_TIME;
+
+  /**
+   * The maximum mumber of milliseconds a cache <code>load</code> operation 
can take before the
+   * cache member is considered to be unhealthy.
+   */
+  private long maxLoadTime = DEFAULT_MAX_LOAD_TIME;
+
+  /** The minimum hit ratio of a healthy cache member. */
+  private double minHitRatio = DEFAULT_MIN_HIT_RATIO;
+
+  /**
+   * The maximum number of entries in the event delivery queue of a healthy 
cache member.
+   */
+  private long maxEventQueueSize = DEFAULT_MAX_EVENT_QUEUE_SIZE;
+
+  /////////////////////// Constructors ///////////////////////
+
+  /**
+   * Creates a new <code>CacheHealthConfigImpl</code> with the default 
configuration.
+   */
+  CacheHealthConfigImpl() {
+
+  }
+
+  ////////////////////// Instance Methods /////////////////////
+
+  public long getMaxNetSearchTime() {
+    return this.maxNetSearchTime;
+  }
+
+  public void setMaxNetSearchTime(long maxNetSearchTime) {
+    this.maxNetSearchTime = maxNetSearchTime;
+  }
+
+  public long getMaxLoadTime() {
+    return this.maxLoadTime;
+  }
+
+  public void setMaxLoadTime(long maxLoadTime) {
+    this.maxLoadTime = maxLoadTime;
+  }
+
+  public double getMinHitRatio() {
+    return this.minHitRatio;
+  }
+
+  public void setMinHitRatio(double minHitRatio) {
+    this.minHitRatio = minHitRatio;
+  }
+
+  public long getMaxEventQueueSize() {
+    return this.maxEventQueueSize;
+  }
+
+  public void setMaxEventQueueSize(long maxEventQueueSize) {
+    this.maxEventQueueSize = maxEventQueueSize;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java
new file mode 100644
index 0000000..8e30518
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java
@@ -0,0 +1,306 @@
+/*
+ * 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.impl;
+
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.CancelException;
+import org.apache.geode.internal.admin.api.CacheHealthConfig;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.internal.OSProcess;
+import org.apache.geode.internal.cache.CacheLifecycleListener;
+import org.apache.geode.internal.cache.CachePerfStats;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+
+/**
+ * Contains the logic for evaluating the health of a GemFire 
<code>Cache</code> instance according
+ * to the thresholds provided in a {@link CacheHealthConfig}.
+ *
+ *
+ * @since GemFire 3.5
+ */
+class CacheHealthEvaluator extends AbstractHealthEvaluator implements 
CacheLifecycleListener {
+
+  private static final Logger logger = LogService.getLogger();
+
+  /** The config from which we get the evaulation criteria */
+  private CacheHealthConfig config;
+
+  /** The description of the cache being evaluated */
+  private String description;
+
+  /**
+   * Statistics about the <code>Cache</code> instance. If no cache has been 
created in this VM, this
+   * field will be <code>null</code>
+   */
+  private CachePerfStats cacheStats;
+
+  /** The previous value of the netsearchTime stat (in nanoseconds) */
+  private long prevNetsearchTime;
+
+  /** The previous value of the netsearchedCompleted stat */
+  private long prevNetsearchesCompleted;
+
+  /** The previous value of the loadTime stat (in nanoseconds) */
+  private long prevLoadTime;
+
+  /** The previous value of the loadedCompleted stat */
+  private long prevLoadsCompleted;
+
+  /** The previous value of the gets stat */
+  private long prevGets;
+
+  ////////////////////// Constructors //////////////////////
+
+  /**
+   * Creates a new <code>CacheHealthEvaluator</code>
+   */
+  CacheHealthEvaluator(GemFireHealthConfig config, DM dm) {
+    super(config, dm);
+
+    this.config = config;
+    InternalDistributedSystem system = dm.getSystem();
+    GemFireCacheImpl cache;
+    try {
+      cache = (GemFireCacheImpl) CacheFactory.getInstance(system);
+
+    } catch (CancelException ex) {
+      // No cache in this VM
+      cache = null;
+    }
+
+    initialize(cache, dm);
+    GemFireCacheImpl.addCacheLifecycleListener(this);
+  }
+
+  //////////////////// Instance Methods ////////////////////
+
+  @Override
+  protected String getDescription() {
+    return this.description;
+  }
+
+  /**
+   * Initializes the state of this evaluator based on the given cache instance.
+   */
+  private void initialize(GemFireCacheImpl cache, DM dm) {
+    StringBuffer sb = new StringBuffer();
+    if (cache != null) {
+      this.cacheStats = cache.getCachePerfStats();
+
+      sb.append("Cache \"");
+      sb.append(cache.getName());
+      sb.append("\"");
+
+    } else {
+      sb.append("No Cache");
+    }
+
+    sb.append(" in member ");
+    sb.append(dm.getId());
+    int pid = OSProcess.getId();
+    if (pid != 0) {
+      sb.append(" with pid ");
+      sb.append(pid);
+    }
+    this.description = sb.toString();
+  }
+
+  public void cacheCreated(GemFireCacheImpl cache) {
+    InternalDistributedSystem system = (InternalDistributedSystem) 
cache.getDistributedSystem();
+    DM dm = system.getDistributionManager();
+    initialize(cache, dm);
+  }
+
+  /**
+   * Checks to make sure that the average <code>netSearch</code> time during 
the previous health
+   * check interval is less than the {@linkplain 
CacheHealthConfig#getMaxNetSearchTime threshold}.
+   * If not, the status is "okay" health.
+   *
+   * @see CachePerfStats#getNetsearchTime
+   * @see CachePerfStats#getNetsearchesCompleted
+   */
+  void checkNetSearchTime(List status) {
+    if (this.cacheStats == null || isFirstEvaluation() || 
this.cacheStats.isClosed()) {
+      return;
+    }
+
+    long deltaNetsearchTime = this.cacheStats.getNetsearchTime() - 
this.prevNetsearchTime;
+    long deltaNetsearchesCompleted =
+        this.cacheStats.getNetsearchesCompleted() - 
this.prevNetsearchesCompleted;
+
+    if (deltaNetsearchesCompleted != 0) {
+      long ratio = deltaNetsearchTime / deltaNetsearchesCompleted;
+      ratio /= 1000000;
+      long threshold = this.config.getMaxNetSearchTime();
+
+      if (ratio > threshold) {
+        String s =
+            
LocalizedStrings.CacheHealthEvaluator_THE_AVERAGE_DURATION_OF_A_CACHE_NETSEARCH_0_MS_EXCEEDS_THE_THRESHOLD_1_MS
+                .toLocalizedString(new Object[] {ratio, threshold});
+        status.add(okayHealth(s));
+      }
+    }
+  }
+
+  /**
+   * Checks to make sure that the average <code>load</code> time during the 
previous health check
+   * interval is less than the {@linkplain CacheHealthConfig#getMaxLoadTime 
threshold}. If not, the
+   * status is "okay" health.
+   *
+   * @see CachePerfStats#getLoadTime
+   * @see CachePerfStats#getLoadsCompleted
+   */
+  void checkLoadTime(List status) {
+    if (this.cacheStats == null || isFirstEvaluation() || 
this.cacheStats.isClosed()) {
+      return;
+    }
+
+    if (!isFirstEvaluation()) {
+      long deltaLoadTime = this.cacheStats.getLoadTime() - this.prevLoadTime;
+      long deltaLoadsCompleted = this.cacheStats.getLoadsCompleted() - 
this.prevLoadsCompleted;
+
+      if (logger.isDebugEnabled()) {
+        logger.debug("Completed {} loads in {} ms", deltaLoadsCompleted, 
(deltaLoadTime / 1000000));
+      }
+
+      if (deltaLoadsCompleted != 0) {
+        long ratio = deltaLoadTime / deltaLoadsCompleted;
+        ratio /= 1000000;
+        long threshold = this.config.getMaxLoadTime();
+
+        if (ratio > threshold) {
+          String s =
+              
LocalizedStrings.CacheHealthEvaluator_THE_AVERAGE_DURATION_OF_A_CACHE_LOAD_0_MS_EXCEEDS_THE_THRESHOLD_1_MS
+                  .toLocalizedString(new Object[] {ratio, threshold});
+          if (logger.isDebugEnabled()) {
+            logger.debug(s);
+          }
+          status.add(okayHealth(s));
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks to make sure that the cache hit ratio during the previous health 
check interval is less
+   * than the {@linkplain CacheHealthConfig#getMinHitRatio threshold}. If not, 
the status is "okay"
+   * health.
+   *
+   * <P>
+   *
+   * The following formula is used to compute the hit ratio:
+   *
+   * <PRE>
+   * hitRatio = (gets - (loadsCompleted + netsearchesCompleted)) / (gets)
+   * </PRE>
+   *
+   *
+   * @see CachePerfStats#getGets
+   * @see CachePerfStats#getLoadsCompleted
+   * @see CachePerfStats#getNetsearchesCompleted
+   */
+  void checkHitRatio(List status) {
+    if (this.cacheStats == null || isFirstEvaluation() || 
this.cacheStats.isClosed()) {
+      return;
+    }
+
+    long deltaGets = this.cacheStats.getGets() - this.prevGets;
+    if (deltaGets != 0) {
+      long deltaLoadsCompleted = this.cacheStats.getLoadsCompleted() - 
this.prevLoadsCompleted;
+      long deltaNetsearchesCompleted =
+          this.cacheStats.getNetsearchesCompleted() - 
this.prevNetsearchesCompleted;
+
+      double hits = (deltaGets - (deltaLoadsCompleted + 
deltaNetsearchesCompleted));
+      double hitRatio = hits / deltaGets;
+      double threshold = this.config.getMinHitRatio();
+      if (hitRatio < threshold) {
+        String s = "The hit ratio of this Cache (" + hitRatio + ") is below 
the threshold ("
+            + threshold + ")";
+        status.add(okayHealth(s));
+      }
+    }
+  }
+
+  /**
+   * Checks to make sure that the {@linkplain CachePerfStats#getEventQueueSize 
cache event queue
+   * size} does not exceed the {@linkplain 
CacheHealthConfig#getMaxEventQueueSize threshold}. If it
+   * does, the status is "okay" health.
+   */
+  void checkEventQueueSize(List status) {
+    if (this.cacheStats == null || isFirstEvaluation() || 
this.cacheStats.isClosed()) {
+      return;
+    }
+
+    long eventQueueSize = this.cacheStats.getEventQueueSize();
+    long threshold = this.config.getMaxEventQueueSize();
+    if (eventQueueSize > threshold) {
+      String s =
+          
LocalizedStrings.CacheHealthEvaluator_THE_SIZE_OF_THE_CACHE_EVENT_QUEUE_0_MS_EXCEEDS_THE_THRESHOLD_1_MS
+              .toLocalizedString(
+                  new Object[] {Long.valueOf(eventQueueSize), 
Long.valueOf(threshold)});
+      status.add(okayHealth(s));
+    }
+  }
+
+
+  /**
+   * Updates the previous values of statistics
+   */
+  private void updatePrevious() {
+    if (this.cacheStats != null && !this.cacheStats.isClosed()) {
+      this.prevLoadTime = this.cacheStats.getLoadTime();
+      this.prevLoadsCompleted = this.cacheStats.getLoadsCompleted();
+      this.prevNetsearchTime = this.cacheStats.getNetsearchTime();
+      this.prevNetsearchesCompleted = 
this.cacheStats.getNetsearchesCompleted();
+      this.prevGets = this.cacheStats.getGets();
+
+    } else {
+      this.prevLoadTime = 0L;
+      this.prevLoadsCompleted = 0L;
+      this.prevNetsearchTime = 0L;
+      this.prevNetsearchesCompleted = 0L;
+      this.prevGets = 0L;
+    }
+  }
+
+  @Override
+  protected void check(List status) {
+
+    checkNetSearchTime(status);
+    checkLoadTime(status);
+    checkHitRatio(status);
+    checkEventQueueSize(status);
+
+    updatePrevious();
+  }
+
+  @Override
+  public void close() {
+    GemFireCacheImpl.removeCacheLifecycleListener(this);
+  }
+
+  @Override
+  public void cacheClosed(GemFireCacheImpl cache) {
+    // do nothing
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java
new file mode 100644
index 0000000..1eadc79
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java
@@ -0,0 +1,133 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.internal.admin.api.CacheServerConfig;
+import org.apache.geode.internal.admin.api.CacheVmConfig;
+import org.apache.geode.internal.admin.GemFireVM;
+
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+
+/**
+ * An implementation of <code>CacheVmConfig</code>
+ *
+ * @since GemFire 4.0
+ */
+public class CacheServerConfigImpl extends ManagedEntityConfigImpl
+    implements CacheVmConfig, CacheServerConfig {
+
+  /**
+   * Declarative caching XML file that is used to initialize the Cache in the 
cache server.
+   */
+  private String cacheXMLFile;
+
+  /** Extra classpath for the cache server */
+  private String classpath;
+
+  /////////////////////// Constructors ///////////////////////
+
+  /**
+   * Creates a new <code>CacheServerConfigImpl</code> with the default 
configuration settings.
+   */
+  public CacheServerConfigImpl() {
+    this.cacheXMLFile = null;
+    this.classpath = null;
+  }
+
+  /**
+   * Creates a new <code>CacheServerConfigImpl</code> for a running cache 
server.
+   */
+  public CacheServerConfigImpl(GemFireVM vm) {
+    super(vm);
+
+    String name = CACHE_XML_FILE;
+    this.cacheXMLFile = vm.getConfig().getAttribute(name);
+    this.classpath = null;
+  }
+
+  /**
+   * Copy constructor
+   */
+  public CacheServerConfigImpl(CacheServerConfig other) {
+    super(other);
+    this.cacheXMLFile = other.getCacheXMLFile();
+    this.classpath = other.getClassPath();
+  }
+
+  /**
+   * Copy constructor
+   */
+  public CacheServerConfigImpl(CacheVmConfig other) {
+    super(other);
+    this.cacheXMLFile = other.getCacheXMLFile();
+    this.classpath = other.getClassPath();
+  }
+
+  ////////////////////// Instance Methods //////////////////////
+
+  public String getCacheXMLFile() {
+    return this.cacheXMLFile;
+  }
+
+  public void setCacheXMLFile(String cacheXMLFile) {
+    checkReadOnly();
+    this.cacheXMLFile = cacheXMLFile;
+    configChanged();
+  }
+
+  public String getClassPath() {
+    return this.classpath;
+  }
+
+  public void setClassPath(String classpath) {
+    checkReadOnly();
+    this.classpath = classpath;
+    configChanged();
+  }
+
+  @Override
+  public void validate() {
+    super.validate();
+
+    // Nothing to validate really. Cache.xml file could live on
+    // different file system.
+  }
+
+  /**
+   * Currently, listeners are not supported on the locator config.
+   */
+  @Override
+  protected void configChanged() {
+
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    return new CacheServerConfigImpl((CacheVmConfig) this);
+  }
+
+  @Override
+  public String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.append(super.toString());
+    sb.append(" cacheXMLFile=");
+    sb.append(this.getCacheXMLFile());
+    sb.append(" classPath=");
+    sb.append(this.getClassPath());
+
+    return sb.toString();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java
new file mode 100644
index 0000000..f5cb704
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java
@@ -0,0 +1,196 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.internal.admin.GemFireVM;
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.CacheServer;
+import org.apache.geode.internal.admin.api.CacheServerConfig;
+import org.apache.geode.internal.admin.api.CacheVm;
+import org.apache.geode.internal.admin.api.CacheVmConfig;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+import org.apache.geode.internal.admin.api.SystemMemberType;
+import org.apache.geode.internal.admin.remote.RemoteApplicationVM;
+
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+
+/**
+ * Implements the administrative interface to a cache server.
+ *
+ * @since GemFire 3.5
+ */
+public class CacheServerImpl extends ManagedSystemMemberImpl implements 
CacheVm, CacheServer {
+
+  /** How many new <code>CacheServer</code>s have been created? */
+  private static int newCacheServers = 0;
+
+  /////////////////////// Instance Fields ///////////////////////
+
+  /** The configuration object for this cache server */
+  private final CacheServerConfigImpl config;
+
+  ///////////////////////// Constructors ////////////////////////
+
+  /**
+   * Creates a new <code>CacheServerImpl</code> that represents a 
non-existsing (unstarted) cache
+   * server in a given distributed system.
+   */
+  public CacheServerImpl(AdminDistributedSystemImpl system, CacheVmConfig 
config)
+      throws AdminException {
+
+    super(system, config);
+
+    this.config = (CacheServerConfigImpl) config;
+    this.config.setManagedEntity(this);
+  }
+
+  /**
+   * Creates a new <code>CacheServerImpl</code> that represents an existing 
dedicated cache server
+   * in a given distributed system.
+   */
+  public CacheServerImpl(AdminDistributedSystemImpl system, GemFireVM vm) 
throws AdminException {
+
+    super(system, vm);
+    this.config = new CacheServerConfigImpl(vm);
+  }
+
+  ////////////////////// Instance Methods //////////////////////
+
+  @Override
+  public SystemMemberType getType() {
+    return SystemMemberType.CACHE_VM;
+  }
+
+  public String getNewId() {
+    synchronized (CacheServerImpl.class) {
+      return "CacheVm" + (++newCacheServers);
+    }
+  }
+
+  public void start() throws AdminException {
+    if (!needToStart()) {
+      return;
+    }
+
+    this.config.validate();
+    this.controller.start(this);
+    this.config.setManagedEntity(this);
+  }
+
+  public void stop() {
+    if (!needToStop()) {
+      return;
+    }
+
+    this.controller.stop(this);
+    // NOTE: DistributedSystem nodeLeft will then set this.manager to null
+    this.config.setManagedEntity(null);
+  }
+
+  public boolean isRunning() {
+    DM dm = ((AdminDistributedSystemImpl) 
getDistributedSystem()).getDistributionManager();
+    if (dm == null) {
+      try {
+        return this.controller.isRunning(this);
+      } catch (IllegalStateException e) {
+        return false;
+      }
+    }
+    return ((DistributionManager) dm).getDistributionManagerIdsIncludingAdmin()
+        .contains(getDistributedMember());
+  }
+
+  public CacheServerConfig getConfig() {
+    return this.config;
+  }
+
+  public CacheVmConfig getVmConfig() {
+    return this.config;
+  }
+
+  //////////////////////// Command execution ////////////////////////
+
+  public ManagedEntityConfig getEntityConfig() {
+    return this.getConfig();
+  }
+
+  public String getEntityType() {
+    // Fix bug 32564
+    return "Cache Vm";
+  }
+
+  public String getStartCommand() {
+    StringBuffer sb = new StringBuffer();
+    sb.append(this.controller.getProductExecutable(this, "cacheserver"));
+    sb.append(" start -dir=");
+    sb.append(this.getConfig().getWorkingDirectory());
+
+    String file = this.getConfig().getCacheXMLFile();
+    if (file != null && file.length() > 0) {
+      sb.append(" ");
+      sb.append(CACHE_XML_FILE);
+      sb.append("=");
+      sb.append(file);
+    }
+
+    String classpath = this.getConfig().getClassPath();
+    if (classpath != null && classpath.length() > 0) {
+      sb.append(" -classpath=");
+      sb.append(classpath);
+    }
+
+    appendConfiguration(sb);
+
+    return sb.toString().trim();
+  }
+
+  public String getStopCommand() {
+    StringBuffer sb = new StringBuffer();
+    sb.append(this.controller.getProductExecutable(this, "cacheserver"));
+    sb.append(" stop -dir=");
+    sb.append(this.getConfig().getWorkingDirectory());
+
+    return sb.toString().trim();
+  }
+
+  public String getIsRunningCommand() {
+    StringBuffer sb = new StringBuffer();
+    sb.append(this.controller.getProductExecutable(this, "cacheserver"));
+    sb.append(" status -dir=");
+    sb.append(this.getConfig().getWorkingDirectory());
+
+    return sb.toString().trim();
+  }
+
+  /**
+   * Find whether this server is primary for given client (durableClientId)
+   * 
+   * @param durableClientId - durable-id of the client
+   * @return true if the server is primary for given client
+   * 
+   * @since GemFire 5.6
+   */
+  public boolean isPrimaryForDurableClient(String durableClientId) {
+    RemoteApplicationVM vm = (RemoteApplicationVM) this.getGemFireVM();
+    boolean isPrimary = false;
+    if (vm != null) {
+      isPrimary = vm.isPrimaryForDurableClient(durableClientId);
+    }
+    return isPrimary;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java
new file mode 100755
index 0000000..9d94209
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java
@@ -0,0 +1,282 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.internal.admin.api.ConfigurationParameter;
+import org.apache.geode.internal.admin.api.UnmodifiableConfigurationException;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import java.io.File;
+// import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A single configuration parameter of a system member.
+ *
+ * @since GemFire 3.5
+ *
+ */
+public class ConfigurationParameterImpl implements ConfigurationParameter {
+
+  /** Identifying name of this configuration parameter */
+  protected String name;
+  /** Full description of this configuration parameter */
+  protected String description;
+  /** The current value */
+  protected Object value;
+  /** Class type of the value */
+  protected Class type;
+  /** True if this is modifiable; false if read-only */
+  protected boolean userModifiable;
+  /** List of listeners to notify when value changes */
+  private final List listeners = new ArrayList();
+
+  // -------------------------------------------------------------------------
+  // Constructor(s)
+  // -------------------------------------------------------------------------
+
+  /**
+   * Constructs new <code>ConfigurationParameterImpl</code>.
+   *
+   * @param name the name of this parameter which cannot change
+   * @param description full description to use
+   * @param value the value of this parameter
+   * @param type the class type of the value
+   * @param userModifiable true if this is modifiable; false if read-only
+   */
+  protected ConfigurationParameterImpl(String name, String description, Object 
value, Class type,
+      boolean userModifiable) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_NAME_MUST_BE_SPECIFIED
+              .toLocalizedString());
+    }
+
+    this.name = name;
+    setInternalState(description, value, type, userModifiable);
+  }
+
+  /**
+   * Constructs new <code>ConfigurationParameterImpl</code>.
+   *
+   * @param name the name of this parameter which cannot change
+   * @param value the value of this parameter
+   */
+  protected ConfigurationParameterImpl(String name, Object value) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_NAME_MUST_BE_SPECIFIED
+              .toLocalizedString());
+    }
+
+    this.name = name;
+    setInternalState(name, value, value.getClass(), true);
+  }
+
+  /** Constructor to allow serialization by subclass */
+  protected ConfigurationParameterImpl() {}
+
+  // -------------------------------------------------------------------------
+  // Attribute accessors and mutators
+  // -------------------------------------------------------------------------
+
+  public String getName() {
+    return this.name;
+  }
+
+  public String getDescription() {
+    return this.description;
+  }
+
+  public Object getValue() {
+    return this.value;
+  }
+
+  public String getValueAsString() {
+    if (isString()) {
+      return (String) this.value;
+    } else if (isInetAddress()) {
+      return InetAddressUtil.toString(this.value);
+    } else if (isFile()) {
+      return this.value.toString();
+    } else if (isOctal()) {
+      String strVal = Integer.toOctalString(((Integer) this.value).intValue());
+      if (!strVal.startsWith("0")) {
+        strVal = "0" + strVal;
+      }
+      return strVal;
+    } else if (isArray()) {
+      List list = Arrays.asList((Object[]) this.value);
+      return list.toString();
+    } else {
+      return this.value.toString();
+    }
+  }
+
+  public Class getValueType() {
+    return this.type;
+  }
+
+  public boolean isModifiable() {
+    return this.userModifiable;
+  }
+
+  public boolean isArray() {
+    return "manager-parameters".equals(this.name) || 
"manager-classpaths".equals(this.name);
+  }
+
+  public boolean isInetAddress() {
+    return java.net.InetAddress.class.isAssignableFrom(this.type);
+  }
+
+  public boolean isFile() {
+    return java.io.File.class.equals(this.type);
+  }
+
+  public boolean isOctal() {
+    return "shared-memory-permissions".equals(this.name);
+  }
+
+  public boolean isString() {
+    return java.lang.String.class.equals(this.type);
+  }
+
+  public void setValue(Object value) throws UnmodifiableConfigurationException 
{
+    if (!isModifiable()) {
+      throw new UnmodifiableConfigurationException(
+          
LocalizedStrings.ConfigurationParameterImpl_0_IS_NOT_A_MODIFIABLE_CONFIGURATION_PARAMETER
+              .toLocalizedString(getName()));
+    }
+    if (value == null) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE
+              .toLocalizedString(getName()));
+    }
+    if (!getValueType().equals(value.getClass())) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_TYPE_0_WITH_TYPE_1
+              .toLocalizedString(
+                  new Object[] {getValueType().getName(), 
value.getClass().getName()}));
+    }
+
+    if (value instanceof String && !isString()) {
+      // we need to check what the type should be and convert to it...
+      setValueFromString((String) value);
+    } else {
+      this.value = value;
+    }
+    fireConfigurationParameterValueChanged(this);
+  }
+
+  // -------------------------------------------------------------------------
+  // Operations for handling the registration of listeners
+  // Note: this is only for use within impl pkg and subclass pkgs
+  // -------------------------------------------------------------------------
+
+  /** Adds the listener for any changes to this configuration parameter. */
+  public void addConfigurationParameterListener(ConfigurationParameterListener 
listener) {
+    if (!this.listeners.contains(listener)) {
+      this.listeners.add(listener);
+    }
+  }
+
+  /** Removes the listener if it's currently registered. */
+  public void 
removeConfigurationParameterListener(ConfigurationParameterListener listener) {
+    if (this.listeners.contains(listener)) {
+      this.listeners.remove(listener);
+    }
+  }
+
+  // -------------------------------------------------------------------------
+  // Implementation methods
+  // -------------------------------------------------------------------------
+
+  protected void setValueFromString(String newValue) {
+    if (newValue == null) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE
+              .toLocalizedString(getName()));
+    }
+
+    if (isInetAddress()) {
+      this.value = InetAddressUtil.toInetAddress(newValue);
+    } else if (isFile()) {
+      this.value = new File(newValue);
+    } else if (isOctal()) {
+      if (!newValue.startsWith("0")) {
+        newValue = "0" + newValue;
+      }
+      this.value = Integer.valueOf(Integer.parseInt(newValue, 8));
+    } else if (isArray()) {
+      // parse it TODO
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_SETTING_ARRAY_VALUE_FROM_DELIMITED_STRING_IS_NOT_SUPPORTED
+              .toLocalizedString());
+    } else {
+      this.value = newValue;
+    }
+  }
+
+  /**
+   * Fires changed configuration parameter to registered listeners.
+   *
+   * @param parm the configuration parameter the changed
+   */
+  protected void fireConfigurationParameterValueChanged(ConfigurationParameter 
parm) {
+    ConfigurationParameterListener[] listeners = 
(ConfigurationParameterListener[]) this.listeners
+        .toArray(new ConfigurationParameterListener[0]);
+    for (int i = 0; i < listeners.length; i++) {
+      listeners[i].configurationParameterValueChanged(parm);
+    }
+  }
+
+  /**
+   * Sets the internal state of this configuration parameter.
+   *
+   * @param description full description to use
+   * @param value the value of this parameter
+   * @param type the class type of the value
+   * @param userModifiable true if this is modifiable; false if read-only
+   */
+  protected void setInternalState(String description, Object value, Class type,
+      boolean userModifiable) {
+    if (description == null || description.length() == 0) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_DESCRIPTION_MUST_BE_SPECIFIED
+              .toLocalizedString());
+    }
+    this.description = description;
+    this.type = type;
+    this.userModifiable = userModifiable;
+
+    if (value == null) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE
+              .toLocalizedString(getName()));
+    }
+
+    this.value = value;
+  }
+
+  @Override
+  public String toString() {
+    return this.name;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java
new file mode 100755
index 0000000..0b32df0
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.internal.admin.api.ConfigurationParameter;
+
+/**
+ * Listens to value changes of a {@link ConfigurationParameter}. This is for 
internal use only to
+ * allow a {@link SystemMemberImpl} to keep track of configuration changes 
made through
+ * {@link ConfigurationParameterImpl#setValue}.
+ *
+ * @since GemFire 3.5
+ *
+ */
+public interface ConfigurationParameterListener {
+  public void configurationParameterValueChanged(ConfigurationParameter parm);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java
new file mode 100755
index 0000000..aab92af
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java
@@ -0,0 +1,94 @@
+/*
+ * 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.impl;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LogMarker;
+
+/**
+ * This is a disabled implementation of ManagedEntityController for bug #47909.
+ *
+ * The old ManagedEntityController was a concrete class which has been renamed 
to
+ * ManagedEntityControllerImpl. The build.xml now skips building 
ManagedEntityControllerImpl. If
+ * ManagedEntityControllerImpl is not found in the classpath then the code uses
+ * DisabledManagedEntityController as a place holder.
+ *
+ */
+class DisabledManagedEntityController implements ManagedEntityController {
+
+  private static final Logger logger = LogService.getLogger();
+
+  private static final String EXCEPTION_MESSAGE =
+      "Local and remote OS command invocations are disabled for the Admin 
API.";
+
+  DisabledManagedEntityController() {}
+
+  @Override
+  public void start(InternalManagedEntity entity) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY, 
"DisabledManagedEntityController#start {}",
+          EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+
+  @Override
+  public void stop(InternalManagedEntity entity) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY, 
"DisabledManagedEntityController#stop {}",
+          EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+
+  @Override
+  public boolean isRunning(InternalManagedEntity entity) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY, 
"DisabledManagedEntityController#isRunning {}",
+          EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+
+  @Override
+  public String getLog(DistributionLocatorImpl locator) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY, 
"DisabledManagedEntityController#getLog {}",
+          EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+
+  @Override
+  public String buildSSLArguments(DistributedSystemConfig config) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY, 
"DisabledManagedEntityController#buildSSLArguments {}",
+          EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+
+  @Override
+  public String getProductExecutable(InternalManagedEntity entity, String 
executable) {
+    if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)) {
+      logger.warn(LogMarker.MANAGED_ENTITY,
+          "DisabledManagedEntityController#getProductExecutable {}", 
EXCEPTION_MESSAGE);
+    }
+    throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/b6c305f8/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java
 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java
new file mode 100755
index 0000000..0298c3e
--- /dev/null
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemConfigImpl.java
@@ -0,0 +1,1114 @@
+/*
+ * 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.impl;
+
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.internal.admin.api.AdminXmlException;
+import org.apache.geode.internal.admin.api.CacheServerConfig;
+import org.apache.geode.internal.admin.api.CacheVmConfig;
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.DistributionLocator;
+import org.apache.geode.internal.admin.api.DistributionLocatorConfig;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.InternalLogWriter;
+import org.apache.geode.internal.logging.LogConfig;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.LogWriterImpl;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+
+/**
+ * An implementation of the configuration object for an 
<code>AdminDistributedSystem</code>. After a
+ * config has been used to create an <code>AdminDistributedSystem</code> most 
of the configuration
+ * attributes cannot be changed. However, some operations (such as getting 
information about GemFire
+ * managers and distribution locators) are "passed through" to the
+ * <code>AdminDistributedSystem</code> associated with this configuration 
object.
+ *
+ * @since GemFire 3.5
+ */
+public class DistributedSystemConfigImpl implements DistributedSystemConfig {
+
+  private static final Logger logger = LogService.getLogger();
+
+  private String entityConfigXMLFile = DEFAULT_ENTITY_CONFIG_XML_FILE;
+  private String systemId = DEFAULT_SYSTEM_ID;
+  private String mcastAddress = DEFAULT_MCAST_ADDRESS;
+  private int mcastPort = DEFAULT_MCAST_PORT;
+  private int ackWaitThreshold = DEFAULT_ACK_WAIT_THRESHOLD;
+  private int ackSevereAlertThreshold = DEFAULT_ACK_SEVERE_ALERT_THRESHOLD;
+  private String locators = DEFAULT_LOCATORS;
+  private String bindAddress = DEFAULT_BIND_ADDRESS;
+  private String serverBindAddress = DEFAULT_BIND_ADDRESS;
+  private String remoteCommand = DEFAULT_REMOTE_COMMAND;
+  private boolean disableTcp = DEFAULT_DISABLE_TCP;
+  private boolean enableNetworkPartitionDetection = 
DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION;
+  private boolean disableAutoReconnect = DEFAULT_DISABLE_AUTO_RECONNECT;
+  private int memberTimeout = DEFAULT_MEMBER_TIMEOUT;
+  private String membershipPortRange = 
getMembershipPortRangeString(DEFAULT_MEMBERSHIP_PORT_RANGE);
+  private int tcpPort = DEFAULT_TCP_PORT;
+
+  private String logFile = DEFAULT_LOG_FILE;
+  private String logLevel = DEFAULT_LOG_LEVEL;
+  private int logDiskSpaceLimit = DEFAULT_LOG_DISK_SPACE_LIMIT;
+  private int logFileSizeLimit = DEFAULT_LOG_FILE_SIZE_LIMIT;
+  private int refreshInterval = DEFAULT_REFRESH_INTERVAL;
+  private Properties gfSecurityProperties = new Properties();
+
+  /**
+   * Listeners to notify when this DistributedSystemConfig changes
+   */
+  private Set listeners = new HashSet();
+
+  /**
+   * Configs for CacheServers that this system config is aware of
+   */
+  private Set cacheServerConfigs = new HashSet();
+
+  /**
+   * Configs for the managed distribution locators in the distributed system
+   */
+  private Set locatorConfigs = new HashSet();
+
+  /**
+   * The display name of this distributed system
+   */
+  private String systemName = DEFAULT_NAME;
+
+  /**
+   * The admin distributed system object that is configured by this config 
object.
+   *
+   * @since GemFire 4.0
+   */
+  private AdminDistributedSystemImpl system;
+
+  /**
+   * The GemFire log writer used by the distributed system
+   */
+  private InternalLogWriter logWriter;
+
+  /////////////////////// Static Methods ///////////////////////
+
+  /**
+   * Filters out all properties that are unique to the admin 
<code>DistributedSystemConfig</code>
+   * that are not present in the internal <code>DistributionConfig</code>.
+   *
+   * @since GemFire 4.0
+   */
+  private static Properties filterOutAdminProperties(Properties props) {
+
+    Properties props2 = new Properties();
+    for (Enumeration names = props.propertyNames(); names.hasMoreElements();) {
+      String name = (String) names.nextElement();
+      if (!(ENTITY_CONFIG_XML_FILE_NAME.equals(name) || 
REFRESH_INTERVAL_NAME.equals(name)
+          || REMOTE_COMMAND_NAME.equals(name))) {
+        String value = props.getProperty(name);
+        if ((name != null) && (value != null)) {
+          props2.setProperty(name, value);
+        }
+      }
+    }
+
+    return props2;
+  }
+
+  //////////////////////// Constructors ////////////////////////
+
+  /**
+   * Creates a new <code>DistributedSystemConfigImpl</code> based on the 
configuration stored in a
+   * <code>DistributedSystem</code>'s <code>DistributionConfig</code>.
+   */
+  public DistributedSystemConfigImpl(DistributionConfig distConfig, String 
remoteCommand) {
+    if (distConfig == null) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.DistributedSystemConfigImpl_DISTRIBUTIONCONFIG_MUST_NOT_BE_NULL
+              .toLocalizedString());
+    }
+
+    this.mcastAddress = InetAddressUtil.toString(distConfig.getMcastAddress());
+    this.mcastPort = distConfig.getMcastPort();
+    this.locators = distConfig.getLocators();
+    this.membershipPortRange = 
getMembershipPortRangeString(distConfig.getMembershipPortRange());
+
+    this.systemName = distConfig.getName();
+
+    this.sslEnabled = distConfig.getClusterSSLEnabled();
+    this.sslCiphers = distConfig.getClusterSSLCiphers();
+    this.sslProtocols = distConfig.getClusterSSLProtocols();
+    this.sslAuthenticationRequired = 
distConfig.getClusterSSLRequireAuthentication();
+
+    this.logFile = distConfig.getLogFile().getPath();
+    this.logLevel = LogWriterImpl.levelToString(distConfig.getLogLevel());
+    this.logDiskSpaceLimit = distConfig.getLogDiskSpaceLimit();
+    this.logFileSizeLimit = distConfig.getLogFileSizeLimit();
+
+    basicSetBindAddress(distConfig.getBindAddress());
+    this.tcpPort = distConfig.getTcpPort();
+
+    this.disableTcp = distConfig.getDisableTcp();
+
+    this.remoteCommand = remoteCommand;
+    this.serverBindAddress = distConfig.getServerBindAddress();
+    this.enableNetworkPartitionDetection = 
distConfig.getEnableNetworkPartitionDetection();
+    this.memberTimeout = distConfig.getMemberTimeout();
+    this.refreshInterval = DistributedSystemConfig.DEFAULT_REFRESH_INTERVAL;
+    this.gfSecurityProperties = (Properties) 
distConfig.getSSLProperties().clone();
+  }
+
+  /**
+   * Zero-argument constructor to be used only by subclasses.
+   *
+   * @since GemFire 4.0
+   */
+  protected DistributedSystemConfigImpl() {
+
+  }
+
+  /**
+   * Creates a new <code>DistributedSystemConifgImpl</code> whose 
configuration is specified by the
+   * given <code>Properties</code> object.
+   */
+  protected DistributedSystemConfigImpl(Properties props) {
+    this(props, false);
+  }
+
+  /**
+   * Creates a new <code>DistributedSystemConifgImpl</code> whose 
configuration is specified by the
+   * given <code>Properties</code> object.
+   * 
+   * @param props The configuration properties specified by the caller
+   * @param ignoreGemFirePropsFile whether to skip loading distributed system 
properties from
+   *        gemfire.properties file
+   * 
+   * @since GemFire 6.5
+   */
+  protected DistributedSystemConfigImpl(Properties props, boolean 
ignoreGemFirePropsFile) {
+    this(new DistributionConfigImpl(filterOutAdminProperties(props), 
ignoreGemFirePropsFile),
+        DEFAULT_REMOTE_COMMAND);
+    String remoteCommand = props.getProperty(REMOTE_COMMAND_NAME);
+    if (remoteCommand != null) {
+      this.remoteCommand = remoteCommand;
+    }
+
+    String entityConfigXMLFile = 
props.getProperty(ENTITY_CONFIG_XML_FILE_NAME);
+    if (entityConfigXMLFile != null) {
+      this.entityConfigXMLFile = entityConfigXMLFile;
+    }
+
+    String refreshInterval = props.getProperty(REFRESH_INTERVAL_NAME);
+    if (refreshInterval != null) {
+      try {
+        this.refreshInterval = Integer.parseInt(refreshInterval);
+      } catch (NumberFormatException nfEx) {
+        throw new IllegalArgumentException(
+            
LocalizedStrings.DistributedSystemConfigImpl_0_IS_NOT_A_VALID_INTEGER_1
+                .toLocalizedString(new Object[] {refreshInterval, 
REFRESH_INTERVAL_NAME}));
+      }
+    }
+  }
+
+  ////////////////////// Instance Methods //////////////////////
+
+  /**
+   * Returns the <code>LogWriterI18n</code> to be used when administering the 
distributed system.
+   * Returns null if nothing has been provided via 
<code>setInternalLogWriter</code>.
+   *
+   * @since GemFire 4.0
+   */
+  public InternalLogWriter getInternalLogWriter() {
+    // LOG: used only for sharing between IDS, AdminDSImpl and AgentImpl -- to 
prevent multiple
+    // banners, etc.
+    synchronized (this) {
+      return this.logWriter;
+    }
+  }
+
+  /**
+   * Sets the <code>LogWriterI18n</code> to be used when administering the 
distributed system.
+   */
+  public void setInternalLogWriter(InternalLogWriter logWriter) {
+    // LOG: used only for sharing between IDS, AdminDSImpl and AgentImpl -- to 
prevent multiple
+    // banners, etc.
+    synchronized (this) {
+      this.logWriter = logWriter;
+    }
+  }
+
+  public LogConfig createLogConfig() {
+    return new LogConfig() {
+      @Override
+      public int getLogLevel() {
+        return 
LogWriterImpl.levelNameToCode(DistributedSystemConfigImpl.this.getLogLevel());
+      }
+
+      @Override
+      public File getLogFile() {
+        return new File(DistributedSystemConfigImpl.this.getLogFile());
+      }
+
+      @Override
+      public int getLogFileSizeLimit() {
+        return DistributedSystemConfigImpl.this.getLogFileSizeLimit();
+      }
+
+      @Override
+      public int getLogDiskSpaceLimit() {
+        return DistributedSystemConfigImpl.this.getLogDiskSpaceLimit();
+      }
+
+      @Override
+      public String getName() {
+        return DistributedSystemConfigImpl.this.getSystemName();
+      }
+
+      @Override
+      public String toLoggerString() {
+        return DistributedSystemConfigImpl.this.toString();
+      }
+    };
+  }
+
+  /**
+   * Marks this config object as "read only". Attempts to modify a config 
object will result in a
+   * {@link IllegalStateException} being thrown.
+   *
+   * @since GemFire 4.0
+   */
+  void setDistributedSystem(AdminDistributedSystemImpl system) {
+    this.system = system;
+  }
+
+  /**
+   * Checks to see if this config object is "read only". If it is, then an
+   * {@link IllegalStateException} is thrown.
+   *
+   * @since GemFire 4.0
+   */
+  protected void checkReadOnly() {
+    if (this.system != null) {
+      throw new IllegalStateException(
+          
LocalizedStrings.DistributedSystemConfigImpl_A_DISTRIBUTEDSYSTEMCONFIG_OBJECT_CANNOT_BE_MODIFIED_AFTER_IT_HAS_BEEN_USED_TO_CREATE_AN_ADMINDISTRIBUTEDSYSTEM
+              .toLocalizedString());
+    }
+  }
+
+  public String getEntityConfigXMLFile() {
+    return this.entityConfigXMLFile;
+  }
+
+  public void setEntityConfigXMLFile(String xmlFile) {
+    checkReadOnly();
+    this.entityConfigXMLFile = xmlFile;
+    configChanged();
+  }
+
+  /**
+   * Parses the XML configuration file that describes managed entities.
+   *
+   * @throws AdminXmlException If a problem is encountered while parsing the 
XML file.
+   */
+  private void parseEntityConfigXMLFile() {
+    String fileName = this.entityConfigXMLFile;
+    File xmlFile = new File(fileName);
+    if (!xmlFile.exists()) {
+      if (DEFAULT_ENTITY_CONFIG_XML_FILE.equals(fileName)) {
+        // Default doesn't exist, no big deal
+        return;
+      } else {
+        throw new AdminXmlException(
+            
LocalizedStrings.DistributedSystemConfigImpl_ENTITY_CONFIGURATION_XML_FILE_0_DOES_NOT_EXIST
+                .toLocalizedString(fileName));
+      }
+    }
+
+    try {
+      InputStream is = new FileInputStream(xmlFile);
+      try {
+        ManagedEntityConfigXmlParser.parse(is, this);
+      } finally {
+        is.close();
+      }
+    } catch (IOException ex) {
+      throw new AdminXmlException(
+          
LocalizedStrings.DistributedSystemConfigImpl_WHILE_PARSING_0.toLocalizedString(fileName),
+          ex);
+    }
+  }
+
+  public String getSystemId() {
+    return this.systemId;
+  }
+
+  public void setSystemId(String systemId) {
+    checkReadOnly();
+    this.systemId = systemId;
+    configChanged();
+  }
+
+  /**
+   * Returns the multicast address for the system
+   */
+  public String getMcastAddress() {
+    return this.mcastAddress;
+  }
+
+  public void setMcastAddress(String mcastAddress) {
+    checkReadOnly();
+    this.mcastAddress = mcastAddress;
+    configChanged();
+  }
+
+  /**
+   * Returns the multicast port for the system
+   */
+  public int getMcastPort() {
+    return this.mcastPort;
+  }
+
+  public void setMcastPort(int mcastPort) {
+    checkReadOnly();
+    this.mcastPort = mcastPort;
+    configChanged();
+  }
+
+  public int getAckWaitThreshold() {
+    return this.ackWaitThreshold;
+  }
+
+  public void setAckWaitThreshold(int seconds) {
+    checkReadOnly();
+    this.ackWaitThreshold = seconds;
+    configChanged();
+  }
+
+  public int getAckSevereAlertThreshold() {
+    return this.ackSevereAlertThreshold;
+  }
+
+  public void setAckSevereAlertThreshold(int seconds) {
+    checkReadOnly();
+    this.ackSevereAlertThreshold = seconds;
+    configChanged();
+  }
+
+  /**
+   * Returns the comma-delimited list of locators for the system
+   */
+  public String getLocators() {
+    return this.locators;
+  }
+
+  public void setLocators(String locators) {
+    checkReadOnly();
+    if (locators == null) {
+      this.locators = "";
+    } else {
+      this.locators = locators;
+    }
+    configChanged();
+  }
+
+  /**
+   * Returns the value for membership-port-range
+   *
+   * @return the value for the Distributed System property 
membership-port-range
+   */
+  public String getMembershipPortRange() {
+    return this.membershipPortRange;
+  }
+
+  /**
+   * Sets the Distributed System property membership-port-range
+   *
+   * @param membershipPortRangeStr the value for membership-port-range given 
as two numbers
+   *        separated by a minus sign.
+   */
+  public void setMembershipPortRange(String membershipPortRangeStr) {
+    /*
+     * FIXME: Setting attributes in DistributedSystemConfig has no effect on 
DistributionConfig
+     * which is actually used for connection with DS. This is true for all 
such attributes. Should
+     * be addressed in the Admin Revamp if we want these 'set' calls to affect 
anything. Then we can
+     * use the validation code in DistributionConfigImpl code.
+     */
+    checkReadOnly();
+    if (membershipPortRangeStr == null) {
+      this.membershipPortRange = 
getMembershipPortRangeString(DEFAULT_MEMBERSHIP_PORT_RANGE);
+    } else {
+      try {
+        if (validateMembershipRange(membershipPortRangeStr)) {
+          this.membershipPortRange = membershipPortRangeStr;
+        } else {
+          throw new IllegalArgumentException(
+              
LocalizedStrings.DistributedSystemConfigImpl_INVALID_VALUE_FOR_MEMBERSHIP_PORT_RANGE
+                  .toLocalizedString(
+                      new Object[] {membershipPortRangeStr, 
MEMBERSHIP_PORT_RANGE_NAME}));
+        }
+      } catch (Exception e) {
+        if (logger.isDebugEnabled()) {
+          logger.debug(e.getMessage(), e);
+        }
+      }
+    }
+  }
+
+  public void setTcpPort(int port) {
+    checkReadOnly();
+    this.tcpPort = port;
+    configChanged();
+  }
+
+  public int getTcpPort() {
+    return this.tcpPort;
+  }
+
+  /**
+   * Validates the given string - which is expected in the format as two 
numbers separated by a
+   * minus sign - in to an integer array of length 2 with first element as 
lower end & second
+   * element as upper end of the range.
+   *
+   * @param membershipPortRange membership-port-range given as two numbers 
separated by a minus
+   *        sign.
+   * @return true if the membership-port-range string is valid, false otherwise
+   */
+  private boolean validateMembershipRange(String membershipPortRange) {
+    int[] range = null;
+    if (membershipPortRange != null && membershipPortRange.trim().length() > 
0) {
+      String[] splitted = membershipPortRange.split("-");
+      range = new int[2];
+      range[0] = Integer.parseInt(splitted[0].trim());
+      range[1] = Integer.parseInt(splitted[1].trim());
+      // NumberFormatException if any could be thrown
+
+      if (range[0] < 0 || range[0] >= range[1] || range[1] < 0 || range[1] > 
65535) {
+        range = null;
+      }
+    }
+    return range != null;
+  }
+
+  /**
+   * @return the String representation of membershipPortRange with lower & 
upper limits of the port
+   *         range separated by '-' e.g. 1-65535
+   */
+  private static String getMembershipPortRangeString(int[] 
membershipPortRange) {
+    String membershipPortRangeString = "";
+    if (membershipPortRange != null && membershipPortRange.length == 2) {
+      membershipPortRangeString = membershipPortRange[0] + "-" + 
membershipPortRange[1];
+    }
+
+    return membershipPortRangeString;
+  }
+
+  public String getBindAddress() {
+    return this.bindAddress;
+  }
+
+  public void setBindAddress(String bindAddress) {
+    checkReadOnly();
+    basicSetBindAddress(bindAddress);
+    configChanged();
+  }
+
+  public String getServerBindAddress() {
+    return this.serverBindAddress;
+  }
+
+  public void setServerBindAddress(String bindAddress) {
+    checkReadOnly();
+    basicSetServerBindAddress(bindAddress);
+    configChanged();
+  }
+
+  public boolean getDisableTcp() {
+    return this.disableTcp;
+  }
+
+  public void setDisableTcp(boolean flag) {
+    checkReadOnly();
+    disableTcp = flag;
+    configChanged();
+  }
+
+  public void setEnableNetworkPartitionDetection(boolean newValue) {
+    checkReadOnly();
+    this.enableNetworkPartitionDetection = newValue;
+    configChanged();
+  }
+
+  public boolean getEnableNetworkPartitionDetection() {
+    return this.enableNetworkPartitionDetection;
+  }
+
+  public void setDisableAutoReconnect(boolean newValue) {
+    checkReadOnly();
+    this.disableAutoReconnect = newValue;
+    configChanged();
+  }
+
+  public boolean getDisableAutoReconnect() {
+    return this.disableAutoReconnect;
+  }
+
+  public int getMemberTimeout() {
+    return this.memberTimeout;
+  }
+
+  public void setMemberTimeout(int value) {
+    checkReadOnly();
+    this.memberTimeout = value;
+    configChanged();
+  }
+
+  private void basicSetBindAddress(String bindAddress) {
+    if (!validateBindAddress(bindAddress)) {
+      throw new IllegalArgumentException(
+          LocalizedStrings.DistributedSystemConfigImpl_INVALID_BIND_ADDRESS_0
+              .toLocalizedString(bindAddress));
+    }
+    this.bindAddress = bindAddress;
+  }
+
+  private void basicSetServerBindAddress(String bindAddress) {
+    if (!validateBindAddress(bindAddress)) {
+      throw new IllegalArgumentException(
+          LocalizedStrings.DistributedSystemConfigImpl_INVALID_BIND_ADDRESS_0
+              .toLocalizedString(bindAddress));
+    }
+    this.serverBindAddress = bindAddress;
+  }
+
+  /**
+   * Returns the remote command setting to use for remote administration
+   */
+  public String getRemoteCommand() {
+    return this.remoteCommand;
+  }
+
+  /**
+   * Sets the remote command for this config object. This attribute may be 
modified after this
+   * config object has been used to create an admin distributed system.
+   */
+  public void setRemoteCommand(String remoteCommand) {
+    if (!ALLOW_ALL_REMOTE_COMMANDS) {
+      checkRemoteCommand(remoteCommand);
+    }
+    this.remoteCommand = remoteCommand;
+    configChanged();
+  }
+
+  private static final boolean ALLOW_ALL_REMOTE_COMMANDS =
+      Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + 
"admin.ALLOW_ALL_REMOTE_COMMANDS");
+  private static final String[] LEGAL_REMOTE_COMMANDS = {"rsh", "ssh"};
+  private static final String ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH =
+      "Allowed remote commands include \"rsh {HOST} {CMD}\" or \"ssh {HOST} 
{CMD}\" with valid rsh or ssh switches. Invalid: ";
+
+  private final void checkRemoteCommand(final String remoteCommand) {
+    if (remoteCommand == null || remoteCommand.isEmpty()) {
+      return;
+    }
+    final String command = remoteCommand.toLowerCase().trim();
+    if (!command.contains("{host}") || !command.contains("{cmd}")) {
+      throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + 
remoteCommand);
+    }
+
+    final StringTokenizer tokenizer = new StringTokenizer(command, " ");
+    final ArrayList<String> array = new ArrayList<String>();
+    for (int i = 0; tokenizer.hasMoreTokens(); i++) {
+      String string = tokenizer.nextToken();
+      if (i == 0) {
+        // first element must be rsh or ssh
+        boolean found = false;
+        for (int j = 0; j < LEGAL_REMOTE_COMMANDS.length; j++) {
+          if (string.contains(LEGAL_REMOTE_COMMANDS[j])) {
+            // verify command is at end of string
+            if (!(string.endsWith(LEGAL_REMOTE_COMMANDS[j])
+                || string.endsWith(LEGAL_REMOTE_COMMANDS[j] + ".exe"))) {
+              throw new 
IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand);
+            }
+            found = true;
+          }
+        }
+        if (!found) {
+          throw new IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH 
+ remoteCommand);
+        }
+      } else {
+        final boolean isSwitch = string.startsWith("-");
+        final boolean isHostOrCmd = string.equals("{host}") || 
string.equals("{cmd}");
+
+        // additional elements must be switches or values-for-switches or 
{host} or user@{host} or
+        // {cmd}
+        if (!isSwitch && !isHostOrCmd) {
+          final String previous =
+              (array == null || array.isEmpty()) ? null : 
array.get(array.size() - 1);
+          final boolean isValueForSwitch = previous != null && 
previous.startsWith("-");
+          final boolean isHostWithUser = string.contains("@") && 
string.endsWith("{host}");
+
+          if (!(isValueForSwitch || isHostWithUser)) {
+            throw new 
IllegalArgumentException(ILLEGAL_REMOTE_COMMAND_RSH_OR_SSH + remoteCommand);
+          }
+        }
+      }
+      array.add(string);
+    }
+  }
+
+  public String getSystemName() {
+    return this.systemName;
+  }
+
+  public void setSystemName(final String systemName) {
+    checkReadOnly();
+    this.systemName = systemName;
+    configChanged();
+  }
+
+  /**
+   * Returns an array of configurations for statically known CacheServers
+   *
+   * @since GemFire 4.0
+   */
+  public CacheServerConfig[] getCacheServerConfigs() {
+    return (CacheServerConfig[]) this.cacheServerConfigs
+        .toArray(new CacheServerConfig[this.cacheServerConfigs.size()]);
+  }
+
+  public CacheVmConfig[] getCacheVmConfigs() {
+    return (CacheVmConfig[]) this.cacheServerConfigs
+        .toArray(new CacheVmConfig[this.cacheServerConfigs.size()]);
+  }
+
+  /**
+   * Creates the configuration for a CacheServer
+   *
+   * @since GemFire 4.0
+   */
+  public CacheServerConfig createCacheServerConfig() {
+    CacheServerConfig config = new CacheServerConfigImpl();
+    addCacheServerConfig(config);
+    return config;
+  }
+
+  public CacheVmConfig createCacheVmConfig() {
+    return (CacheVmConfig) createCacheServerConfig();
+  }
+
+  /**
+   * Adds the configuration for a CacheServer
+   *
+   * @since GemFire 4.0
+   */
+  private void addCacheServerConfig(CacheServerConfig managerConfig) {
+    checkReadOnly();
+
+    if (managerConfig == null)
+      return;
+    for (Iterator iter = this.cacheServerConfigs.iterator(); iter.hasNext();) {
+      CacheServerConfigImpl impl = (CacheServerConfigImpl) iter.next();
+      if (impl.equals(managerConfig)) {
+        return;
+      }
+    }
+    this.cacheServerConfigs.add(managerConfig);
+    configChanged();
+  }
+
+  /**
+   * Removes the configuration for a CacheServer
+   *
+   * @since GemFire 4.0
+   */
+  public void removeCacheServerConfig(CacheServerConfig managerConfig) {
+    removeCacheVmConfig((CacheVmConfig) managerConfig);
+  }
+
+  public void removeCacheVmConfig(CacheVmConfig managerConfig) {
+    checkReadOnly();
+    this.cacheServerConfigs.remove(managerConfig);
+    configChanged();
+  }
+
+  /**
+   * Returns the configurations of all managed distribution locators
+   */
+  public DistributionLocatorConfig[] getDistributionLocatorConfigs() {
+    if (this.system != null) {
+      DistributionLocator[] locators = this.system.getDistributionLocators();
+      DistributionLocatorConfig[] configs = new 
DistributionLocatorConfig[locators.length];
+      for (int i = 0; i < locators.length; i++) {
+        configs[i] = locators[i].getConfig();
+      }
+      return configs;
+
+    } else {
+      Object[] array = new 
DistributionLocatorConfig[this.locatorConfigs.size()];
+      return (DistributionLocatorConfig[]) this.locatorConfigs.toArray(array);
+    }
+  }
+
+  /**
+   * Creates the configuration for a DistributionLocator
+   */
+  public DistributionLocatorConfig createDistributionLocatorConfig() {
+    checkReadOnly();
+    DistributionLocatorConfig config = new DistributionLocatorConfigImpl();
+    addDistributionLocatorConfig(config);
+    return config;
+  }
+
+  /**
+   * Adds the configuration for a DistributionLocator
+   */
+  private void addDistributionLocatorConfig(DistributionLocatorConfig config) {
+    checkReadOnly();
+    this.locatorConfigs.add(config);
+    configChanged();
+  }
+
+  /**
+   * Removes the configuration for a DistributionLocator
+   */
+  public void removeDistributionLocatorConfig(DistributionLocatorConfig 
config) {
+    checkReadOnly();
+    this.locatorConfigs.remove(config);
+    configChanged();
+  }
+
+  /**
+   * Validates the bind address. The address may be a host name or IP address, 
but it must not be
+   * empty and must be usable for creating an InetAddress. Cannot have a 
leading '/' (which
+   * InetAddress.toString() produces).
+   *
+   * @param bindAddress host name or IP address to validate
+   */
+  public static boolean validateBindAddress(String bindAddress) {
+    if (bindAddress == null || bindAddress.length() == 0)
+      return true;
+    if (InetAddressUtil.validateHost(bindAddress) == null)
+      return false;
+    return true;
+  }
+
+  public synchronized void configChanged() {
+    ConfigListener[] clients = null;
+    synchronized (this.listeners) {
+      clients = (ConfigListener[]) listeners.toArray(new 
ConfigListener[this.listeners.size()]);
+    }
+    for (int i = 0; i < clients.length; i++) {
+      try {
+        clients[i].configChanged(this);
+      } catch (Exception e) {
+        logger.warn(e.getMessage(), e);
+      }
+    }
+  }
+
+  /**
+   * Registers listener for notification of changes in this config.
+   */
+  public void addListener(ConfigListener listener) {
+    synchronized (this.listeners) {
+      this.listeners.add(listener);
+    }
+  }
+
+  /**
+   * Removes previously registered listener of this config.
+   */
+  public void removeListener(ConfigListener listener) {
+    synchronized (this.listeners) {
+      this.listeners.remove(listener);
+    }
+  }
+
+  // -------------------------------------------------------------------------
+  // SSL support...
+  // -------------------------------------------------------------------------
+  private boolean sslEnabled = DistributionConfig.DEFAULT_SSL_ENABLED;
+  private String sslProtocols = DistributionConfig.DEFAULT_SSL_PROTOCOLS;
+  private String sslCiphers = DistributionConfig.DEFAULT_SSL_CIPHERS;
+  private boolean sslAuthenticationRequired = 
DistributionConfig.DEFAULT_SSL_REQUIRE_AUTHENTICATION;
+  private Properties sslProperties = new Properties();
+
+  public boolean isSSLEnabled() {
+    return this.sslEnabled;
+  }
+
+  public void setSSLEnabled(boolean enabled) {
+    checkReadOnly();
+    this.sslEnabled = enabled;
+    configChanged();
+  }
+
+  public String getSSLProtocols() {
+    return this.sslProtocols;
+  }
+
+  public void setSSLProtocols(String protocols) {
+    checkReadOnly();
+    this.sslProtocols = protocols;
+    configChanged();
+  }
+
+  public String getSSLCiphers() {
+    return this.sslCiphers;
+  }
+
+  public void setSSLCiphers(String ciphers) {
+    checkReadOnly();
+    this.sslCiphers = ciphers;
+    configChanged();
+  }
+
+  public boolean isSSLAuthenticationRequired() {
+    return this.sslAuthenticationRequired;
+  }
+
+  public void setSSLAuthenticationRequired(boolean authRequired) {
+    checkReadOnly();
+    this.sslAuthenticationRequired = authRequired;
+    configChanged();
+  }
+
+  public Properties getSSLProperties() {
+    return this.sslProperties;
+  }
+
+  public void setSSLProperties(Properties sslProperties) {
+    checkReadOnly();
+    this.sslProperties = sslProperties;
+    if (this.sslProperties == null) {
+      this.sslProperties = new Properties();
+    }
+    configChanged();
+  }
+
+  public void addSSLProperty(String key, String value) {
+    checkReadOnly();
+    this.sslProperties.put(key, value);
+    configChanged();
+  }
+
+  public void removeSSLProperty(String key) {
+    checkReadOnly();
+    this.sslProperties.remove(key);
+    configChanged();
+  }
+
+  /**
+   * @return the gfSecurityProperties
+   * @since GemFire 6.6.3
+   */
+  public Properties getGfSecurityProperties() {
+    return gfSecurityProperties;
+  }
+
+  public String getLogFile() {
+    return this.logFile;
+  }
+
+  public void setLogFile(String logFile) {
+    checkReadOnly();
+    this.logFile = logFile;
+    configChanged();
+  }
+
+  public String getLogLevel() {
+    return this.logLevel;
+  }
+
+  public void setLogLevel(String logLevel) {
+    checkReadOnly();
+    this.logLevel = logLevel;
+    configChanged();
+  }
+
+  public int getLogDiskSpaceLimit() {
+    return this.logDiskSpaceLimit;
+  }
+
+  public void setLogDiskSpaceLimit(int limit) {
+    checkReadOnly();
+    this.logDiskSpaceLimit = limit;
+    configChanged();
+  }
+
+  public int getLogFileSizeLimit() {
+    return this.logFileSizeLimit;
+  }
+
+  public void setLogFileSizeLimit(int limit) {
+    checkReadOnly();
+    this.logFileSizeLimit = limit;
+    configChanged();
+  }
+
+  /**
+   * Returns the refreshInterval in seconds
+   */
+  public int getRefreshInterval() {
+    return this.refreshInterval;
+  }
+
+  /**
+   * Sets the refreshInterval in seconds
+   */
+  public void setRefreshInterval(int timeInSecs) {
+    checkReadOnly();
+    this.refreshInterval = timeInSecs;
+    configChanged();
+  }
+
+  /**
+   * Makes sure that the mcast port and locators are correct and consistent.
+   *
+   * @throws IllegalArgumentException If configuration is not valid
+   */
+  public void validate() {
+    if (this.getMcastPort() < MIN_MCAST_PORT || this.getMcastPort() > 
MAX_MCAST_PORT) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.DistributedSystemConfigImpl_MCASTPORT_MUST_BE_AN_INTEGER_INCLUSIVELY_BETWEEN_0_AND_1
+              .toLocalizedString(
+                  new Object[] {Integer.valueOf(MIN_MCAST_PORT), 
Integer.valueOf(MAX_MCAST_PORT)}));
+    }
+
+    // disabled in 5.1 - multicast and locators can be used together
+    // if (!DEFAULT_LOCATORS.equals(this.getLocators()) &&
+    // this.mcastPort > 0) {
+    // throw new IllegalArgumentException(
+    // "mcastPort must be zero when locators are specified");
+    // }
+
+    LogWriterImpl.levelNameToCode(this.logLevel);
+
+    if (this.logFileSizeLimit < MIN_LOG_FILE_SIZE_LIMIT
+        || this.logFileSizeLimit > MAX_LOG_FILE_SIZE_LIMIT) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.DistributedSystemConfigImpl_LOGFILESIZELIMIT_MUST_BE_AN_INTEGER_BETWEEN_0_AND_1
+              .toLocalizedString(new Object[] 
{Integer.valueOf(MIN_LOG_FILE_SIZE_LIMIT),
+                  Integer.valueOf(MAX_LOG_FILE_SIZE_LIMIT)}));
+    }
+
+    if (this.logDiskSpaceLimit < MIN_LOG_DISK_SPACE_LIMIT
+        || this.logDiskSpaceLimit > MAX_LOG_DISK_SPACE_LIMIT) {
+      throw new IllegalArgumentException(
+          
LocalizedStrings.DistributedSystemConfigImpl_LOGDISKSPACELIMIT_MUST_BE_AN_INTEGER_BETWEEN_0_AND_1
+              .toLocalizedString(new Object[] 
{Integer.valueOf(MIN_LOG_DISK_SPACE_LIMIT),
+                  Integer.valueOf(MAX_LOG_DISK_SPACE_LIMIT)}));
+    }
+
+    parseEntityConfigXMLFile();
+  }
+
+  /**
+   * Makes a deep copy of this config object.
+   */
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    DistributedSystemConfigImpl other = (DistributedSystemConfigImpl) 
super.clone();
+    other.system = null;
+    other.cacheServerConfigs = new HashSet();
+    other.locatorConfigs = new HashSet();
+
+    DistributionLocatorConfig[] myLocators = 
this.getDistributionLocatorConfigs();
+    for (int i = 0; i < myLocators.length; i++) {
+      DistributionLocatorConfig locator = myLocators[i];
+      other.addDistributionLocatorConfig((DistributionLocatorConfig) 
locator.clone());
+    }
+
+    CacheServerConfig[] myCacheServers = this.getCacheServerConfigs();
+    for (int i = 0; i < myCacheServers.length; i++) {
+      CacheServerConfig locator = myCacheServers[i];
+      other.addCacheServerConfig((CacheServerConfig) locator.clone());
+    }
+
+    return other;
+  }
+
+  @Override
+  public String toString() {
+    StringBuffer buf = new StringBuffer(1000);
+    String lf = System.getProperty("line.separator");
+    if (lf == null)
+      lf = ",";
+
+    buf.append("DistributedSystemConfig(");
+    buf.append(lf);
+    buf.append("  system-name=");
+    buf.append(String.valueOf(this.systemName));
+    buf.append(lf);
+    buf.append("  " + MCAST_ADDRESS + "=");
+    buf.append(String.valueOf(this.mcastAddress));
+    buf.append(lf);
+    buf.append("  " + MCAST_PORT + "=");
+    buf.append(String.valueOf(this.mcastPort));
+    buf.append(lf);
+    buf.append("  " + LOCATORS + "=");
+    buf.append(String.valueOf(this.locators));
+    buf.append(lf);
+    buf.append("  " + MEMBERSHIP_PORT_RANGE_NAME + "=");
+    buf.append(getMembershipPortRange());
+    buf.append(lf);
+    buf.append("  " + BIND_ADDRESS + "=");
+    buf.append(String.valueOf(this.bindAddress));
+    buf.append(lf);
+    buf.append("  " + TCP_PORT + "=" + this.tcpPort);
+    buf.append(lf);
+    buf.append("  " + DISABLE_TCP + "=");
+    buf.append(String.valueOf(this.disableTcp));
+    buf.append(lf);
+    buf.append("  " + DISABLE_AUTO_RECONNECT + "=");
+    buf.append(String.valueOf(this.disableAutoReconnect));
+    buf.append(lf);
+    buf.append("  " + REMOTE_COMMAND_NAME + "=");
+    buf.append(String.valueOf(this.remoteCommand));
+    buf.append(lf);
+    buf.append("  " + CLUSTER_SSL_ENABLED + "=");
+    buf.append(String.valueOf(this.sslEnabled));
+    buf.append(lf);
+    buf.append("  " + CLUSTER_SSL_CIPHERS + "=");
+    buf.append(String.valueOf(this.sslCiphers));
+    buf.append(lf);
+    buf.append("  " + CLUSTER_SSL_PROTOCOLS + "=");
+    buf.append(String.valueOf(this.sslProtocols));
+    buf.append(lf);
+    buf.append("  " + CLUSTER_SSL_REQUIRE_AUTHENTICATION + "=");
+    buf.append(String.valueOf(this.sslAuthenticationRequired));
+    buf.append(lf);
+    buf.append("  " + LOG_FILE_NAME + "=");
+    buf.append(String.valueOf(this.logFile));
+    buf.append(lf);
+    buf.append("  " + LOG_LEVEL_NAME + "=");
+    buf.append(String.valueOf(this.logLevel));
+    buf.append(lf);
+    buf.append("  " + LOG_DISK_SPACE_LIMIT_NAME + "=");
+    buf.append(String.valueOf(this.logDiskSpaceLimit));
+    buf.append(lf);
+    buf.append("  " + LOG_FILE_SIZE_LIMIT_NAME + "=");
+    buf.append(String.valueOf(this.logFileSizeLimit));
+    buf.append(lf);
+    buf.append("  " + REFRESH_INTERVAL_NAME + "=");
+    buf.append(String.valueOf(this.refreshInterval));
+    buf.append(")");
+    return buf.toString();
+  }
+}
+


Reply via email to