You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/10/26 22:49:34 UTC
[68/93] incubator-geode git commit: GEODE-288: move admin package to
internal
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java
new file mode 100644
index 0000000..d38d5cb
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthConfigImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.DistributedSystemHealthConfig;
+
+/**
+ * The implementation of <code>DistributedSystemHealthConfig</code>. Note that because it never
+ * leaves the management VM, it is not <code>Serializable</code> and is not part of the
+ * {@link GemFireHealthConfigImpl} class hierarchy.
+ *
+ *
+ * @since GemFire 3.5
+ */
+public class DistributedSystemHealthConfigImpl implements DistributedSystemHealthConfig {
+
+ /**
+ * The maximum number of application members that can unexceptedly leave a healthy the distributed
+ * system.
+ */
+ private long maxDepartedApplications = DEFAULT_MAX_DEPARTED_APPLICATIONS;
+
+ ////////////////////// Constructors //////////////////////
+
+ /**
+ * Creates a new <code>DistributedSystemHealthConfigImpl</code> with the default configuration.
+ */
+ protected DistributedSystemHealthConfigImpl() {
+
+ }
+
+ ///////////////////// Instance Methods /////////////////////
+
+ public long getMaxDepartedApplications() {
+ return this.maxDepartedApplications;
+ }
+
+ public void setMaxDepartedApplications(long maxDepartedApplications) {
+ this.maxDepartedApplications = maxDepartedApplications;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java
new file mode 100644
index 0000000..5087933
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthEvaluator.java
@@ -0,0 +1,167 @@
+/*
+ * 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.DistributedSystemHealthConfig;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.distributed.internal.MembershipListener;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Contains the logic for evaluating the health of an entire GemFire distributed system according to
+ * the thresholds provided in a {@link DistributedSystemHealthConfig}.
+ *
+ * <P>
+ *
+ * Note that unlike other evaluators, the <code>DistributedSystemHealthEvaluator</code> resides in
+ * the "administrator" VM and not in the member VMs. This is because there only needs to be one
+ * <code>DistributedSystemHealthEvaluator</code> per distributed system.
+ *
+ *
+ * @since GemFire 3.5
+ */
+class DistributedSystemHealthEvaluator extends AbstractHealthEvaluator
+ implements MembershipListener {
+
+ /** The config from which we get the evaluation criteria */
+ private DistributedSystemHealthConfig config;
+
+ /**
+ * The distribution manager with which this MembershipListener is registered
+ */
+ private DM dm;
+
+ /** The description of the distributed system being evaluated */
+ private String description;
+
+ /**
+ * The number of application members that have unexpectedly left since the previous evaluation
+ */
+ private int crashedApplications;
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>DistributedSystemHealthEvaluator</code>
+ */
+ DistributedSystemHealthEvaluator(DistributedSystemHealthConfig config, DM dm) {
+ super(null, dm);
+
+ this.config = config;
+ this.dm = dm;
+ this.dm.addMembershipListener(this);
+
+ StringBuffer sb = new StringBuffer();
+ sb.append("Distributed System ");
+
+ String desc = null;
+ if (dm instanceof DistributionManager) {
+ desc = ((DistributionManager) dm).getDistributionConfigDescription();
+ }
+
+ if (desc != null) {
+ sb.append(desc);
+
+ } else {
+ DistributionConfig dsc = dm.getSystem().getConfig();
+ String locators = dsc.getLocators();
+ if (locators == null || locators.equals("")) {
+ sb.append("using multicast ");
+ sb.append(dsc.getMcastAddress());
+ sb.append(":");
+ sb.append(dsc.getMcastPort());
+
+ } else {
+ sb.append("using locators ");
+ sb.append(locators);
+ }
+ }
+
+ this.description = sb.toString();
+ }
+
+ //////////////////// Instance Methods ////////////////////
+
+ @Override
+ protected String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Checks to make sure that the number of application members of the distributed system that have
+ * left unexpected since the last evaluation is less than the
+ * {@linkplain DistributedSystemHealthConfig#getMaxDepartedApplications threshold}. If not, the
+ * status is "poor" health.
+ */
+ void checkDepartedApplications(List status) {
+ synchronized (this) {
+ long threshold = this.config.getMaxDepartedApplications();
+ if (this.crashedApplications > threshold) {
+ String s =
+ LocalizedStrings.DistributedSystemHealth_THE_NUMBER_OF_APPLICATIONS_THAT_HAVE_LEFT_THE_DISTRIBUTED_SYSTEM_0_EXCEEDS_THE_THRESHOLD_1
+ .toLocalizedString(
+ new Object[] {Long.valueOf(this.crashedApplications), Long.valueOf(threshold)});
+ status.add(poorHealth(s));
+ }
+ this.crashedApplications = 0;
+ }
+ }
+
+ @Override
+ protected void check(List status) {
+ checkDepartedApplications(status);
+ }
+
+ @Override
+ void close() {
+ this.dm.removeMembershipListener(this);
+ }
+
+ public void memberJoined(InternalDistributedMember id) {
+
+ }
+
+ /**
+ * Keeps track of which members depart unexpectedly
+ */
+ public void memberDeparted(InternalDistributedMember id, boolean crashed) {
+ if (!crashed)
+ return;
+ synchronized (this) {
+ int kind = id.getVmKind();
+ switch (kind) {
+ case DistributionManager.LOCATOR_DM_TYPE:
+ case DistributionManager.NORMAL_DM_TYPE:
+ this.crashedApplications++;
+ break;
+ default:
+ break;
+ }
+ } // synchronized
+ }
+
+ public void quorumLost(Set<InternalDistributedMember> failures,
+ List<InternalDistributedMember> remaining) {}
+
+ public void memberSuspect(InternalDistributedMember id, InternalDistributedMember whoSuspected,
+ String reason) {}
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java
new file mode 100644
index 0000000..5a6e660
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributedSystemHealthMonitor.java
@@ -0,0 +1,461 @@
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.internal.admin.api.AdminException;
+import org.apache.geode.internal.admin.api.GemFireHealth;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.internal.admin.api.GemFireMemberStatus;
+import org.apache.geode.internal.admin.api.RegionSubRegionSnapshot;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionAttributes;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.Assert;
+import org.apache.geode.internal.Config;
+import org.apache.geode.internal.net.SocketCreator;
+import org.apache.geode.internal.admin.AdminBridgeServer;
+import org.apache.geode.internal.admin.CacheInfo;
+import org.apache.geode.internal.admin.DLockInfo;
+import org.apache.geode.internal.admin.GemFireVM;
+import org.apache.geode.internal.admin.GfManagerAgent;
+import org.apache.geode.internal.admin.HealthListener;
+import org.apache.geode.internal.admin.Stat;
+import org.apache.geode.internal.admin.StatAlertDefinition;
+import org.apache.geode.internal.admin.StatListener;
+import org.apache.geode.internal.admin.StatResource;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.LoggingThreadGroup;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+
+/**
+ * A thread that monitors the health of the distributed system. It is kind of like a
+ * {@link org.apache.geode.distributed.internal.HealthMonitorImpl}. In order to get it to place nice
+ * with the rest of the health monitoring APIs, this class pretends that it is a
+ * <code>GemFireVM</code>. Kind of hokey, but it beats a bunch of special-case code.
+ *
+ *
+ * @since GemFire 3.5
+ */
+class DistributedSystemHealthMonitor implements Runnable, GemFireVM {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /** Evaluates the health of the distributed system */
+ private DistributedSystemHealthEvaluator eval;
+
+ /** Notified when the health of the distributed system changes */
+ private GemFireHealthImpl healthImpl;
+
+ /** The number of seconds between health checks */
+ private int interval;
+
+ /** The thread in which the monitoring occurs */
+ private Thread thread;
+
+ /** Has this monitor been asked to stop? */
+ private volatile boolean stopRequested = false;
+
+ /** The health of the distributed system the last time we checked. */
+ private GemFireHealth.Health prevHealth = GemFireHealth.GOOD_HEALTH;
+
+ /**
+ * The most recent <code>OKAY_HEALTH</code> diagnoses of the GemFire system
+ */
+ private List okayDiagnoses;
+
+ /**
+ * The most recent <code>POOR_HEALTH</code> diagnoses of the GemFire system
+ */
+ private List poorDiagnoses;
+
+ ////////////////////// Constructors //////////////////////
+
+ /**
+ * Creates a new <code>DistributedSystemHealthMonitor</code> that evaluates the health of the
+ * distributed system against the given thresholds once every <code>interval</code> seconds.
+ *
+ * @param eval Used to evaluate the health of the distributed system
+ * @param healthImpl Receives callbacks when the health of the distributed system changes
+ * @param interval How often the health is checked
+ */
+ DistributedSystemHealthMonitor(DistributedSystemHealthEvaluator eval,
+ GemFireHealthImpl healthImpl, int interval) {
+ this.eval = eval;
+ this.healthImpl = healthImpl;
+ this.interval = interval;
+ this.okayDiagnoses = new ArrayList();
+ this.poorDiagnoses = new ArrayList();
+
+ ThreadGroup group = LoggingThreadGroup.createThreadGroup(
+ LocalizedStrings.DistributedSystemHealthMonitor_HEALTH_MONITORS.toLocalizedString(),
+ logger);
+ String name = LocalizedStrings.DistributedSystemHealthMonitor_HEALTH_MONITOR_FOR_0
+ .toLocalizedString(eval.getDescription());
+ this.thread = new Thread(group, this, name);
+ this.thread.setDaemon(true);
+ }
+
+ /**
+ * Does the work of monitoring the health of the distributed system.
+ */
+ public void run() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Monitoring health of {} every {} seconds", this.eval.getDescription(),
+ interval);
+ }
+
+ while (!this.stopRequested) {
+ SystemFailure.checkFailure();
+ try {
+ Thread.sleep(interval * 1000);
+ List status = new ArrayList();
+ eval.evaluate(status);
+
+ GemFireHealth.Health overallHealth = GemFireHealth.GOOD_HEALTH;
+ this.okayDiagnoses.clear();
+ this.poorDiagnoses.clear();
+
+ for (Iterator iter = status.iterator(); iter.hasNext();) {
+ AbstractHealthEvaluator.HealthStatus health =
+ (AbstractHealthEvaluator.HealthStatus) iter.next();
+ if (overallHealth == GemFireHealth.GOOD_HEALTH) {
+ if ((health.getHealthCode() != GemFireHealth.GOOD_HEALTH)) {
+ overallHealth = health.getHealthCode();
+ }
+
+ } else if (overallHealth == GemFireHealth.OKAY_HEALTH) {
+ if (health.getHealthCode() == GemFireHealth.POOR_HEALTH) {
+ overallHealth = GemFireHealth.POOR_HEALTH;
+ }
+ }
+
+ GemFireHealth.Health healthCode = health.getHealthCode();
+ if (healthCode == GemFireHealth.OKAY_HEALTH) {
+ this.okayDiagnoses.add(health.getDiagnosis());
+
+ } else if (healthCode == GemFireHealth.POOR_HEALTH) {
+ this.poorDiagnoses.add(health.getDiagnosis());
+ break;
+ }
+ }
+
+ if (overallHealth != prevHealth) {
+ healthImpl.healthChanged(this, overallHealth);
+ this.prevHealth = overallHealth;
+ }
+
+ } catch (InterruptedException ex) {
+ // We're all done
+ // No need to reset the interrupted flag, since we're going to exit.
+ break;
+ }
+ }
+
+ eval.close();
+ if (logger.isDebugEnabled()) {
+ logger.debug("Stopped checking for distributed system health");
+ }
+ }
+
+ /**
+ * Starts this <code>DistributedSystemHealthMonitor</code>
+ */
+ void start() {
+ this.thread.start();
+ }
+
+ /**
+ * Stops this <code>DistributedSystemHealthMonitor</code>
+ */
+ void stop() {
+ if (this.thread.isAlive()) {
+ this.stopRequested = true;
+ this.thread.interrupt();
+ this.healthImpl.nodeLeft(null, this);
+
+ try {
+ this.thread.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ logger.warn(
+ LocalizedMessage.create(
+ LocalizedStrings.DistributedSystemHealthMonitor_INTERRUPTED_WHILE_STOPPING_HEALTH_MONITOR_THREAD),
+ ex);
+ }
+ }
+ }
+
+ ////////////////////// GemFireVM Methods //////////////////////
+
+ public java.net.InetAddress getHost() {
+ try {
+ return SocketCreator.getLocalHost();
+
+ } catch (Exception ex) {
+ throw new org.apache.geode.InternalGemFireException(
+ LocalizedStrings.DistributedSystemHealthMonitor_COULD_NOT_GET_LOCALHOST
+ .toLocalizedString());
+ }
+ }
+
+ public String getName() {
+ // return getId().toString();
+ throw new UnsupportedOperationException("Not a real GemFireVM");
+ }
+
+ public java.io.File getWorkingDirectory() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public java.io.File getGemFireDir() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public java.util.Date getBirthDate() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public Properties getLicenseInfo() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public GemFireMemberStatus getSnapshot() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public RegionSubRegionSnapshot getRegionSnapshot() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public StatResource[] getStats(String statisticsTypeName) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public StatResource[] getAllStats() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public DLockInfo[] getDistributedLockInfo() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void addStatListener(StatListener observer, StatResource observedResource,
+ Stat observedStat) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void removeStatListener(StatListener observer) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void addHealthListener(HealthListener observer, GemFireHealthConfig cfg) {
+
+ }
+
+ public void removeHealthListener() {
+
+ }
+
+ public void resetHealthStatus() {
+ this.prevHealth = GemFireHealth.GOOD_HEALTH;
+ }
+
+ public String[] getHealthDiagnosis(GemFireHealth.Health healthCode) {
+ if (healthCode == GemFireHealth.GOOD_HEALTH) {
+ return new String[0];
+
+ } else if (healthCode == GemFireHealth.OKAY_HEALTH) {
+ String[] array = new String[this.okayDiagnoses.size()];
+ this.okayDiagnoses.toArray(array);
+ return array;
+
+ } else {
+ Assert.assertTrue(healthCode == GemFireHealth.POOR_HEALTH);
+ String[] array = new String[this.poorDiagnoses.size()];
+ this.poorDiagnoses.toArray(array);
+ return array;
+ }
+ }
+
+ public Config getConfig() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void setConfig(Config cfg) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public GfManagerAgent getManagerAgent() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public String[] getSystemLogs() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void setInspectionClasspath(String classpath) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public String getInspectionClasspath() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public Region[] getRootRegions() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public Region getRegion(CacheInfo c, String path) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public Region createVMRootRegion(CacheInfo c, String name, RegionAttributes attrs) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public Region createSubregion(CacheInfo c, String parentPath, String name,
+ RegionAttributes attrs) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void setCacheInspectionMode(int mode) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public int getCacheInspectionMode() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public void takeRegionSnapshot(String regionName, int snapshotId) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public InternalDistributedMember getId() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public CacheInfo getCacheInfo() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public String getVersionInfo() {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public CacheInfo setCacheLockTimeout(CacheInfo c, int v) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public CacheInfo setCacheLockLease(CacheInfo c, int v) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public CacheInfo setCacheSearchTimeout(CacheInfo c, int v) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public AdminBridgeServer addCacheServer(CacheInfo cache) throws AdminException {
+
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public AdminBridgeServer getBridgeInfo(CacheInfo cache, int id) throws AdminException {
+
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public AdminBridgeServer startBridgeServer(CacheInfo cache, AdminBridgeServer bridge)
+ throws AdminException {
+
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ public AdminBridgeServer stopBridgeServer(CacheInfo cache, AdminBridgeServer bridge)
+ throws AdminException {
+
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ /**
+ * This operation is not supported for this object. Will throw UnsupportedOperationException if
+ * invoked.
+ */
+ public void setAlertsManager(StatAlertDefinition[] alertDefs, long refreshInterval,
+ boolean setRemotely) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ /**
+ * This operation is not supported for this object. Will throw UnsupportedOperationException if
+ * invoked.
+ */
+ public void setRefreshInterval(long refreshInterval) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+
+ /**
+ * This operation is not supported for this object. Will throw UnsupportedOperationException if
+ * invoked.
+ */
+ public void updateAlertDefinitions(StatAlertDefinition[] alertDefs, int actionCode) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributedSystemHealthMonitor_NOT_A_REAL_GEMFIREVM.toLocalizedString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java
new file mode 100644
index 0000000..9dcd16f
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorConfigImpl.java
@@ -0,0 +1,187 @@
+/*
+ * 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.DistributionLocator;
+import org.apache.geode.internal.admin.api.DistributionLocatorConfig;
+import org.apache.geode.distributed.internal.tcpserver.*;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import java.net.InetAddress;
+import java.util.Properties;
+
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+
+/**
+ * Provides an implementation of <code>DistributionLocatorConfig</code>.
+ *
+ * @since GemFire 4.0
+ */
+public class DistributionLocatorConfigImpl extends ManagedEntityConfigImpl
+ implements DistributionLocatorConfig {
+
+ /** The minimum networking port (0) */
+ public static final int MIN_PORT = 0;
+
+ /** The maximum networking port (65535) */
+ public static final int MAX_PORT = 65535;
+
+ ////////////////////// Instance Fields //////////////////////
+
+ /** The port on which this locator listens */
+ private int port;
+
+ /** The address to bind to on a multi-homed host */
+ private String bindAddress;
+
+ /**
+ * The properties used to configure the DistributionLocator's DistributedSystem
+ */
+ private Properties dsProperties;
+
+ /** The DistributionLocator that was created with this config */
+ private DistributionLocator locator;
+
+ ////////////////////// Static Methods //////////////////////
+
+ /**
+ * Contacts a distribution locator on the given host and port and creates a
+ * <code>DistributionLocatorConfig</code> for it.
+ *
+ * @see TcpClient#getLocatorInfo
+ *
+ * @return <code>null</code> if the locator cannot be contacted
+ */
+ static DistributionLocatorConfig createConfigFor(String host, int port, InetAddress bindAddress) {
+ TcpClient client = new TcpClient();
+ String[] info = null;
+ if (bindAddress != null) {
+ info = client.getInfo(bindAddress, port);
+ } else {
+ info = client.getInfo(InetAddressUtil.toInetAddress(host), port);
+ }
+ if (info == null) {
+ return null;
+ }
+
+ DistributionLocatorConfigImpl config = new DistributionLocatorConfigImpl();
+ config.setHost(host);
+ config.setPort(port);
+ if (bindAddress != null) {
+ config.setBindAddress(bindAddress.getHostAddress());
+ }
+ config.setWorkingDirectory(info[0]);
+ config.setProductDirectory(info[1]);
+
+ return config;
+ }
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>DistributionLocatorConfigImpl</code> with the default settings.
+ */
+ public DistributionLocatorConfigImpl() {
+ this.port = 0;
+ this.bindAddress = null;
+ this.locator = null;
+ this.dsProperties = new java.util.Properties();
+ this.dsProperties.setProperty(MCAST_PORT, "0");
+ }
+
+ ///////////////////// Instance Methods /////////////////////
+
+ /**
+ * Sets the locator that was configured with this <Code>DistributionLocatorConfigImpl</code>.
+ */
+ void setLocator(DistributionLocator locator) {
+ this.locator = locator;
+ }
+
+ @Override
+ protected boolean isReadOnly() {
+ return this.locator != null && this.locator.isRunning();
+ }
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public void setPort(int port) {
+ checkReadOnly();
+ this.port = port;
+ configChanged();
+ }
+
+ public String getBindAddress() {
+ return this.bindAddress;
+ }
+
+ public void setBindAddress(String bindAddress) {
+ checkReadOnly();
+ this.bindAddress = bindAddress;
+ configChanged();
+ }
+
+ public void setDistributedSystemProperties(Properties props) {
+ this.dsProperties = props;
+ }
+
+ public Properties getDistributedSystemProperties() {
+ return this.dsProperties;
+ }
+
+ @Override
+ public void validate() {
+ super.validate();
+
+ if (port < MIN_PORT || port > MAX_PORT) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.DistributionLocatorConfigImpl_PORT_0_MUST_BE_AN_INTEGER_BETWEEN_1_AND_2
+ .toLocalizedString(new Object[] {Integer.valueOf(port), Integer.valueOf(MIN_PORT),
+ Integer.valueOf(MAX_PORT)}));
+ }
+
+ if (this.bindAddress != null && InetAddressUtil.validateHost(this.bindAddress) == null) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.DistributionLocatorConfigImpl_INVALID_HOST_0
+ .toLocalizedString(this.bindAddress));
+ }
+ }
+
+ /**
+ * Currently, listeners are not supported on the locator config.
+ */
+ @Override
+ protected void configChanged() {
+
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ DistributionLocatorConfigImpl clone = (DistributionLocatorConfigImpl) super.clone();
+ clone.locator = null;
+ return clone;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("DistributionLocatorConfig: host=").append(getHost());
+ sb.append(", bindAddress=").append(getBindAddress());
+ sb.append(", port=").append(getPort());
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java
new file mode 100755
index 0000000..ccfbcac
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DistributionLocatorImpl.java
@@ -0,0 +1,329 @@
+/*
+ * 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.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.DistributionLocator;
+import org.apache.geode.internal.admin.api.DistributionLocatorConfig;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.admin.remote.DistributionLocatorId;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+import org.apache.logging.log4j.Logger;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.*;
+
+/**
+ * Default administrative implementation of a DistributionLocator.
+ *
+ * @since GemFire 3.5
+ */
+public class DistributionLocatorImpl implements DistributionLocator, InternalManagedEntity {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /**
+ * How many new <code>DistributionLocator</code>s have been created?
+ */
+ private static int newLocators = 0;
+
+ //////////////////// Instance Fields ////////////////////
+
+ /**
+ * The configuration object for this locator
+ */
+ private final DistributionLocatorConfigImpl config;
+
+ /**
+ * The id of this distribution locator
+ */
+ private final String id;
+
+ /**
+ * Used to control the actual DistributionLocator service
+ */
+ private ManagedEntityController controller;
+
+ /**
+ * The system that this locator is a part of
+ */
+ private AdminDistributedSystemImpl system;
+
+ // -------------------------------------------------------------------------
+ // constructor(s)...
+ // -------------------------------------------------------------------------
+
+ /**
+ * Constructs new instance of <code>DistributionLocatorImpl</code> that is a member of the given
+ * distributed system.
+ */
+ public DistributionLocatorImpl(DistributionLocatorConfig config,
+ AdminDistributedSystemImpl system) {
+ this.config = (DistributionLocatorConfigImpl) config;
+ this.config.validate();
+ this.config.setManagedEntity(this);
+ this.id = getNewId();
+ this.controller = system.getEntityController();
+ this.system = system;
+ }
+
+ // -------------------------------------------------------------------------
+ // Attribute accessors/mutators...
+ // -------------------------------------------------------------------------
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getNewId() {
+ synchronized (DistributionLocatorImpl.class) {
+ return "Locator" + (++newLocators);
+ }
+ }
+
+ /**
+ * Returns the configuration object for this locator.
+ *
+ * @since GemFire 4.0
+ */
+ public DistributionLocatorConfig getConfig() {
+ return this.config;
+ }
+
+ public AdminDistributedSystem getDistributedSystem() {
+ return this.system;
+ }
+
+ /**
+ * Unfortunately, it doesn't make much sense to maintain the state of a locator. The admin API
+ * does not receive notification when the locator actually starts and stops. If we try to guess,
+ * we'll just end up with race conditions galore. So, we can't fix bug 32455 for locators.
+ */
+ public int setState(int state) {
+ throw new UnsupportedOperationException(
+ LocalizedStrings.DistributionLocatorImpl_CAN_NOT_SET_THE_STATE_OF_A_LOCATOR
+ .toLocalizedString());
+ }
+
+ // -------------------------------------------------------------------------
+ // Operations...
+ // -------------------------------------------------------------------------
+
+ /**
+ * Polls to determine whether or not this managed entity has started.
+ */
+ public boolean waitToStart(long timeout) throws InterruptedException {
+
+ if (Thread.interrupted())
+ throw new InterruptedException();
+
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < timeout) {
+ if (this.isRunning()) {
+ return true;
+
+ } else {
+ Thread.sleep(100);
+ }
+ }
+
+ logger.info(
+ LocalizedMessage.create(LocalizedStrings.DistributionLocatorImpl_DONE_WAITING_FOR_LOCATOR));
+ return this.isRunning();
+ }
+
+ /**
+ * Polls to determine whether or not this managed entity has stopped.
+ */
+ public boolean waitToStop(long timeout) throws InterruptedException {
+
+ if (Thread.interrupted())
+ throw new InterruptedException();
+
+ long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < timeout) {
+ if (!this.isRunning()) {
+ return true;
+
+ } else {
+ Thread.sleep(100);
+ }
+ }
+
+ return !this.isRunning();
+ }
+
+ public boolean isRunning() {
+ DM dm = ((AdminDistributedSystemImpl) getDistributedSystem()).getDistributionManager();
+ if (dm == null) {
+ try {
+ return this.controller.isRunning(this);
+ } catch (IllegalStateException e) {
+ return false;
+ }
+ }
+
+ String host = getConfig().getHost();
+ int port = getConfig().getPort();
+ String bindAddress = getConfig().getBindAddress();
+
+ boolean found = false;
+ Map<InternalDistributedMember, Collection<String>> hostedLocators = dm.getAllHostedLocators();
+ for (Iterator<InternalDistributedMember> memberIter =
+ hostedLocators.keySet().iterator(); memberIter.hasNext();) {
+ for (Iterator<String> locatorIter =
+ hostedLocators.get(memberIter.next()).iterator(); locatorIter.hasNext();) {
+ DistributionLocatorId locator = new DistributionLocatorId(locatorIter.next());
+ found = found || locator.getHost().getHostAddress().equals(host);
+ found = found || locator.getHost().getHostName().equals(host);
+ if (!found && !host.contains(".")) {
+ try {
+ InetAddress inetAddr = InetAddress.getByName(host);
+ found = locator.getHost().getHostName().equals(inetAddr.getHostName());
+ if (!found) {
+ found = locator.getHost().getHostAddress().equals(inetAddr.getHostAddress());
+ }
+ } catch (UnknownHostException e) {
+ // try config host as if it is an IP address instead of host name
+ }
+ }
+ if (locator.getBindAddress() != null && !locator.getBindAddress().isEmpty()
+ && bindAddress != null && !bindAddress.isEmpty()) {
+ found = found && locator.getBindAddress().equals(bindAddress);
+ }
+ found = found && locator.getPort() == port;
+ if (found) {
+ return true;
+ }
+ }
+ }
+ return found;
+ }
+
+ public void start() {
+ this.config.validate();
+ this.controller.start(this);
+ this.config.setLocator(this);
+ this.system.updateLocatorsString();
+ }
+
+ public void stop() {
+ this.controller.stop(this);
+ this.config.setLocator(null);
+ }
+
+ public String getLog() {
+ return this.controller.getLog(this);
+ }
+
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return a string representation of the object
+ */
+ @Override
+ public String toString() {
+ return "DistributionLocator " + getId();
+ }
+
+ //////////////////////// Command execution ////////////////////////
+
+ public ManagedEntityConfig getEntityConfig() {
+ return this.getConfig();
+ }
+
+ public String getEntityType() {
+ return "Locator";
+ }
+
+ public String getStartCommand() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.controller.getProductExecutable(this, "gemfire"));
+ sb.append(" start-locator -q -dir=");
+ sb.append(this.getConfig().getWorkingDirectory());
+ sb.append(" -port=");
+ sb.append(this.getConfig().getPort());
+ Properties props = config.getDistributedSystemProperties();
+ Enumeration en = props.propertyNames();
+ while (en.hasMoreElements()) {
+ String pn = (String) en.nextElement();
+ sb.append(" -D" + DistributionConfig.GEMFIRE_PREFIX + "" + pn + "=" + props.getProperty(pn));
+ }
+
+ String bindAddress = this.getConfig().getBindAddress();
+ if (bindAddress != null && bindAddress.length() > 0) {
+ sb.append(" -address=");
+ sb.append(this.getConfig().getBindAddress());
+ }
+ sb.append(" ");
+
+ String sslArgs = this.controller.buildSSLArguments(this.system.getConfig());
+ if (sslArgs != null) {
+ sb.append(sslArgs);
+ }
+
+ return sb.toString().trim();
+ }
+
+ public String getStopCommand() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.controller.getProductExecutable(this, "gemfire"));
+ sb.append(" stop-locator -q -dir=");
+ sb.append(this.getConfig().getWorkingDirectory());
+ sb.append(" -port=");
+ sb.append(this.getConfig().getPort());
+
+ String bindAddress = this.getConfig().getBindAddress();
+ if (bindAddress != null && bindAddress.length() > 0) {
+ sb.append(" -address=");
+ sb.append(this.getConfig().getBindAddress());
+ }
+ sb.append(" ");
+
+ String sslArgs = this.controller.buildSSLArguments(this.system.getConfig());
+ if (sslArgs != null) {
+ sb.append(sslArgs);
+ }
+
+ return sb.toString().trim();
+ }
+
+ public String getIsRunningCommand() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.controller.getProductExecutable(this, "gemfire"));
+ sb.append(" status-locator -dir=");
+ sb.append(this.getConfig().getWorkingDirectory());
+
+ return sb.toString().trim();
+ }
+
+ public String getLogCommand() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.controller.getProductExecutable(this, "gemfire"));
+ sb.append(" tail-locator-log -dir=");
+ sb.append(this.getConfig().getWorkingDirectory());
+
+ return sb.toString().trim();
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/EnabledManagedEntityController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/EnabledManagedEntityController.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/EnabledManagedEntityController.java
new file mode 100755
index 0000000..554d160
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/EnabledManagedEntityController.java
@@ -0,0 +1,385 @@
+/*
+ * 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.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.ManagedEntity;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.ProcessOutputReader;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.LoggingThreadGroup;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+import org.apache.logging.log4j.Logger;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Properties;
+
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+
+/**
+ * Implements the actual administration (starting, stopping, etc.) of GemFire
+ * {@link ManagedEntity}s. It {@link Runtime#exec(java.lang.String) executes} commands to administer
+ * the entities based on information provided by the {@link InternalManagedEntity} object. Note that
+ * it does not use <code>SystemAdmin</code> to manage "local" entities; it always execs the scripts.
+ *
+ * <P>
+ *
+ * This class is a refactoring of <code>Systemcontroller</code>, <code>RemoteCommand</code>, and
+ * <code>LocatorRemoteCommand</code>.
+ *
+ * @since GemFire 4.0
+ */
+class EnabledManagedEntityController implements ManagedEntityController {
+ private static final Logger logger = LogService.getLogger();
+
+ // /** A lock to ensure that only entity is managed at a time. See bug
+ // * 31374. */
+ // private static Object startStopLock = new Object();
+
+ /** Known strings found in output indicating error. */
+ private static final String[] ERROR_OUTPUTS = new String[] {"No such file or directory",
+ "The system cannot find the file specified.", "Access is denied.", "cannot open", "ERROR"};
+
+ /** Token in command prefix to be replaced with actual HOST */
+ private static final String HOST = "{HOST}";
+
+ /** Token in command prefix to be replaced with actual execution CMD */
+ private static final String CMD = "{CMD}";
+
+ ////////////////////// Instance Fields //////////////////////
+
+ /**
+ * The thread group in which threads launched by this system controller reside.
+ */
+ private final ThreadGroup threadGroup;
+
+ /** System to which the managed entities belong */
+ private final AdminDistributedSystem system;
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>ManagedEntityController</code> for entities in the given distributed
+ * system.
+ */
+ EnabledManagedEntityController(AdminDistributedSystem system) {
+ this.system = system;
+ this.threadGroup =
+ LoggingThreadGroup.createThreadGroup("ManagedEntityController threads", logger);
+ }
+
+ ///////////////////// Instance Methods /////////////////////
+
+ /**
+ * Returns <code>true</code> if the <code>output</code> string contains a known error message.
+ */
+ private boolean outputIsError(String output) {
+ if (output == null)
+ return false;
+ boolean error = false;
+ for (int i = 0; i < ERROR_OUTPUTS.length; i++) {
+ error = output.indexOf(ERROR_OUTPUTS[i]) > -1;
+ if (error)
+ return error;
+ }
+ return error;
+ }
+
+ /**
+ * Executes a command using {@link Runtime#exec(java.lang.String)}.
+ *
+ * @param command The full command to remotely execute
+ *
+ * @return Output from the command that was executed or <code>null</code> if the executing the
+ * command failed.
+ */
+ protected String execute(String command, InternalManagedEntity entity) {
+ /*
+ * TODO: this is getting ugly... clients of this method really need to have the ability to do
+ * their own parsing/checking of 'output'
+ */
+ if (command == null || command.length() == 0) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.ManagedEntityController_EXECUTION_COMMAND_IS_EMPTY.toLocalizedString());
+ }
+
+ File workingDir = new File(entity.getEntityConfig().getWorkingDirectory());
+ logger.info(LocalizedMessage.create(
+ LocalizedStrings.ManagedEntityController_EXECUTING_REMOTE_COMMAND_0_IN_DIRECTORY_1,
+ new Object[] {command, workingDir}));
+ Process p = null;
+ try {
+ p = Runtime.getRuntime().exec(command, null /* env */, workingDir);
+
+ } catch (java.io.IOException e) {
+ logger.fatal(LocalizedMessage
+ .create(LocalizedStrings.ManagedEntityController_WHILE_EXECUTING_0, command), e);
+ return null;
+ }
+
+ final ProcessOutputReader pos = new ProcessOutputReader(p);
+ int retCode = pos.getExitCode();
+ final String output = pos.getOutput();
+ logger.info(
+ LocalizedMessage.create(LocalizedStrings.ManagedEntityController_RESULT_OF_EXECUTING_0_IS_1,
+ new Object[] {command, Integer.valueOf(retCode)}));
+ logger.info(LocalizedMessage.create(LocalizedStrings.ManagedEntityController_OUTPUT_OF_0_IS_1,
+ new Object[] {command, output}));
+
+ if (retCode != 0 || outputIsError(output)) {
+ logger.warn(LocalizedMessage
+ .create(LocalizedStrings.ManagedEntityController_REMOTE_EXECUTION_OF_0_FAILED, command));
+ return null;
+ }
+
+ return output;
+ }
+
+ /** Returns true if the path ends with a path separator. */
+ private boolean endsWithSeparator(String path) {
+ return path.endsWith("/") || path.endsWith("\\");
+ }
+
+ /** Translates the path between Windows and UNIX. */
+ private String getOSPath(String path) {
+ if (pathIsWindows(path)) {
+ return path.replace('/', '\\');
+ } else {
+ return path.replace('\\', '/');
+ }
+ }
+
+ // /** Returns true if the path is on Windows. */
+ // private boolean pathIsWindows(File path) {
+ // return pathIsWindows(path.toString());
+ // }
+
+ /** Returns true if the path is on Windows. */
+ private boolean pathIsWindows(String path) {
+ if (path != null && path.length() > 1) {
+ return (Character.isLetter(path.charAt(0)) && path.charAt(1) == ':')
+ || (path.startsWith("//") || path.startsWith("\\\\"));
+ }
+ return false;
+ }
+
+ /**
+ * If the managed entity resides on a remote host, then <code>command</code> is munged to take the
+ * remote command into account.
+ *
+ * @throws IllegalStateException If a remote command is required, but one has not been specified.
+ */
+ private String arrangeRemoteCommand(InternalManagedEntity entity, String cmd) {
+
+ String host = entity.getEntityConfig().getHost();
+ if (InetAddressUtil.isLocalHost(host)) {
+ // No arranging necessary
+ return cmd;
+ }
+
+ String prefix = entity.getEntityConfig().getRemoteCommand();
+ if (prefix == null || prefix.length() <= 0) {
+ prefix = entity.getDistributedSystem().getRemoteCommand();
+ }
+
+ if (prefix == null || prefix.length() <= 0) {
+ throw new IllegalStateException(
+ LocalizedStrings.ManagedEntityController_A_REMOTE_COMMAND_MUST_BE_SPECIFIED_TO_OPERATE_ON_A_MANAGED_ENTITY_ON_HOST_0
+ .toLocalizedString(host));
+ }
+
+ int hostIdx = prefix.indexOf(HOST);
+ int cmdIdx = prefix.indexOf(CMD);
+ if (hostIdx == -1 && cmdIdx == -1) {
+ return prefix + " " + host + " " + cmd;
+ }
+
+ if (hostIdx >= 0) {
+ String start = prefix.substring(0, hostIdx);
+ String end = null;
+ if (hostIdx + HOST.length() >= prefix.length()) {
+ end = "";
+ } else {
+ end = prefix.substring(hostIdx + HOST.length());
+ }
+ prefix = start + host + end;
+ cmdIdx = prefix.indexOf(CMD); // recalculate;
+ }
+
+ if (cmdIdx >= 0) {
+ String start = prefix.substring(0, cmdIdx);
+ String end = null;
+ if (cmdIdx + CMD.length() >= prefix.length()) {
+ end = "";
+ } else {
+ end = prefix.substring(cmdIdx + CMD.length());
+ }
+ prefix = start + cmd + end;
+ }
+ return prefix;
+ }
+
+ /**
+ * Returns the full path to the executable in <code>$GEMFIRE/bin</code> taking into account the
+ * {@linkplain ManagedEntityConfig#getProductDirectory product directory} and the platform's file
+ * separator.
+ *
+ * <P>
+ *
+ * Note: we should probably do a better job of determine whether or not the machine on which the
+ * entity runs is Windows or Linux.
+ *
+ * @param executable The name of the executable that resides in <code>$GEMFIRE/bin</code>.
+ */
+ public String getProductExecutable(InternalManagedEntity entity, String executable) {
+ String productDirectory = entity.getEntityConfig().getProductDirectory();
+ String path = null;
+ File productDir = new File(productDirectory);
+ // if (productDir != null) (cannot be null)
+ {
+ path = productDir.getPath();
+ if (!endsWithSeparator(path)) {
+ path += File.separator;
+ }
+ path += "bin" + File.separator;
+ }
+ // else {
+ // path = "";
+ // }
+
+ String bat = "";
+ if (pathIsWindows(path)) {
+ bat = ".bat";
+ }
+ return getOSPath(path) + executable + bat;
+ }
+
+ /**
+ * Builds optional SSL command-line arguments. Returns null if SSL is not enabled for the
+ * distributed system.
+ */
+ public String buildSSLArguments(DistributedSystemConfig config) {
+ Properties sslProps = buildSSLProperties(config, true);
+ if (sslProps == null)
+ return null;
+
+ StringBuffer sb = new StringBuffer();
+ for (Iterator iter = sslProps.keySet().iterator(); iter.hasNext();) {
+ String key = (String) iter.next();
+ String value = sslProps.getProperty(key);
+ sb.append(" -J-D" + key + "=" + value);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Builds optional SSL properties for DistributionLocator. Returns null if SSL is not enabled for
+ * the distributed system.
+ *
+ * @param forCommandLine true indicates that {@link DistributionConfig#GEMFIRE_PREFIX} should be
+ * prepended so the argument will become -Dgemfire.xxxx
+ */
+ private Properties buildSSLProperties(DistributedSystemConfig config, boolean forCommandLine) {
+ if (!config.isSSLEnabled())
+ return null;
+
+ String prefix = "";
+ if (forCommandLine)
+ prefix = DistributionConfig.GEMFIRE_PREFIX;
+
+ Properties sslProps = (Properties) config.getSSLProperties().clone();
+ // add ssl-enabled, etc...
+ sslProps.setProperty(prefix + MCAST_PORT, "0");
+ sslProps.setProperty(prefix + CLUSTER_SSL_ENABLED, String.valueOf(config.isSSLEnabled()));
+ sslProps.setProperty(prefix + CLUSTER_SSL_CIPHERS, config.getSSLCiphers());
+ sslProps.setProperty(prefix + CLUSTER_SSL_PROTOCOLS, config.getSSLProtocols());
+ sslProps.setProperty(prefix + CLUSTER_SSL_REQUIRE_AUTHENTICATION,
+ String.valueOf(config.isSSLAuthenticationRequired()));
+ return sslProps;
+ }
+
+
+ /**
+ * Starts a managed entity.
+ */
+ public void start(final InternalManagedEntity entity) {
+ final String command = arrangeRemoteCommand(entity, entity.getStartCommand());
+ Thread start = new Thread(this.threadGroup, new Runnable() {
+ public void run() {
+ execute(command, entity);
+ }
+ }, "Start " + entity.getEntityType());
+ start.start();
+ }
+
+ /**
+ * Stops a managed entity.
+ */
+ public void stop(final InternalManagedEntity entity) {
+ final String command = arrangeRemoteCommand(entity, entity.getStopCommand());
+ Thread stop = new Thread(this.threadGroup, new Runnable() {
+ public void run() {
+ execute(command, entity);
+ }
+ }, "Stop " + entity.getEntityType());
+ stop.start();
+ }
+
+ /**
+ * Returns whether or not a managed entity is running
+ */
+ public boolean isRunning(InternalManagedEntity entity) {
+ final String command = arrangeRemoteCommand(entity, entity.getIsRunningCommand());
+ String output = execute(command, entity);
+
+ if (output == null || (output.indexOf("stop" /* "ing" "ped" */) != -1)
+ || (output.indexOf("killed") != -1) || (output.indexOf("starting") != -1)) {
+ return false;
+
+ } else if (output.indexOf("running") != -1) {
+ return true;
+
+ } else {
+ throw new IllegalStateException(
+ LocalizedStrings.ManagedEntityController_COULD_NOT_DETERMINE_IF_MANAGED_ENTITY_WAS_RUNNING_0
+ .toLocalizedString(output));
+ }
+ }
+
+ /**
+ * Returns the contents of a locator's log file. Other APIs are used to get the log file of
+ * managed entities that are also system members.
+ */
+ public String getLog(DistributionLocatorImpl locator) {
+ String command = arrangeRemoteCommand(locator, locator.getLogCommand());
+ return execute(command, locator);
+ }
+
+ /**
+ * Returns the contents of the given directory using the given managed entity to determine the
+ * host and remote command.
+ */
+ private String listDirectory(InternalManagedEntity entity, String dir) {
+ ManagedEntityConfig config = entity.getEntityConfig();
+ String listFile = pathIsWindows(config.getProductDirectory()) ? "dir " : "ls ";
+ String command = arrangeRemoteCommand(entity, listFile + dir);
+ return execute(command, entity);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupRequest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupRequest.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupRequest.java
new file mode 100644
index 0000000..dd0d0dc
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupRequest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.DataInput;
+import java.io.DataOutput;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.CancelException;
+import org.apache.geode.DataSerializer;
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.distributed.internal.DistributionMessage;
+import org.apache.geode.distributed.internal.ReplyException;
+import org.apache.geode.internal.admin.remote.AdminFailureResponse;
+import org.apache.geode.internal.admin.remote.AdminMultipleReplyProcessor;
+import org.apache.geode.internal.admin.remote.AdminResponse;
+import org.apache.geode.internal.admin.remote.CliLegacyMessage;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LocalizedMessage;
+
+/**
+ * A request send from an admin VM to all of the peers to indicate that that should complete the
+ * backup operation.
+ *
+ *
+ */
+public class FinishBackupRequest extends CliLegacyMessage {
+ private static final Logger logger = LogService.getLogger();
+
+ private File targetDir;
+ private File baselineDir;
+ private boolean abort;
+
+ public FinishBackupRequest() {
+ super();
+ }
+
+ public FinishBackupRequest(File targetDir, File baselineDir, boolean abort) {
+ this.targetDir = targetDir;
+ this.baselineDir = baselineDir;
+ this.abort = abort;
+ }
+
+ public static Map<DistributedMember, Set<PersistentID>> send(DM dm, Set recipients,
+ File targetDir, File baselineDir, boolean abort) {
+ FinishBackupRequest request = new FinishBackupRequest(targetDir, baselineDir, abort);
+ request.setRecipients(recipients);
+
+ FinishBackupReplyProcessor replyProcessor = new FinishBackupReplyProcessor(dm, recipients);
+ request.msgId = replyProcessor.getProcessorId();
+ dm.putOutgoing(request);
+ try {
+ replyProcessor.waitForReplies();
+ } catch (ReplyException e) {
+ if (!(e.getCause() instanceof CancelException)) {
+ throw e;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ AdminResponse response = request.createResponse((DistributionManager) dm);
+ response.setSender(dm.getDistributionManagerId());
+ replyProcessor.process(response);
+ return replyProcessor.results;
+ }
+
+ @Override
+ protected AdminResponse createResponse(DistributionManager dm) {
+ GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
+ HashSet<PersistentID> persistentIds;
+ if (cache == null || cache.getBackupManager() == null) {
+ persistentIds = new HashSet<PersistentID>();
+ } else {
+ try {
+ persistentIds = cache.getBackupManager().finishBackup(targetDir, baselineDir, abort);
+ } catch (IOException e) {
+ logger.error(
+ LocalizedMessage.create(LocalizedStrings.CliLegacyMessage_ERROR, this.getClass()), e);
+ return AdminFailureResponse.create(dm, getSender(), e);
+ }
+ }
+
+ return new FinishBackupResponse(this.getSender(), persistentIds);
+ }
+
+ public int getDSFID() {
+ return FINISH_BACKUP_REQUEST;
+ }
+
+ @Override
+ public void fromData(DataInput in) throws IOException, ClassNotFoundException {
+ super.fromData(in);
+ targetDir = DataSerializer.readFile(in);
+ baselineDir = DataSerializer.readFile(in);
+ abort = DataSerializer.readBoolean(in);
+ }
+
+ @Override
+ public void toData(DataOutput out) throws IOException {
+ super.toData(out);
+ DataSerializer.writeFile(targetDir, out);
+ DataSerializer.writeFile(baselineDir, out);
+ DataSerializer.writeBoolean(abort, out);
+ }
+
+ private static class FinishBackupReplyProcessor extends AdminMultipleReplyProcessor {
+ Map<DistributedMember, Set<PersistentID>> results =
+ Collections.synchronizedMap(new HashMap<DistributedMember, Set<PersistentID>>());
+
+ public FinishBackupReplyProcessor(DM dm, Collection initMembers) {
+ super(dm, initMembers);
+ }
+
+ @Override
+ protected boolean stopBecauseOfExceptions() {
+ return false;
+ }
+
+
+
+ @Override
+ protected int getAckWaitThreshold() {
+ // Disable the 15 second warning if the backup is taking a long time
+ return 0;
+ }
+
+ @Override
+ public long getAckSevereAlertThresholdMS() {
+ // Don't log severe alerts for backups either
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ protected void process(DistributionMessage msg, boolean warn) {
+ if (msg instanceof FinishBackupResponse) {
+ final HashSet<PersistentID> persistentIds = ((FinishBackupResponse) msg).getPersistentIds();
+ if (persistentIds != null && !persistentIds.isEmpty()) {
+ results.put(msg.getSender(), persistentIds);
+ }
+ }
+ super.process(msg, warn);
+ }
+
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupResponse.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupResponse.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupResponse.java
new file mode 100644
index 0000000..ad68f97
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FinishBackupResponse.java
@@ -0,0 +1,76 @@
+/*
+ * 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.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.HashSet;
+
+import org.apache.geode.DataSerializer;
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.admin.remote.AdminResponse;
+
+/**
+ * The reply for a {@link FinishBackupRequest}. The reply contains the persistent ids of the disk
+ * stores that were backed up on this member.
+ *
+ *
+ */
+public class FinishBackupResponse extends AdminResponse {
+
+ private HashSet<PersistentID> persistentIds;
+
+ public FinishBackupResponse() {
+ super();
+ }
+
+ public FinishBackupResponse(InternalDistributedMember sender,
+ HashSet<PersistentID> persistentIds) {
+ this.setRecipient(sender);
+ this.persistentIds = persistentIds;
+ }
+
+ public HashSet<PersistentID> getPersistentIds() {
+ return persistentIds;
+ }
+
+ @Override
+ public void fromData(DataInput in) throws IOException, ClassNotFoundException {
+ super.fromData(in);
+ persistentIds = DataSerializer.readHashSet(in);
+ }
+
+ @Override
+ public void toData(DataOutput out) throws IOException {
+ super.toData(out);
+ DataSerializer.writeHashSet(persistentIds, out);
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ public int getDSFID() {
+ return FINISH_BACKUP_RESPONSE;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + ": " + persistentIds;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskRequest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskRequest.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskRequest.java
new file mode 100644
index 0000000..c780d1d
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskRequest.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 java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.geode.CancelException;
+import org.apache.geode.cache.persistence.PersistentID;
+import org.apache.geode.distributed.internal.DM;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.distributed.internal.ReplyException;
+import org.apache.geode.internal.admin.remote.AdminMultipleReplyProcessor;
+import org.apache.geode.internal.admin.remote.AdminResponse;
+import org.apache.geode.internal.admin.remote.CliLegacyMessage;
+import org.apache.geode.internal.cache.DiskStoreImpl;
+import org.apache.geode.internal.cache.GemFireCacheImpl;
+
+/**
+ * A request to from an admin VM to all non admin members to start a backup. In the prepare phase of
+ * the backup, the members will suspend bucket destroys to make sure buckets aren't missed during
+ * the backup.
+ *
+ *
+ */
+public class FlushToDiskRequest extends CliLegacyMessage {
+
+ public FlushToDiskRequest() {
+
+ }
+
+ public static void send(DM dm, Set recipients) {
+ FlushToDiskRequest request = new FlushToDiskRequest();
+ request.setRecipients(recipients);
+
+ FlushToDiskProcessor replyProcessor = new FlushToDiskProcessor(dm, recipients);
+ request.msgId = replyProcessor.getProcessorId();
+ dm.putOutgoing(request);
+ try {
+ replyProcessor.waitForReplies();
+ } catch (ReplyException e) {
+ if (!(e.getCause() instanceof CancelException)) {
+ throw e;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ AdminResponse response = request.createResponse((DistributionManager) dm);
+ response.setSender(dm.getDistributionManagerId());
+ replyProcessor.process(response);
+ }
+
+ @Override
+ protected AdminResponse createResponse(DistributionManager dm) {
+ GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
+ HashSet<PersistentID> persistentIds;
+ if (cache != null) {
+ Collection<DiskStoreImpl> diskStores = cache.listDiskStoresIncludingRegionOwned();
+ for (DiskStoreImpl store : diskStores) {
+ store.flush();
+ }
+ }
+
+ return new FlushToDiskResponse(this.getSender());
+ }
+
+ public int getDSFID() {
+ return FLUSH_TO_DISK_REQUEST;
+ }
+
+ private static class FlushToDiskProcessor extends AdminMultipleReplyProcessor {
+ public FlushToDiskProcessor(DM dm, Collection initMembers) {
+ super(dm, initMembers);
+ }
+
+ @Override
+ protected boolean stopBecauseOfExceptions() {
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskResponse.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskResponse.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskResponse.java
new file mode 100644
index 0000000..869d56b
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/FlushToDiskResponse.java
@@ -0,0 +1,43 @@
+/*
+ * 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.membership.InternalDistributedMember;
+import org.apache.geode.internal.admin.remote.AdminResponse;
+
+/**
+ * The response to the {@link FlushToDiskRequest}
+ *
+ *
+ */
+public class FlushToDiskResponse extends AdminResponse {
+
+ public FlushToDiskResponse() {
+ super();
+ }
+
+ public FlushToDiskResponse(InternalDistributedMember sender) {
+ this.setRecipient(sender);
+ }
+
+ public int getDSFID() {
+ return FLUSH_TO_DISK_RESPONSE;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthConfigImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthConfigImpl.java
new file mode 100644
index 0000000..16b1d79
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthConfigImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.GemFireHealthConfig;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+// @todo davidw Delegate to a "parent" config for properties that are not overridden.
+// This will be made easier with a special <code>HealthConfigAttribute</code> class.
+/**
+ * The implementation of <code>GemFireHealthConfig</code>
+ *
+ *
+ *
+ * @since GemFire 3.5
+ */
+public class GemFireHealthConfigImpl extends CacheHealthConfigImpl implements GemFireHealthConfig {
+
+ private static final long serialVersionUID = -6797673296902808018L;
+
+ /** The name of the host to which this configuration applies. */
+ private String hostName;
+
+ /**
+ * The number of seconds to wait between evaluating the health of GemFire.
+ */
+ private int interval = DEFAULT_HEALTH_EVALUATION_INTERVAL;
+
+ //////////////////////// Constructors ////////////////////////
+
+ /**
+ * Creates a new <code>GemFireHealthConfigImpl</code> that applies to the host with the given
+ * name.
+ *
+ * @param hostName The name of the host to which this configuration applies. If <code>null</code>,
+ * then this is the "default" configuration.
+ */
+ public GemFireHealthConfigImpl(String hostName) {
+ this.hostName = hostName;
+ }
+
+ /////////////////////// Instance Methods ///////////////////////
+
+ public String getHostName() {
+ return this.hostName;
+ }
+
+ public void setHealthEvaluationInterval(int interval) {
+ this.interval = interval;
+ }
+
+ public int getHealthEvaluationInterval() {
+ return this.interval;
+ }
+
+ @Override
+ public String toString() {
+ if (this.hostName == null) {
+ return LocalizedStrings.GemFireHealthConfigImpl_DEFAULT_GEMFIRE_HEALTH_CONFIGURATION
+ .toLocalizedString();
+
+ } else {
+ return LocalizedStrings.GemFireHealthConfigImpl_GEMFIRE_HEALTH_CONFIGURATION_FOR_HOST_0
+ .toLocalizedString(this.hostName);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthEvaluator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthEvaluator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthEvaluator.java
new file mode 100644
index 0000000..d35a94c
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthEvaluator.java
@@ -0,0 +1,182 @@
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.internal.admin.api.GemFireHealth;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.distributed.internal.DistributionManager;
+import org.apache.geode.internal.Assert;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+
+/**
+ * Evaluates the health of various GemFire components in the VM according to a
+ * {@link GemFireHealthConfig}.
+ *
+ * <P>
+ *
+ * Note that evaluators never reside in the administration VM, they only in member VMs. They are not
+ * <code>Serializable</code> and aren't meant to be.
+ *
+ * @see MemberHealthEvaluator
+ * @see CacheHealthEvaluator
+ *
+ *
+ * @since GemFire 3.5
+ */
+public class GemFireHealthEvaluator {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /** Determines how the health of GemFire is determined */
+ private GemFireHealthConfig config;
+
+ /** Evaluates the health of this member of the distributed system */
+ private MemberHealthEvaluator memberHealth;
+
+ /** Evaluates the health of the Cache hosted in this VM */
+ private CacheHealthEvaluator cacheHealth;
+
+ /**
+ * The most recent <code>OKAY_HEALTH</code> diagnoses of the GemFire system
+ */
+ private List okayDiagnoses;
+
+ /**
+ * The most recent <code>POOR_HEALTH</code> diagnoses of the GemFire system
+ */
+ private List poorDiagnoses;
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>GemFireHealthEvaluator</code>
+ *
+ * @param config The configuration that determines whether or GemFire is healthy
+ * @param dm The distribution manager
+ */
+ public GemFireHealthEvaluator(GemFireHealthConfig config, DistributionManager dm) {
+ if (config == null) {
+ throw new NullPointerException(
+ LocalizedStrings.GemFireHealthEvaluator_NULL_GEMFIREHEALTHCONFIG.toLocalizedString());
+ }
+
+ this.config = config;
+ this.memberHealth = new MemberHealthEvaluator(config, dm);
+ this.cacheHealth = new CacheHealthEvaluator(config, dm);
+ this.okayDiagnoses = new ArrayList();
+ this.poorDiagnoses = new ArrayList();
+ }
+
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Evaluates the health of the GemFire components in this VM.
+ *
+ * @return The aggregate health code (such as {@link GemFireHealth#OKAY_HEALTH}) of the GemFire
+ * components.
+ */
+ public GemFireHealth.Health evaluate() {
+ List status = new ArrayList();
+ this.memberHealth.evaluate(status);
+ this.cacheHealth.evaluate(status);
+
+ GemFireHealth.Health overallHealth = GemFireHealth.GOOD_HEALTH;
+ this.okayDiagnoses.clear();
+ this.poorDiagnoses.clear();
+
+ for (Iterator iter = status.iterator(); iter.hasNext();) {
+ AbstractHealthEvaluator.HealthStatus health =
+ (AbstractHealthEvaluator.HealthStatus) iter.next();
+ if (overallHealth == GemFireHealth.GOOD_HEALTH) {
+ if ((health.getHealthCode() != GemFireHealth.GOOD_HEALTH)) {
+ overallHealth = health.getHealthCode();
+ }
+
+ } else if (overallHealth == GemFireHealth.OKAY_HEALTH) {
+ if (health.getHealthCode() == GemFireHealth.POOR_HEALTH) {
+ overallHealth = GemFireHealth.POOR_HEALTH;
+ }
+ }
+
+ GemFireHealth.Health healthCode = health.getHealthCode();
+ if (healthCode == GemFireHealth.OKAY_HEALTH) {
+ this.okayDiagnoses.add(health.getDiagnosis());
+
+ } else if (healthCode == GemFireHealth.POOR_HEALTH) {
+ this.poorDiagnoses.add(health.getDiagnosis());
+ }
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Evaluated health to be {}", overallHealth);
+ }
+ return overallHealth;
+ }
+
+ /**
+ * Returns detailed information explaining the current health status. Each array element is a
+ * different cause for the current status. An empty array will be returned if the current status
+ * is {@link GemFireHealth#GOOD_HEALTH}.
+ */
+ public String[] getDiagnosis(GemFireHealth.Health healthCode) {
+ if (healthCode == GemFireHealth.GOOD_HEALTH) {
+ return new String[0];
+
+ } else if (healthCode == GemFireHealth.OKAY_HEALTH) {
+ String[] array = new String[this.okayDiagnoses.size()];
+ this.okayDiagnoses.toArray(array);
+ return array;
+
+ } else {
+ Assert.assertTrue(healthCode == GemFireHealth.POOR_HEALTH);
+ String[] array = new String[this.poorDiagnoses.size()];
+ this.poorDiagnoses.toArray(array);
+ return array;
+ }
+ }
+
+ /**
+ * Resets the state of this evaluator
+ */
+ public void reset() {
+ this.okayDiagnoses.clear();
+ this.poorDiagnoses.clear();
+ }
+
+ /**
+ * Returns the heath evaluation interval, in seconds.
+ *
+ * @see GemFireHealthConfig#getHealthEvaluationInterval
+ */
+ public int getEvaluationInterval() {
+ return this.config.getHealthEvaluationInterval();
+ }
+
+ /**
+ * Closes this evaluator and releases all of its resources
+ */
+ public void close() {
+ this.memberHealth.close();
+ this.cacheHealth.close();
+ }
+
+}