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:33 UTC
[67/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/GemFireHealthImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthImpl.java
new file mode 100644
index 0000000..fc40261
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/GemFireHealthImpl.java
@@ -0,0 +1,514 @@
+/*
+ * 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.CancelException;
+import org.apache.geode.internal.Assert;
+import org.apache.geode.internal.admin.*;
+import org.apache.geode.internal.admin.api.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.DistributedSystemHealthConfig;
+import org.apache.geode.internal.admin.api.GemFireHealth;
+import org.apache.geode.internal.admin.api.GemFireHealthConfig;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.*;
+
+/**
+ * Provides the implementation of the <code>GemFireHealth</code> administration API. This class is
+ * responsible for {@linkplain GemFireVM#addHealthListener sending} the {@link GemFireHealthConfig}s
+ * to the remote member VM in which the health is calcualted.
+ *
+ *
+ * @since GemFire 3.5
+ */
+public class GemFireHealthImpl implements GemFireHealth, JoinLeaveListener, HealthListener {
+
+ /** The distributed system whose health is being monitored */
+ private final GfManagerAgent agent;
+
+ /** The default configuration for checking GemFire health */
+ protected GemFireHealthConfig defaultConfig;
+
+ /**
+ * Maps the name of a host to its <code>GemFireHealthConfig</code>. Note that the mappings are
+ * created lazily.
+ */
+ private final Map hostConfigs;
+
+ /**
+ * Maps the name of a host to all of the members (<code>GemFireVM</code>s) that run on that host.
+ */
+ private final Map hostMembers;
+
+ /** The members that are known to be in {@link #OKAY_HEALTH}. */
+ private Collection okayHealth;
+
+ /** The members that are known to be in {@link #POOR_HEALTH}. */
+ private Collection poorHealth;
+
+ /** The overall health of GemFire */
+ private GemFireHealth.Health overallHealth;
+
+ /** Is this GemFireHealthImpl closed? */
+ private boolean isClosed;
+
+ /**
+ * The configuration specifying how the health of the distributed system should be computed.
+ */
+ protected volatile DistributedSystemHealthConfig dsHealthConfig;
+
+ /** Monitors the health of the entire distributed system */
+ private DistributedSystemHealthMonitor dsHealthMonitor = null;
+
+ /**
+ * The distributed system whose health is monitored by this <Code>GemFireHealth</code>.
+ */
+ private final AdminDistributedSystem system;
+
+
+ /////////////////////// Constructors ///////////////////////
+
+ /**
+ * Creates a new <code>GemFireHealthImpl</code> that monitors the health of member of the given
+ * distributed system.
+ */
+ protected GemFireHealthImpl(GfManagerAgent agent, AdminDistributedSystem system) {
+ // agent.getDM().getLogger().info("Creating GemFireHealthImpl",
+ // new Exception("Stack trace"));
+
+ this.agent = agent;
+ this.system = system;
+
+ this.hostConfigs = new HashMap();
+ this.hostMembers = new HashMap();
+ this.okayHealth = new HashSet();
+ this.poorHealth = new HashSet();
+ this.overallHealth = GOOD_HEALTH;
+ this.isClosed = false;
+
+ GemFireVM[] apps = this.agent.listApplications();
+ for (int i = 0; i < apps.length; i++) {
+ GemFireVM member = apps[i];
+ this.noteNewMember(member);
+ }
+
+ agent.addJoinLeaveListener(this);
+ setDefaultGemFireHealthConfig(createGemFireHealthConfig(null));
+ setDistributedSystemHealthConfig(createDistributedSystemHealthConfig());
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("closed=" + isClosed);
+ sb.append("; hostMembers=" + hostMembers);
+ sb.append("; okayHealth=" + okayHealth);
+ sb.append("; poorHealth=" + poorHealth);
+ sb.append("; overallHealth=" + overallHealth);
+ sb.append("; diagnosis=" + getDiagnosis());
+ return sb.toString();
+ }
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Returns the <code>DistributedSystem</code> whose health this <code>GemFireHealth</code>
+ * monitors.
+ */
+ public AdminDistributedSystem getDistributedSystem() {
+ return this.system;
+ }
+
+ /**
+ * A "template factory" method for creating a <code>DistributedSystemHealthConfig</code>. It can
+ * be overridden by subclasses to produce instances of different
+ * <code>DistributedSystemHealthConfig</code> implementations.
+ */
+ protected DistributedSystemHealthConfig createDistributedSystemHealthConfig() {
+
+ return new DistributedSystemHealthConfigImpl();
+ }
+
+ /**
+ * A "template factory" method for creating a <code>GemFireHealthConfig</code>. It can be
+ * overridden by subclasses to produce instances of different <code>GemFireHealthConfig</code>
+ * implementations.
+ *
+ * @param hostName The host whose health we are configuring
+ */
+ protected GemFireHealthConfig createGemFireHealthConfig(String hostName) {
+
+ return new GemFireHealthConfigImpl(hostName);
+ }
+
+ /**
+ * Throws an {@link IllegalStateException} if this <code>GemFireHealthImpl</code> is closed.
+ */
+ private void checkClosed() {
+ if (this.isClosed) {
+ throw new IllegalStateException(
+ LocalizedStrings.GemFireHealthImpl_CANNOT_ACCESS_A_CLOSED_GEMFIREHEALTH_INSTANCE
+ .toLocalizedString());
+ }
+ }
+
+ /**
+ * Returns the overall health of GemFire. Note that this method does not contact any of the member
+ * VMs. Instead, it relies on the members to alert it of changes in its health via a
+ * {@link HealthListener}.
+ */
+ public GemFireHealth.Health getHealth() {
+ checkClosed();
+ return this.overallHealth;
+ }
+
+ /**
+ * Resets the overall health to be {@link #GOOD_HEALTH}. It also resets the health in the member
+ * VMs.
+ *
+ * @see GemFireVM#resetHealthStatus
+ */
+ public void resetHealth() {
+ checkClosed();
+
+ this.overallHealth = GOOD_HEALTH;
+ this.okayHealth.clear();
+ this.poorHealth.clear();
+
+ synchronized (this) {
+ for (Iterator iter = hostMembers.values().iterator(); iter.hasNext();) {
+ List members = (List) iter.next();
+ for (Iterator iter2 = members.iterator(); iter2.hasNext();) {
+ GemFireVM member = (GemFireVM) iter2.next();
+ member.resetHealthStatus();
+ }
+ }
+ }
+ }
+
+ /**
+ * Aggregates the diagnoses from all members of the distributed system.
+ */
+ public String getDiagnosis() {
+ checkClosed();
+
+ StringBuffer sb = new StringBuffer();
+
+ synchronized (this) {
+ for (Iterator iter = hostMembers.values().iterator(); iter.hasNext();) {
+ List members = (List) iter.next();
+ for (Iterator iter2 = members.iterator(); iter2.hasNext();) {
+ GemFireVM member = (GemFireVM) iter2.next();
+ String[] diagnoses = member.getHealthDiagnosis(this.overallHealth);
+ for (int i = 0; i < diagnoses.length; i++) {
+ sb.append(diagnoses[i]).append("\n");;
+ }
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Starts a new {@link DistributedSystemHealthMonitor}
+ */
+ public void setDistributedSystemHealthConfig(DistributedSystemHealthConfig config) {
+ synchronized (this.hostConfigs) {
+ // If too many threads are changing the health config, then we
+ // will might get an OutOfMemoryError trying to start a new
+ // health monitor thread.
+
+ if (this.dsHealthMonitor != null) {
+ this.dsHealthMonitor.stop();
+ }
+
+ this.dsHealthConfig = config;
+
+ DistributedSystemHealthEvaluator eval =
+ new DistributedSystemHealthEvaluator(config, this.agent.getDM());
+ int interval = this.getDefaultGemFireHealthConfig().getHealthEvaluationInterval();
+ this.dsHealthMonitor = new DistributedSystemHealthMonitor(eval, this, interval);
+ this.dsHealthMonitor.start();
+ }
+ }
+
+ public DistributedSystemHealthConfig getDistributedSystemHealthConfig() {
+
+ checkClosed();
+ return this.dsHealthConfig;
+ }
+
+ public GemFireHealthConfig getDefaultGemFireHealthConfig() {
+ checkClosed();
+ return this.defaultConfig;
+ }
+
+ public void setDefaultGemFireHealthConfig(GemFireHealthConfig config) {
+ checkClosed();
+
+ if (config.getHostName() != null) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.GemFireHealthImpl_THE_GEMFIREHEALTHCONFIG_FOR_FOR_0_CANNOT_SERVE_AS_THE_DEFAULT_HEALTH_CONFIG
+ .toLocalizedString(config.getHostName()));
+ }
+
+ this.defaultConfig = config;
+
+ synchronized (this) {
+ for (Iterator iter = this.hostMembers.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ InetAddress hostIpAddress = (InetAddress) entry.getKey();
+ List members = (List) entry.getValue();
+
+ GemFireHealthConfig hostConfig = (GemFireHealthConfig) hostConfigs.get(hostIpAddress);
+ if (hostConfig == null) {
+ hostConfig = config;
+ }
+
+ for (Iterator iter2 = members.iterator(); iter2.hasNext();) {
+ GemFireVM member = (GemFireVM) iter2.next();
+ Assert.assertTrue(member.getHost().equals(hostIpAddress));
+ member.addHealthListener(this, hostConfig);
+ }
+ }
+ }
+
+ // We only need to do this if the health monitoring interval has
+ // change. This is probably not the most efficient way of doing
+ // things.
+ if (this.dsHealthConfig != null) {
+ setDistributedSystemHealthConfig(this.dsHealthConfig);
+ }
+ }
+
+ /**
+ * Returns the GemFireHealthConfig object for the given host name.
+ *
+ * @param hostName host name for which the GemFire Health Config is needed
+ *
+ * @throws IllegalArgumentException if host with given name could not be found
+ */
+ public synchronized GemFireHealthConfig getGemFireHealthConfig(String hostName) {
+
+ checkClosed();
+
+ InetAddress hostIpAddress = null;
+ try {
+ hostIpAddress = InetAddress.getByName(hostName);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.GemFireHealthImpl_COULD_NOT_FIND_A_HOST_WITH_NAME_0
+ .toLocalizedString(hostName),
+ e);
+ }
+
+ GemFireHealthConfig config = (GemFireHealthConfig) this.hostConfigs.get(hostIpAddress);
+ if (config == null) {
+ config = createGemFireHealthConfig(hostName);
+ this.hostConfigs.put(hostIpAddress, config);
+ }
+
+ return config;
+ }
+
+ /**
+ * Sets the GemFireHealthConfig object for the given host name.
+ *
+ * @param hostName host name for which the GemFire Health Config is needed
+ * @param config GemFireHealthConfig object to set
+ *
+ * @throws IllegalArgumentException if (1) given host name & the host name in the given config do
+ * not match OR (2) host with given name could not be found OR (3) there are no GemFire
+ * components running on the given host
+ */
+ public void setGemFireHealthConfig(String hostName, GemFireHealthConfig config) {
+ checkClosed();
+
+ synchronized (this) {
+ String configHost = config.getHostName();
+ if (configHost == null || !configHost.equals(hostName)) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("The GemFireHealthConfig configures ");
+ if (configHost == null) {
+ sb.append("the default host ");
+
+ } else {
+ sb.append("host \"");
+ sb.append(config.getHostName());
+ sb.append("\" ");
+ }
+ sb.append("not \"" + hostName + "\"");
+ throw new IllegalArgumentException(sb.toString());
+ }
+ InetAddress hostIpAddress = null;
+ try {
+ hostIpAddress = InetAddress.getByName(hostName);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.GemFireHealthImpl_COULD_NOT_FIND_A_HOST_WITH_NAME_0
+ .toLocalizedString(hostName),
+ e);
+ }
+
+ List members = (List) this.hostMembers.get(hostIpAddress);
+ if (members == null || members.isEmpty()) {
+ throw new IllegalArgumentException(
+ LocalizedStrings.GemFireHealthImpl_THERE_ARE_NO_GEMFIRE_COMPONENTS_ON_HOST_0
+ .toLocalizedString(hostName));
+ }
+
+ for (Iterator iter = members.iterator(); iter.hasNext();) {
+ GemFireVM member = (GemFireVM) iter.next();
+ member.addHealthListener(this, config);
+ }
+ }
+ }
+
+ /**
+ * Tells the members of the distributed system that we are no longer interested in monitoring
+ * their health.
+ *
+ * @see GemFireVM#removeHealthListener
+ */
+ public void close() {
+ this.agent.removeJoinLeaveListener(this);
+
+ synchronized (this) {
+ if (this.isClosed) {
+ return;
+ }
+
+ this.isClosed = true;
+
+ if (this.dsHealthMonitor != null) {
+ this.dsHealthMonitor.stop();
+ this.dsHealthMonitor = null;
+ }
+
+ try {
+ for (Iterator iter = hostMembers.values().iterator(); iter.hasNext();) {
+ List members = (List) iter.next();
+ for (Iterator iter2 = members.iterator(); iter2.hasNext();) {
+ GemFireVM member = (GemFireVM) iter2.next();
+ member.removeHealthListener();
+ }
+ }
+ } catch (CancelException e) {
+ // if the DS is disconnected, stop trying to distribute to other members
+ }
+
+ hostConfigs.clear();
+ hostMembers.clear();
+ okayHealth.clear();
+ poorHealth.clear();
+ }
+ }
+
+ public boolean isClosed() {
+ return this.isClosed;
+ }
+
+ /**
+ * Makes note of the newly-joined member
+ */
+ private void noteNewMember(GemFireVM member) {
+ InetAddress hostIpAddress = member.getHost();
+ List members = (List) this.hostMembers.get(hostIpAddress);
+ if (members == null) {
+ members = new ArrayList();
+ this.hostMembers.put(hostIpAddress, members);
+ }
+ members.add(member);
+
+ }
+
+ public synchronized void nodeJoined(GfManagerAgent source, GemFireVM joined) {
+ noteNewMember(joined);
+
+ InetAddress hostIpAddress = joined.getHost();
+
+ GemFireHealthConfig config = (GemFireHealthConfig) this.hostConfigs.get(hostIpAddress);
+ if (config == null) {
+ config = this.getDefaultGemFireHealthConfig();
+ }
+ joined.addHealthListener(this, config);
+ }
+
+ /**
+ * Makes note of the newly-left member
+ */
+ public synchronized void nodeLeft(GfManagerAgent source, GemFireVM left) {
+ InetAddress hostIpAddress = left.getHost();
+ List members = (List) this.hostMembers.get(hostIpAddress);
+ if (members != null) {
+ members.remove(left);
+ if (members.isEmpty()) {
+ // No more members on the host
+ this.hostConfigs.remove(hostIpAddress);
+ this.hostMembers.remove(hostIpAddress);
+ }
+ }
+
+ this.okayHealth.remove(left);
+ this.poorHealth.remove(left);
+
+ reevaluateHealth();
+ }
+
+ /**
+ * Does the same thing as {@link #nodeLeft}
+ */
+ public void nodeCrashed(GfManagerAgent source, GemFireVM crashed) {
+ nodeLeft(source, crashed);
+ }
+
+ /**
+ * Re-evaluates the overall health of GemFire
+ */
+ private void reevaluateHealth() {
+ if (!this.poorHealth.isEmpty()) {
+ this.overallHealth = POOR_HEALTH;
+
+ } else if (!this.okayHealth.isEmpty()) {
+ this.overallHealth = OKAY_HEALTH;
+
+ } else {
+ this.overallHealth = GOOD_HEALTH;
+ }
+ }
+
+ public void healthChanged(GemFireVM member, GemFireHealth.Health status) {
+ if (status == GOOD_HEALTH) {
+ this.okayHealth.remove(member);
+ this.poorHealth.remove(member);
+
+ } else if (status == OKAY_HEALTH) {
+ this.okayHealth.add(member);
+ this.poorHealth.remove(member);
+
+ } else if (status == POOR_HEALTH) {
+ this.okayHealth.remove(member);
+ this.poorHealth.add(member);
+
+ } else {
+ Assert.assertTrue(false, "Unknown health code: " + status);
+ }
+
+ reevaluateHealth();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InetAddressUtil.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InetAddressUtil.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InetAddressUtil.java
new file mode 100755
index 0000000..5a4d3ca
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InetAddressUtil.java
@@ -0,0 +1,201 @@
+/*
+ * 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.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.GemFireIOException;
+import org.apache.geode.internal.Assert;
+import org.apache.geode.internal.net.SocketCreator;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.logging.LogService;
+
+
+/**
+ * Provides static utilities for manipulating, validating, and converting InetAddresses and host
+ * strings.
+ *
+ * @since GemFire 3.5
+ */
+@Deprecated
+public class InetAddressUtil {
+
+ private static final Logger logger = LogService.getLogger();
+
+ /** InetAddress instance representing the local host */
+ public static final InetAddress LOCALHOST = createLocalHost();
+
+ public static final String LOOPBACK_ADDRESS =
+ SocketCreator.preferIPv6Addresses() ? "::1" : "127.0.0.1";
+
+ public static final InetAddress LOOPBACK = InetAddressUtil.toInetAddress(LOOPBACK_ADDRESS);
+
+ /** Disallows InetAddressUtil instantiation. */
+ private InetAddressUtil() {}
+
+ /**
+ * Returns a string version of InetAddress which can be converted back to an InetAddress later.
+ * Essentially any leading slash is trimmed.
+ *
+ * @param val the InetAddress or String to return a formatted string of
+ * @return string version the InetAddress minus any leading slash
+ */
+ public static String toString(Object val) {
+ if (val instanceof String) {
+ return trimLeadingSlash((String) val);
+
+ } else if (val instanceof InetAddress) {
+ return ((InetAddress) val).getHostAddress();
+
+ } else {
+ return trimLeadingSlash(val.toString());
+ }
+ }
+
+ /**
+ * Converts the string host to an instance of InetAddress. Returns null if the string is empty.
+ * Fails Assertion if the conversion would result in <code>java.lang.UnknownHostException</code>.
+ * <p>
+ * Any leading slashes on host will be ignored.
+ *
+ * @param host string version the InetAddress
+ * @return the host converted to InetAddress instance
+ */
+ public static InetAddress toInetAddress(String host) {
+ if (host == null || host.length() == 0) {
+ return null;
+ }
+ try {
+ if (host.indexOf("/") > -1) {
+ return InetAddress.getByName(host.substring(host.indexOf("/") + 1));
+ } else {
+ return InetAddress.getByName(host);
+ }
+ } catch (java.net.UnknownHostException e) {
+ logStackTrace(e);
+ Assert.assertTrue(false, "Failed to get InetAddress: " + host);
+ return null; // will never happen since the Assert will fail
+ }
+ }
+
+ /**
+ * Creates an InetAddress representing the local host. The checked exception
+ * <code>java.lang.UnknownHostException</code> is captured and results in an Assertion failure
+ * instead.
+ *
+ * @return InetAddress instance representing the local host
+ */
+ public static InetAddress createLocalHost() {
+ try {
+ return SocketCreator.getLocalHost();
+ } catch (java.net.UnknownHostException e) {
+ logStackTrace(e);
+ Assert.assertTrue(false, "Failed to get local host");
+ return null; // will never happen
+ }
+ }
+
+ /**
+ * Validates the host by making sure it can successfully be used to get an instance of
+ * InetAddress. If the host string is null, empty or would result in
+ * <code>java.lang.UnknownHostException</code> then null is returned.
+ * <p>
+ * Any leading slashes on host will be ignored.
+ *
+ * @param host string version the InetAddress
+ * @return the host converted to InetAddress instance
+ */
+ public static String validateHost(String host) {
+ if (host == null || host.length() == 0) {
+ return null;
+ }
+ try {
+ InetAddress.getByName(trimLeadingSlash(host));
+ return host;
+ } catch (java.net.UnknownHostException e) {
+ logStackTrace(e);
+ return null;
+ }
+ }
+
+ /** Returns true if host matches the LOCALHOST. */
+ public static boolean isLocalHost(Object host) {
+ if (host instanceof InetAddress) {
+ if (LOCALHOST.equals(host)) {
+ return true;
+ } else {
+ // InetAddress hostAddr = (InetAddress)host;
+ try {
+ Enumeration en = NetworkInterface.getNetworkInterfaces();
+ while (en.hasMoreElements()) {
+ NetworkInterface i = (NetworkInterface) en.nextElement();
+ for (Enumeration en2 = i.getInetAddresses(); en2.hasMoreElements();) {
+ InetAddress addr = (InetAddress) en2.nextElement();
+ if (host.equals(addr)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } catch (SocketException e) {
+ throw new GemFireIOException(
+ LocalizedStrings.InetAddressUtil_UNABLE_TO_QUERY_NETWORK_INTERFACE
+ .toLocalizedString(),
+ e);
+ }
+ }
+ } else {
+ return isLocalHost(InetAddressUtil.toInetAddress(host.toString()));
+ }
+ }
+
+ /** Returns true if host matches the LOOPBACK (127.0.0.1). */
+ public static boolean isLoopback(Object host) {
+ if (host instanceof InetAddress) {
+ return LOOPBACK.equals(host);
+ } else {
+ return isLoopback(InetAddressUtil.toInetAddress(host.toString()));
+ }
+ }
+
+ /** Returns a version of the value after removing any leading slashes */
+ private static String trimLeadingSlash(String value) {
+ if (value == null)
+ return "";
+ while (value.indexOf("/") > -1) {
+ value = value.substring(value.indexOf("/") + 1);
+ }
+ return value;
+ }
+
+ /**
+ * Logs the stack trace for the given Throwable if logger is initialized else prints the stack
+ * trace using System.out. If logged the logs are logged at WARNING level.
+ *
+ * @param throwable Throwable to log stack trace for
+ */
+ private static void logStackTrace(Throwable throwable) {
+ AdminDistributedSystemImpl adminDS = AdminDistributedSystemImpl.getConnectedInstance();
+
+ logger.warn(throwable.getMessage(), throwable);
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InternalManagedEntity.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InternalManagedEntity.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InternalManagedEntity.java
new file mode 100644
index 0000000..a1e9fb0
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/InternalManagedEntity.java
@@ -0,0 +1,96 @@
+/*
+ * 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.ManagedEntity;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+
+/**
+ * Provides internal-only functionality that is expected of all <code>ManagedEntity<code>s. This
+ * functionality is used by the {@link ManagedEntityController} to manage the entity.
+ *
+ * @since GemFire 4.0
+ */
+public interface InternalManagedEntity extends ManagedEntity {
+
+ /** The state of a managed entity is unknown. */
+ public static final int UNKNOWN = 10;
+
+ /** A managed entity is stopped */
+ public static final int STOPPED = 11;
+
+ /** A managed entity is stopping (being stopped) */
+ public static final int STOPPING = 12;
+
+ /** A managed entity is starting */
+ public static final int STARTING = 13;
+
+ /** A managed entity is running (is started) */
+ public static final int RUNNING = 14;
+
+ ////////////////////// Instance Methods //////////////////////
+
+ /**
+ * Returns the <code>ManagedEntityConfig</code> for this <code>ManagedEntity</code>.
+ */
+ public ManagedEntityConfig getEntityConfig();
+
+ /**
+ * Returns a brief description (such as "locator") of this managed entity.
+ */
+ public String getEntityType();
+
+ /**
+ * Returns the (local) command to execute in order to start this managed entity. The command
+ * includes the full path to the executable (include <code>$GEMFIRE/bin</code>) and any
+ * command-line arguments. It does not take the {@linkplain ManagedEntityConfig#getRemoteCommand
+ * remote command} into account.
+ */
+ public String getStartCommand();
+
+ /**
+ * Returns the (local) command to execute in order to stop this managed entity.
+ */
+ public String getStopCommand();
+
+ /**
+ * Returns the (local) command to execute in order to determine whether or not this managed entity
+ * is runing.
+ */
+ public String getIsRunningCommand();
+
+ /**
+ * Returns a descriptive, one-word, unique id for a newly-created <code>ManagedEntity</code>. This
+ * ensures that we do not have collisions in the ids of entities.
+ */
+ public String getNewId();
+
+ /**
+ * Returns the distributed system to which this managed entity belongs.
+ */
+ public AdminDistributedSystem getDistributedSystem();
+
+ /**
+ * Sets the state of this managed entity and informs threads that are waiting for a state change.
+ * See bug 32455.
+ *
+ * @return The previous state of this managed entity.
+ *
+ * @see #RUNNING
+ */
+ public int setState(int state);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/LogCollator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/LogCollator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/LogCollator.java
new file mode 100755
index 0000000..b3c2b9c
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/LogCollator.java
@@ -0,0 +1,121 @@
+/*
+ * 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.GfManagerAgent;
+import org.apache.geode.internal.admin.GemFireVM;
+import org.apache.geode.internal.admin.ApplicationVM;
+import org.apache.geode.internal.logging.MergeLogFiles;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class LogCollator {
+
+ private GfManagerAgent system;
+ private List logTails;
+
+ public LogCollator() {}
+
+ public String collateLogs(GfManagerAgent system) {
+ try {
+ if (system == null) {
+ return "";
+ }
+ this.system = system;
+ this.logTails = new ArrayList();
+ gatherActiveLogs();
+ gatherInactiveLogs();
+ return mergeLogs();
+ } finally {
+ this.system = null;
+ this.logTails = null;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ private String mergeLogs() {
+ // combine logs...
+ InputStream[] logFiles = new InputStream[this.logTails.size()];
+ String[] logFileNames = new String[logFiles.length];
+ for (int i = 0; i < this.logTails.size(); i++) {
+ Loglet loglet = (Loglet) this.logTails.get(i);
+ logFiles[i] = new ByteArrayInputStream(loglet.tail.getBytes());
+ logFileNames[i] = loglet.name;
+ }
+
+ // delegate to MergeLogFiles...
+ StringWriter writer = new StringWriter();
+ PrintWriter mergedLog = new PrintWriter(writer);
+ if (!MergeLogFiles.mergeLogFiles(logFiles, logFileNames, mergedLog)) {
+ return writer.toString();
+ } else {
+ return "";
+ }
+ }
+
+ private void gatherActiveLogs() {
+ ApplicationVM[] runningsApps = this.system.listApplications();
+ for (int i = 0; i < runningsApps.length; i++) {
+ addLogFrom(runningsApps[i]);
+ }
+ }
+
+ private void gatherInactiveLogs() {
+ /*
+ * not yet supported.... if (useStopped) { LogViewHelper helper = new LogViewHelper(); for
+ * (Iterator iter = stoppedNodes.iterator(); iter.hasNext(); ) { Object adminEntity =
+ * iter.next(); helper.setAdminEntity(adminEntity); try { if (helper.logViewAvailable()) {
+ * String[] logs = helper.getSystemLogs(); addTail(allTails, logs, adminEntity.toString()); } }
+ * catch (Exception e) { Service.getService().reportSystemError(e); } } }
+ */
+ }
+
+ private void addLogFrom(GemFireVM vm) {
+ String name = null;
+ name = vm.toString();
+ String[] logs = vm.getSystemLogs();
+ addTail(name, logs);
+ }
+
+ private void addTail(String logName, String[] logs) {
+ if (logs.length > 0) {
+ String tail = (logs.length > 1) ? logs[1] : logs[0];
+ this.logTails.add(new Loglet(logName, tail));
+ }
+ }
+
+ /*
+ * public void setUseStoppedManagers(boolean useStopped) { this.useStopped = useStopped; }
+ */
+
+ private static class Loglet {
+ String name;
+ String tail;
+
+ Loglet(String name, String tail) {
+ this.name = name;
+ this.tail = tail;
+ }
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigImpl.java
new file mode 100644
index 0000000..3e27405
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigImpl.java
@@ -0,0 +1,254 @@
+/*
+ * 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.ManagedEntityConfig;
+import org.apache.geode.internal.admin.GemFireVM;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.net.SocketCreator;
+
+import java.io.File;
+import java.net.*;
+
+/**
+ * The abstract superclass of objects that configure a managed entity such as a GemFire cache server
+ * or a distribution locator. It contains configuration state and behavior common to all managed
+ * entities.
+ *
+ * @since GemFire 4.0
+ */
+public abstract class ManagedEntityConfigImpl implements ManagedEntityConfig {
+
+ /** The name of the host on which the managed entity runs */
+ private String host;
+
+ /** Directory in which the locator runs */
+ private String workingDirectory;
+
+ /** The directory in which GemFire is installed */
+ private String productDirectory;
+
+ /** Command used to launch locator on remote machine */
+ private String remoteCommand;
+
+ /**
+ * The managed entity configured by this object.
+ *
+ * @see #isReadOnly
+ */
+ private InternalManagedEntity entity = null;
+
+ ///////////////////// Static Methods /////////////////////
+
+ /**
+ * Returns the {@linkplain InetAddress#getCanonicalHostName canonical name} of the local machine.
+ */
+ protected static String getLocalHostName() {
+ try {
+ return SocketCreator.getLocalHost().getCanonicalHostName();
+
+ } catch (UnknownHostException ex) {
+ IllegalStateException ex2 = new IllegalStateException(
+ LocalizedStrings.ManagedEntityConfigImpl_COULD_NOT_DETERMINE_LOCALHOST
+ .toLocalizedString());
+ ex2.initCause(ex);
+ throw ex2;
+ }
+ }
+
+ /**
+ * Returns the current working directory for this VM.
+ */
+ private static File getCurrentWorkingDirectory() {
+ File cwd = new File(System.getProperty("user.dir"));
+ return cwd.getAbsoluteFile();
+ }
+
+ /**
+ * Returns the location of the GemFire product installation. This is determined by finding the
+ * location of the gemfire jar and working backwards.
+ */
+ private static File getGemFireInstallation() {
+ URL url = GemFireVersion.getJarURL();
+ if (url == null) {
+ throw new IllegalStateException(
+ LocalizedStrings.ManagedEntityConfigImpl_COULD_NOT_FIND_GEMFIREJAR.toLocalizedString());
+ }
+
+ File gemfireJar = new File(url.getPath());
+ File lib = gemfireJar.getParentFile();
+ File product = lib.getParentFile();
+
+ return product;
+ }
+
+ ////////////////////// Constructors //////////////////////
+
+ /**
+ * Creates a <code>ManagedEntityConfigImpl</code> with the default configuration.
+ */
+ protected ManagedEntityConfigImpl() {
+ this.host = getLocalHostName();
+ this.workingDirectory = getCurrentWorkingDirectory().getAbsolutePath();
+ this.productDirectory = getGemFireInstallation().getAbsolutePath();
+ this.remoteCommand = null; // Delegate to AdminDistributedSystem
+ }
+
+ /**
+ * Creates a new <code>ManagedEntityConfigImpl</code> based on the configuration of a running
+ * <code>GemFireVM</code>
+ */
+ protected ManagedEntityConfigImpl(GemFireVM vm) {
+ this.host = SocketCreator.getHostName(vm.getHost());
+ this.workingDirectory = vm.getWorkingDirectory().getAbsolutePath();
+ this.productDirectory = vm.getGemFireDir().getAbsolutePath();
+ this.remoteCommand = null;
+ }
+
+ /**
+ * A copy constructor that creates a new <code>ManagedEntityConfigImpl</code> with the same
+ * configuration as another <code>ManagedEntityConfig</code>.
+ */
+ protected ManagedEntityConfigImpl(ManagedEntityConfig other) {
+ this.host = other.getHost();
+ this.workingDirectory = other.getWorkingDirectory();
+ this.productDirectory = other.getProductDirectory();
+ this.remoteCommand = other.getRemoteCommand();
+ }
+
+ //////////////////// Instance Methods ////////////////////
+
+ /**
+ * Checks to see if this config object is "read only". If it is, then an
+ * {@link IllegalStateException} is thrown. It should be called by every setter method.
+ *
+ * @see #isReadOnly
+ */
+ public void checkReadOnly() {
+ if (this.isReadOnly()) {
+ throw new IllegalStateException(
+ LocalizedStrings.ManagedEntityConfigImpl_THIS_CONFIGURATION_CANNOT_BE_MODIFIED_WHILE_ITS_MANAGED_ENTITY_IS_RUNNING
+ .toLocalizedString());
+ }
+ }
+
+ /**
+ * Returns whether or not this <code>ManagedEntityConfigImpl</code> is read-only (can be
+ * modified).
+ */
+ protected boolean isReadOnly() {
+ return this.entity != null && this.entity.isRunning();
+ }
+
+ /**
+ * Sets the entity that is configured by this config object. Once the entity is running, the
+ * config object cannot be modified.
+ *
+ * @see #checkReadOnly
+ */
+ public void setManagedEntity(InternalManagedEntity entity) {
+ this.entity = entity;
+ }
+
+ /**
+ * Notifies any configuration listeners that this configuration has changed.
+ */
+ protected abstract void configChanged();
+
+ public String getHost() {
+ return this.host;
+ }
+
+ public void setHost(String host) {
+ checkReadOnly();
+ this.host = host;
+ configChanged();
+ }
+
+ public String getWorkingDirectory() {
+ String dir = this.workingDirectory;
+ return dir;
+ }
+
+ public void setWorkingDirectory(String workingDirectory) {
+ checkReadOnly();
+ this.workingDirectory = workingDirectory;
+ configChanged();
+ }
+
+ public String getProductDirectory() {
+ return this.productDirectory;
+ }
+
+ public void setProductDirectory(String productDirectory) {
+ checkReadOnly();
+ this.productDirectory = productDirectory;
+ configChanged();
+ }
+
+ public String getRemoteCommand() {
+ return this.remoteCommand;
+ }
+
+ public void setRemoteCommand(String remoteCommand) {
+ checkReadOnly();
+ this.remoteCommand = remoteCommand;
+ configChanged();
+ }
+
+ /**
+ * Validates this configuration.
+ *
+ * @throws IllegalStateException If this config is not valid
+ */
+ public void validate() {
+ if (InetAddressUtil.validateHost(this.host) == null) {
+ throw new IllegalStateException(
+ LocalizedStrings.ManagedEntityConfigImpl_INVALID_HOST_0.toLocalizedString(this.host));
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ // Since all fields are immutable objects, no deep cloning is
+ // necessary.
+ ManagedEntityConfigImpl clone = (ManagedEntityConfigImpl) super.clone();
+ clone.entity = null;
+ return clone;
+ }
+
+ @Override
+ public String toString() {
+ String className = this.getClass().getName();
+ int index = className.lastIndexOf('.');
+ className = className.substring(index + 1);
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(className);
+
+ sb.append(" host=");
+ sb.append(this.getHost());
+ sb.append(" workingDirectory=");
+ sb.append(this.getWorkingDirectory());
+ sb.append(" productDirectory=");
+ sb.append(this.getProductDirectory());
+ sb.append(" remoteCommand=\"");
+ sb.append(this.getRemoteCommand());
+ sb.append("\"");
+
+ 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/ManagedEntityConfigXml.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXml.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXml.java
new file mode 100644
index 0000000..3557751
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXml.java
@@ -0,0 +1,171 @@
+/*
+ * 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.ConfigurationProperties;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.xml.sax.*;
+
+import java.io.InputStream;
+
+/**
+ * The abstract superclass of classes that convert XML into a {@link
+ * DistributedSystemConfig} and vice versa.
+ * It provides helper methods and constants.
+ *
+ * @since GemFire 4.0
+ */
+abstract class ManagedEntityConfigXml implements EntityResolver, ErrorHandler {
+
+ /** The location of the DTD file */
+ protected static final String DTD_LOCATION =
+ "/org/apache/geode/internal/admin/doc-files/ds5_0.dtd";
+
+ /** The URL for the DTD */
+ protected static final String SYSTEM_ID = "http://www.gemstone.com/dtd/ds5_0.dtd";
+
+ /** The public ID for the DTD */
+ protected static final String PUBLIC_ID =
+ "-//GemStone Systems, Inc.//GemFire Distributed System 5.0//EN";
+
+ /** The name of the <code>distributed-system</code> element. */
+ public static final String DISTRIBUTED_SYSTEM = "distributed-system";
+
+ /** The name of the <code>id</code> attribute. */
+ public static final String ID = "id";
+
+ /** The name of the <code>disable-tcp</code> attribute. */
+ public static final String DISABLE_TCP = "disable-tcp";
+
+ /** The name of the <code>remote-command</code> element. */
+ public static final String REMOTE_COMMAND = "remote-command";
+
+ /** The name of the <code>locators</code> element. */
+ public static final String LOCATORS = ConfigurationProperties.LOCATORS;
+
+ /** The name of the <code>ssl</code> element. */
+ public static final String SSL = "ssl";
+
+ /** The name of the <code>cache-server</code> element */
+ public static final String CACHE_SERVER = "cache-server";
+
+ /** The name of the <code>multicast</code> element */
+ public static final String MULTICAST = "multicast";
+
+ /** The name of the <code>locator</code> element */
+ public static final String LOCATOR = "locator";
+
+ /** The name of the <code>port</code> attribute */
+ public static final String PORT = "port";
+
+ /** The name of the <code>address</code> attribute */
+ public static final String ADDRESS = "address";
+
+ /** The name of the <code>host</code> element. */
+ public static final String HOST = "host";
+
+ /** The name of the <code>working-directory</code> element */
+ public static final String WORKING_DIRECTORY = "working-directory";
+
+ /** The name of the <code>product-directory</code> element */
+ public static final String PRODUCT_DIRECTORY = "product-directory";
+
+ /** The name of the <code>protocols</code> element */
+ public static final String PROTOCOLS = "protocols";
+
+ /** The name of the <code>ciphers</code> element */
+ public static final String CIPHERS = "ciphers";
+
+ /** The name of the <code>property</code> element */
+ public static final String PROPERTY = "property";
+
+ /** Name of the <code>authentication-required</code> attribute */
+ public static final String AUTHENTICATION_REQUIRED = "authentication-required";
+
+ /** The name of the <code>key</code> element */
+ public static final String KEY = "key";
+
+ /** The name of the <code>value</code> element */
+ public static final String VALUE = "value";
+
+ /** The name of the <code>classpath</code> element */
+ public static final String CLASSPATH = "classpath";
+
+ /////////////////////// Instance Methods ///////////////////////
+
+ /**
+ * Given a public id, attempt to resolve it to a DTD. Returns an <code>InputSoure</code> for the
+ * DTD.
+ */
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
+
+ if (publicId == null || systemId == null) {
+ throw new SAXException(LocalizedStrings.ManagedEntityConfigXml_PUBLIC_ID_0_SYSTEM_ID_1
+ .toLocalizedString(new Object[] {publicId, systemId}));
+ }
+
+ // Figure out the location for the publicId.
+ String location = DTD_LOCATION;
+
+ InputSource result;
+ // if (location != null) (cannot be null)
+ {
+ InputStream stream = ClassPathLoader.getLatest().getResourceAsStream(getClass(), location);
+ if (stream != null) {
+ result = new InputSource(stream);
+ } else {
+ throw new SAXNotRecognizedException(
+ LocalizedStrings.ManagedEntityConfigXml_DTD_NOT_FOUND_0.toLocalizedString(location));
+ }
+
+ // } else {
+ // throw new
+ // SAXNotRecognizedException(LocalizedStrings.ManagedEntityConfigXml_COULD_NOT_FIND_DTD_FOR_0_1.toLocalizedString(new
+ // Object[] {publicId, systemId}));
+ }
+
+ return result;
+ }
+
+ /**
+ * Warnings are ignored
+ */
+ public void warning(SAXParseException ex) throws SAXException {
+
+ }
+
+ /**
+ * Throws a {@link org.apache.geode.cache.CacheXmlException}
+ */
+ public void error(SAXParseException ex) throws SAXException {
+ IllegalArgumentException ex2 = new IllegalArgumentException(
+ LocalizedStrings.ManagedEntityConfigXml_ERROR_WHILE_PARSING_XML.toLocalizedString());
+ ex2.initCause(ex);
+ throw ex2;
+ }
+
+ /**
+ * Throws a {@link org.apache.geode.cache.CacheXmlException}
+ */
+ public void fatalError(SAXParseException ex) throws SAXException {
+ IllegalArgumentException ex2 = new IllegalArgumentException(
+ LocalizedStrings.ManagedEntityConfigXml_FATAL_ERROR_WHILE_PARSING_XML.toLocalizedString());
+ ex2.initCause(ex);
+ throw ex2;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlGenerator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlGenerator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlGenerator.java
new file mode 100644
index 0000000..aaffa8e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlGenerator.java
@@ -0,0 +1,374 @@
+/*
+ * 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.Assert;
+import org.apache.geode.internal.admin.api.AdminDistributedSystem;
+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.DistributedSystemConfig;
+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.internal.i18n.LocalizedStrings;
+
+import javax.xml.transform.*;
+// import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import org.xml.sax.*;
+// import org.xml.sax.ext.*;
+import org.xml.sax.helpers.AttributesImpl;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Generates XML data that represents the managed entities in an
+ * <code>AdminDistributedSystem</code>. This class is used mainly for testing.
+ *
+ * @since GemFire 4.0
+ */
+public class ManagedEntityConfigXmlGenerator extends ManagedEntityConfigXml implements XMLReader {
+
+ /** An empty <code>Attributes</code> */
+ private static Attributes EMPTY = new AttributesImpl();
+
+ ///////////////////////// Instance Fields ////////////////////////
+
+ /**
+ * The <code>AdminDistributedSystem</code> for which we are generating XML
+ */
+ private AdminDistributedSystem system;
+
+ /** The content handler to which SAX events are generated */
+ private ContentHandler handler;
+
+ ///////////////////////// Static Methods ////////////////////////
+
+ /**
+ * Generates an XML representation of all of the managed entities in the given
+ * <code>AdminDistributedSystem</code>.
+ */
+ public static void generate(AdminDistributedSystem system, PrintWriter pw) {
+ (new ManagedEntityConfigXmlGenerator(system)).generate(pw);
+ }
+
+ ///////////////////////// Constructors //////////////////////////
+
+ /**
+ * Creates a new generator for the given <code>AdminDistributedSystem</code>.
+ */
+ private ManagedEntityConfigXmlGenerator(AdminDistributedSystem system) {
+ this.system = system;
+ }
+
+ /////////////////////// Instance Methods ///////////////////////
+
+ /**
+ * Generates XML and writes it to the given <code>PrintWriter</code>
+ */
+ private void generate(PrintWriter pw) {
+ // Use JAXP's transformation API to turn SAX events into pretty
+ // XML text
+ try {
+ Source src = new SAXSource(this, new InputSource());
+ Result res = new StreamResult(pw);
+
+ TransformerFactory xFactory = TransformerFactory.newInstance();
+ Transformer xform = xFactory.newTransformer();
+ xform.setOutputProperty(OutputKeys.METHOD, "xml");
+ xform.setOutputProperty(OutputKeys.INDENT, "yes");
+ xform.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, SYSTEM_ID);
+ xform.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, PUBLIC_ID);
+ xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ xform.transform(src, res);
+ pw.flush();
+
+ } catch (Exception ex) {
+ RuntimeException ex2 = new RuntimeException(
+ LocalizedStrings.ManagedEntityConfigXmlGenerator_EXCEPTION_THROWN_WHILE_GENERATING_XML
+ .toLocalizedString());
+ ex2.initCause(ex);
+ throw ex2;
+ }
+ }
+
+ /**
+ * Called by the transformer to parse the "input source". We ignore the input source and, instead,
+ * generate SAX events to the {@link #setContentHandler ContentHandler}.
+ */
+ public void parse(InputSource input) throws SAXException {
+ Assert.assertTrue(this.handler != null);
+
+ handler.startDocument();
+
+ AttributesImpl atts = new AttributesImpl();
+
+ atts.addAttribute("", "", ID, "", String.valueOf(this.system.getConfig().getSystemId()));
+
+ handler.startElement("", DISTRIBUTED_SYSTEM, DISTRIBUTED_SYSTEM, atts);
+
+ // Add generation methods here
+ try {
+ generateRemoteCommand();
+ generateDiscovery();
+ generateSSL();
+ generateCacheServers();
+
+ } catch (AdminException ex) {
+ throw new SAXException(
+ LocalizedStrings.ManagedEntityConfigXmlGenerator_AN_ADMINEXCEPTION_WAS_THROWN_WHILE_GENERATING_XML
+ .toLocalizedString(),
+ ex);
+ }
+
+ handler.endElement("", DISTRIBUTED_SYSTEM, DISTRIBUTED_SYSTEM);
+ handler.endDocument();
+ }
+
+ /**
+ * Generates XML for the remote command
+ */
+ private void generateRemoteCommand() throws SAXException {
+ String remoteCommand = this.system.getRemoteCommand();
+
+ handler.startElement("", REMOTE_COMMAND, REMOTE_COMMAND, EMPTY);
+
+ handler.characters(remoteCommand.toCharArray(), 0, remoteCommand.length());
+
+ handler.endElement("", REMOTE_COMMAND, REMOTE_COMMAND);
+ }
+
+ /**
+ * Generates XML for locators in the distributed system
+ */
+ private void generateDiscovery() throws SAXException {
+ handler.startElement("", LOCATORS, LOCATORS, EMPTY);
+
+ generateLocators();
+
+ handler.endElement("", LOCATORS, LOCATORS);
+ }
+
+ /**
+ * Generates XML for the distributed system's locators
+ */
+ private void generateLocators() throws SAXException {
+ DistributionLocator[] locators = this.system.getDistributionLocators();
+ for (int i = 0; i < locators.length; i++) {
+ generateLocator(locators[i].getConfig());
+ }
+ }
+
+ /**
+ * Generates XML for a locator
+ */
+ private void generateLocator(DistributionLocatorConfig config)
+ throws SAXException {
+
+ AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute("", "", PORT, "", String.valueOf(config.getPort()));
+
+ handler.startElement("", LOCATOR, LOCATOR, atts);
+
+ generateEntityConfig(config);
+
+ handler.endElement("", LOCATOR, LOCATOR);
+ }
+
+ /**
+ * Generates XML for attributes common to all managed entities.
+ */
+ private void generateEntityConfig(ManagedEntityConfig config)
+ throws SAXException {
+
+ String host = config.getHost();
+ if (host != null) {
+ handler.startElement("", HOST, HOST, EMPTY);
+ handler.characters(host.toCharArray(), 0, host.length());
+ handler.endElement("", HOST, HOST);
+ }
+
+ String remoteCommand = config.getRemoteCommand();
+ if (remoteCommand != null) {
+ handler.startElement("", REMOTE_COMMAND, REMOTE_COMMAND, EMPTY);
+ handler.characters(remoteCommand.toCharArray(), 0, remoteCommand.length());
+ handler.endElement("", REMOTE_COMMAND, REMOTE_COMMAND);
+ }
+
+ String workingDirectory = config.getWorkingDirectory();
+ if (workingDirectory != null) {
+ handler.startElement("", WORKING_DIRECTORY, WORKING_DIRECTORY, EMPTY);
+ handler.characters(workingDirectory.toCharArray(), 0, workingDirectory.length());
+ handler.endElement("", WORKING_DIRECTORY, WORKING_DIRECTORY);
+ }
+
+ String productDirectory = config.getProductDirectory();
+ if (productDirectory != null) {
+ handler.startElement("", PRODUCT_DIRECTORY, PRODUCT_DIRECTORY, EMPTY);
+ handler.characters(productDirectory.toCharArray(), 0, productDirectory.length());
+ handler.endElement("", PRODUCT_DIRECTORY, PRODUCT_DIRECTORY);
+ }
+ }
+
+ /**
+ * Generates XML for the SSL configuration of the distributed system.
+ */
+ private void generateSSL() throws SAXException {
+ DistributedSystemConfig config = this.system.getConfig();
+
+ boolean sslEnabled = config.isSSLEnabled();
+ if (!sslEnabled) {
+ return;
+ }
+
+ AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute("", "", AUTHENTICATION_REQUIRED, "",
+ String.valueOf(config.isSSLAuthenticationRequired()));
+
+ handler.startElement("", SSL, SSL, atts);
+
+ String protocols = config.getSSLProtocols();
+ if (protocols != null) {
+ handler.startElement("", PROTOCOLS, PROTOCOLS, EMPTY);
+ handler.characters(protocols.toCharArray(), 0, protocols.length());
+ handler.endElement("", PROTOCOLS, PROTOCOLS);
+ }
+
+ String ciphers = config.getSSLCiphers();
+ if (ciphers != null) {
+ handler.startElement("", CIPHERS, CIPHERS, EMPTY);
+ handler.characters(ciphers.toCharArray(), 0, ciphers.length());
+ handler.endElement("", CIPHERS, CIPHERS);
+ }
+
+ Properties sslProps = config.getSSLProperties();
+ for (Iterator iter = sslProps.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ String key = (String) entry.getKey();
+ String value = (String) entry.getValue();
+
+ handler.startElement("", PROPERTY, PROPERTY, EMPTY);
+
+ handler.startElement("", KEY, KEY, EMPTY);
+ handler.characters(key.toCharArray(), 0, key.length());
+ handler.endElement("", KEY, KEY);
+
+ handler.startElement("", VALUE, VALUE, EMPTY);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", VALUE, VALUE);
+
+ handler.endElement("", PROPERTY, PROPERTY);
+ }
+
+ handler.endElement("", SSL, SSL);
+ }
+
+ /**
+ * Generates an XML representation of the <code>CacheServer</code>s in the distributed system.
+ */
+ private void generateCacheServers() throws SAXException, AdminException {
+
+ CacheServer[] servers = this.system.getCacheServers();
+ for (int i = 0; i < servers.length; i++) {
+ generateCacheServer(servers[i].getConfig());
+ }
+ }
+
+ /**
+ * Generates an XML representation of a <code>CacheServerConfig</code>.
+ */
+ private void generateCacheServer(CacheServerConfig config)
+ throws SAXException {
+
+ handler.startElement("", CACHE_SERVER, CACHE_SERVER, EMPTY);
+
+ generateEntityConfig(config);
+
+ String classpath = config.getClassPath();
+ if (classpath != null) {
+ handler.startElement("", CLASSPATH, CLASSPATH, EMPTY);
+ handler.characters(classpath.toCharArray(), 0, classpath.length());
+ handler.endElement("", CLASSPATH, CLASSPATH);
+ }
+
+ handler.endElement("", CACHE_SERVER, CACHE_SERVER);
+ }
+
+ /**
+ * Keep track of the content handler for use during {@link #parse(String)}.
+ */
+ public void setContentHandler(ContentHandler handler) {
+ this.handler = handler;
+ }
+
+ public ContentHandler getContentHandler() {
+ return this.handler;
+ }
+
+ public ErrorHandler getErrorHandler() {
+ return this;
+ }
+
+ ////////// Inherited methods that don't do anything //////////
+
+ public boolean getFeature(String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException {
+ return false;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws SAXNotRecognizedException, SAXNotSupportedException {
+
+ }
+
+ public Object getProperty(String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException {
+
+ return null;
+ }
+
+ public void setProperty(String name, Object value)
+ throws SAXNotRecognizedException, SAXNotSupportedException {
+
+ }
+
+ public void setEntityResolver(EntityResolver resolver) {
+
+ }
+
+ public EntityResolver getEntityResolver() {
+ return this;
+ }
+
+ public void setDTDHandler(DTDHandler handler) {
+
+ }
+
+ public DTDHandler getDTDHandler() {
+ return null;
+ }
+
+ public void setErrorHandler(ErrorHandler handler) {
+
+ }
+
+ public void parse(String systemId) throws IOException, SAXException {
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlParser.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlParser.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlParser.java
new file mode 100644
index 0000000..111c7fc
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityConfigXmlParser.java
@@ -0,0 +1,591 @@
+/*
+ * 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.Assert;
+import org.apache.geode.internal.admin.api.AdminXmlException;
+import org.apache.geode.internal.admin.api.CacheServerConfig;
+import org.apache.geode.internal.admin.api.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.DistributionLocatorConfig;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Parses an XML file and configures a {@link DistributedSystemConfig} from it.
+ *
+ * @since GemFire 4.0
+ */
+public class ManagedEntityConfigXmlParser extends ManagedEntityConfigXml implements ContentHandler {
+
+ /** The <code>DistributedSystemConfig</code> to be configured */
+ private DistributedSystemConfig config;
+
+ /** The stack of intermediate values used while parsing */
+ private Stack stack = new Stack();
+
+ ////////////////////// Static Methods //////////////////////
+
+ /**
+ * Parses XML data and from it configures a <code>DistributedSystemConfig</code>.
+ *
+ * @throws AdminXmlException If an error is encountered while parsing the XML
+ */
+ public static void parse(InputStream is, DistributedSystemConfig config) {
+ ManagedEntityConfigXmlParser handler = new ManagedEntityConfigXmlParser();
+ handler.config = config;
+
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(true);
+ SAXParser parser = factory.newSAXParser();
+ parser.parse(is, new DefaultHandlerDelegate(handler));
+
+ } catch (Exception ex) {
+ if (ex instanceof AdminXmlException) {
+ throw (AdminXmlException) ex;
+
+ } else if (ex.getCause() instanceof AdminXmlException) {
+ throw (AdminXmlException) ex.getCause();
+
+ } else if (ex instanceof SAXException) {
+ // Silly JDK 1.4.2 XML parser wraps RunTime exceptions in a
+ // SAXException. Pshaw!
+
+ SAXException sax = (SAXException) ex;
+ Exception cause = sax.getException();
+ if (cause instanceof AdminXmlException) {
+ throw (AdminXmlException) cause;
+ }
+ }
+
+ throw new AdminXmlException(
+ LocalizedStrings.ManagedEntityConfigXmlParser_WHILE_PARSING_XML.toLocalizedString(), ex);
+ }
+ }
+
+ /**
+ * Helper method for parsing an integer
+ *
+ * @throws org.apache.geode.cache.CacheXmlException If <code>s</code> is a malformed integer
+ */
+ private static int parseInt(String s) {
+ try {
+ return Integer.parseInt(s);
+
+ } catch (NumberFormatException ex) {
+ throw new AdminXmlException(
+ LocalizedStrings.ManagedEntityConfigXmlParser_MALFORMED_INTEGER_0.toLocalizedString(s),
+ ex);
+ }
+ }
+
+ ////////////////////// Instance Methods //////////////////////
+
+ // if (this.system.isMcastEnabled()) {
+ // generateMulticast();
+ // }
+
+ public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
+ throws SAXException {
+
+ if (qName.equals(DISTRIBUTED_SYSTEM)) {
+ startDistributedSystem(atts);
+
+ } else if (qName.equals(REMOTE_COMMAND)) {
+ startRemoteCommand(atts);
+
+ } else if (qName.equals(LOCATORS)) {
+ startLocators(atts);
+
+ } else if (qName.equals(MULTICAST)) {
+ startMulticast(atts);
+
+ } else if (qName.equals(LOCATOR)) {
+ startLocator(atts);
+
+ } else if (qName.equals(HOST)) {
+ startHost(atts);
+
+ } else if (qName.equals(WORKING_DIRECTORY)) {
+ startWorkingDirectory(atts);
+
+ } else if (qName.equals(PRODUCT_DIRECTORY)) {
+ startProductDirectory(atts);
+
+ } else if (qName.equals(SSL)) {
+ startSSL(atts);
+
+ } else if (qName.equals(PROTOCOLS)) {
+ startProtocols(atts);
+
+ } else if (qName.equals(CIPHERS)) {
+ startCiphers(atts);
+
+ } else if (qName.equals(PROPERTY)) {
+ startProperty(atts);
+
+ } else if (qName.equals(KEY)) {
+ startKey(atts);
+
+ } else if (qName.equals(VALUE)) {
+ startValue(atts);
+
+ } else if (qName.equals(CACHE_SERVER)) {
+ startCacheServer(atts);
+
+ } else if (qName.equals(CLASSPATH)) {
+ startClassPath(atts);
+
+ } else {
+ throw new AdminXmlException(
+ LocalizedStrings.ManagedEntityConfigXmlParser_UNKNOWN_XML_ELEMENT_0
+ .toLocalizedString(qName));
+ }
+ }
+
+ public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+
+ if (qName.equals(DISTRIBUTED_SYSTEM)) {
+ endDistributedSystem();
+
+ } else if (qName.equals(REMOTE_COMMAND)) {
+ endRemoteCommand();
+
+ } else if (qName.equals(LOCATORS)) {
+ endLocators();
+
+ } else if (qName.equals(MULTICAST)) {
+ endMulticast();
+
+ } else if (qName.equals(LOCATOR)) {
+ endLocator();
+
+ } else if (qName.equals(HOST)) {
+ endHost();
+
+ } else if (qName.equals(WORKING_DIRECTORY)) {
+ endWorkingDirectory();
+
+ } else if (qName.equals(PRODUCT_DIRECTORY)) {
+ endProductDirectory();
+
+ } else if (qName.equals(SSL)) {
+ endSSL();
+
+ } else if (qName.equals(PROTOCOLS)) {
+ endProtocols();
+
+ } else if (qName.equals(CIPHERS)) {
+ endCiphers();
+
+ } else if (qName.equals(PROPERTY)) {
+ endProperty();
+
+ } else if (qName.equals(KEY)) {
+ endKey();
+
+ } else if (qName.equals(VALUE)) {
+ endValue();
+
+ } else if (qName.equals(CACHE_SERVER)) {
+ endCacheServer();
+
+ } else if (qName.equals(CLASSPATH)) {
+ endClassPath();
+
+ } else {
+ throw new AdminXmlException(
+ LocalizedStrings.ManagedEntityConfigXmlParser_UNKNOWN_XML_ELEMENT_0
+ .toLocalizedString(qName));
+ }
+ }
+
+ /**
+ * When a <code>distributed-system</code> element is encountered, we push the
+ * <code>DistributedSystemConfig</code> on the stack.
+ */
+ private void startDistributedSystem(Attributes atts) {
+ Assert.assertTrue(stack.isEmpty());
+
+ String id = atts.getValue(ID);
+ if (id != null) {
+ this.config.setSystemId(id);
+ }
+
+ String disable_tcp = atts.getValue(DISABLE_TCP);
+ if (disable_tcp != null) {
+ this.config.setDisableTcp(DISABLE_TCP.equalsIgnoreCase("true"));
+ }
+
+ stack.push(this.config);
+ }
+
+ /**
+ * When a <code>distributed-system</code> element is finished
+ */
+ private void endDistributedSystem() {
+
+ }
+
+ /**
+ * When a <code>multicast</code> is first encountered, get the
+ * <code>DistributedSystemConfig</code> off of the top of the stack and set its multicast config
+ * appropriately.
+ */
+ private void startMulticast(Attributes atts) {
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+
+ String port = atts.getValue(PORT);
+ config.setMcastPort(parseInt(port));
+
+ String address = atts.getValue(ADDRESS);
+ if (address != null) {
+ config.setMcastAddress(address);
+ }
+ }
+
+ private void endMulticast() {
+
+ }
+
+ /**
+ * Starts a <code>remote-command</code> element. The item on top of the stack may be a
+ * <code>DistributedSystemConfig</code> or it might be a <code>ManagedEntityConfig</code>.
+ */
+ private void startRemoteCommand(Attributes atts) {
+
+ }
+
+ /**
+ * Ends a <code>remote-command</code> element. Pop the command off the top of the stack and set it
+ * on the <code>DistributedSystemConfig</code> or it might be a <code>ManagedEntityConfig</code>
+ * on top of the stack.
+ */
+ private void endRemoteCommand() {
+ String remoteCommand = popString();
+ Object top = stack.peek();
+ Assert.assertTrue(top != null);
+
+ if (top instanceof DistributedSystemConfig) {
+ ((DistributedSystemConfig) top).setRemoteCommand(remoteCommand);
+
+ } else if (top instanceof ManagedEntityConfig) {
+ ((ManagedEntityConfig) top).setRemoteCommand(remoteCommand);
+
+ } else {
+ String s = "Did not expect a " + top.getClass().getName() + " on top of the stack";
+ Assert.assertTrue(false, s);
+ }
+ }
+
+ private void startLocators(Attributes atts) {
+
+ }
+
+ private void endLocators() {
+
+ }
+
+ private void startLocator(Attributes atts) {
+ String port = atts.getValue(PORT);
+
+ DistributedSystemConfig system = (DistributedSystemConfig) stack.peek();
+ system.setMcastPort(0);
+
+ DistributionLocatorConfig config = system.createDistributionLocatorConfig();
+
+ config.setPort(parseInt(port));
+
+ stack.push(config);
+ }
+
+ private void endLocator() {
+ Object o = stack.pop();
+ Assert.assertTrue(o instanceof DistributionLocatorConfig);
+ }
+
+ private void startHost(Attributes atts) {
+
+ }
+
+ /**
+ * We assume that there is a <code>ManagedEntityConfig</code> on top of the stack.
+ */
+ private void endHost() {
+ String host = popString();
+ ManagedEntityConfig config = (ManagedEntityConfig) stack.peek();
+ config.setHost(host);
+ }
+
+ private void startWorkingDirectory(Attributes atts) {
+
+ }
+
+ private void endWorkingDirectory() {
+ String workingDirectory = popString();
+ ManagedEntityConfig config = (ManagedEntityConfig) stack.peek();
+ config.setWorkingDirectory(workingDirectory);
+ }
+
+ private void startProductDirectory(Attributes atts) {
+
+ }
+
+ private void endProductDirectory() {
+ String productDirectory = popString();
+ ManagedEntityConfig config = (ManagedEntityConfig) stack.peek();
+ config.setProductDirectory(productDirectory);
+ }
+
+ private void startSSL(Attributes atts) {
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+ config.setSSLEnabled(true);
+
+ String authenticationRequired = atts.getValue(AUTHENTICATION_REQUIRED);
+ config.setSSLAuthenticationRequired(Boolean.valueOf(authenticationRequired).booleanValue());
+ }
+
+ private void endSSL() {
+
+ }
+
+ private void startProtocols(Attributes atts) {
+
+ }
+
+ private void endProtocols() {
+ String protocols = popString();
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+ config.setSSLProtocols(protocols);
+ }
+
+ private void startCiphers(Attributes atts) {
+
+ }
+
+ private void endCiphers() {
+ String ciphers = popString();
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+ config.setSSLCiphers(ciphers);
+ }
+
+ private void startProperty(Attributes atts) {
+
+ }
+
+ private void endProperty() {
+ String value = popString();
+ String key = popString();
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+ config.addSSLProperty(key, value);
+ }
+
+ private void startKey(Attributes atts) {
+
+ }
+
+ private void endKey() {
+ String key = popString();
+ stack.push(key);
+ }
+
+ private void startValue(Attributes atts) {
+
+ }
+
+ private void endValue() {
+ String value = popString();
+ stack.push(value);
+ }
+
+ private void startCacheServer(Attributes atts) {
+ DistributedSystemConfig config = (DistributedSystemConfig) stack.peek();
+ CacheServerConfig server = config.createCacheServerConfig();
+ stack.push(server);
+ }
+
+ private void endCacheServer() {
+ /* CacheServerConfig server = (CacheServerConfig) */ stack.pop();
+ }
+
+ private void startClassPath(Attributes atts) {
+
+ }
+
+ private void endClassPath() {
+ String classpath = popString();
+ CacheServerConfig server = (CacheServerConfig) stack.peek();
+ server.setClassPath(classpath);
+ }
+
+ /**
+ * Pops a <code>String</code> off of the stack.
+ */
+ private String popString() {
+ Object o = stack.pop();
+
+ if (o instanceof StringBuffer) {
+ StringBuffer sb = (StringBuffer) o;
+ return sb.toString();
+
+ } else {
+ return (String) o;
+ }
+ }
+
+ /**
+ * Long strings in XML files may generate multiple <code>characters</code> callbacks. Coalesce
+ * multiple callbacks into one big string by using a <code>StringBuffer</code>. See bug 32122.
+ */
+ public void characters(char[] ch, int start, int length) throws SAXException {
+
+ Object top = stack.peek();
+
+ StringBuffer sb;
+ if (top instanceof StringBuffer) {
+ sb = (StringBuffer) top;
+
+ } else {
+ sb = new StringBuffer();
+ stack.push(sb);
+ }
+
+ sb.append(ch, start, length);
+ }
+
+ ////////// Inherited methods that don't do anything //////////
+
+ public void setDocumentLocator(Locator locator) {}
+
+ public void startDocument() throws SAXException {}
+
+ public void endDocument() throws SAXException {}
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {}
+
+ public void endPrefixMapping(String prefix) throws SAXException {}
+
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {}
+
+ public void processingInstruction(String target, String data) throws SAXException {}
+
+ public void skippedEntity(String name) throws SAXException {}
+
+ /////////////////////// Inner Classes ///////////////////////
+
+ /**
+ * Class that delegates all of the methods of a {@link DefaultHandler} to a
+ * {@link ManagedEntityConfigXmlParser} that implements all of the methods of
+ * <code>DefaultHandler</code>, but <B>is not</B> a <code>DefaultHandler</code>.
+ */
+ static class DefaultHandlerDelegate extends DefaultHandler {
+ /**
+ * The <code>ManagedEntityConfigXmlParser</code> that does the real work
+ */
+ private ManagedEntityConfigXmlParser handler;
+
+ /**
+ * Creates a new <code>DefaultHandlerDelegate</code> that delegates to the given
+ * <code>ManagedEntityConfigXmlParser</code>.
+ */
+ public DefaultHandlerDelegate(ManagedEntityConfigXmlParser handler) {
+ this.handler = handler;
+ }
+
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
+ return handler.resolveEntity(publicId, systemId);
+ }
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ handler.setDocumentLocator(locator);
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ handler.startDocument();
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ handler.endDocument();
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ handler.startPrefixMapping(prefix, uri);
+ }
+
+ @Override
+ public void endPrefixMapping(String prefix) throws SAXException {
+ handler.endPrefixMapping(prefix);
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ handler.startElement(uri, localName, qName, attributes);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ handler.endElement(uri, localName, qName);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ handler.characters(ch, start, length);
+ }
+
+ @Override
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ handler.ignorableWhitespace(ch, start, length);
+ }
+
+ @Override
+ public void processingInstruction(String target, String data) throws SAXException {
+ handler.processingInstruction(target, data);
+ }
+
+ @Override
+ public void skippedEntity(String name) throws SAXException {
+ handler.skippedEntity(name);
+ }
+
+ @Override
+ public void warning(SAXParseException e) throws SAXException {
+ handler.warning(e);
+ }
+
+ @Override
+ public void error(SAXParseException e) throws SAXException {
+ handler.error(e);
+ }
+
+ @Override
+ public void fatalError(SAXParseException e) throws SAXException {
+ handler.fatalError(e);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityController.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityController.java
new file mode 100644
index 0000000..5876d0e
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityController.java
@@ -0,0 +1,66 @@
+/*
+ * 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.DistributedSystemConfig;
+import org.apache.geode.internal.admin.api.ManagedEntity;
+import org.apache.geode.internal.admin.api.ManagedEntityConfig;
+
+/**
+ * Defines the actual administration (starting, stopping, etc.) of GemFire {@link ManagedEntity}s.
+ *
+ */
+interface ManagedEntityController {
+ /**
+ * Starts a managed entity.
+ */
+ public void start(final InternalManagedEntity entity);
+
+ /**
+ * Stops a managed entity.
+ */
+ public void stop(final InternalManagedEntity entity);
+
+ /**
+ * Returns whether or not a managed entity is running
+ */
+ public boolean isRunning(InternalManagedEntity entity);
+
+ /**
+ * 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);
+
+ /**
+ * 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);
+
+ /**
+ * Builds optional SSL command-line arguments. Returns null if SSL is not enabled for the
+ * distributed system.
+ */
+ public String buildSSLArguments(DistributedSystemConfig config);
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/895fd144/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityControllerFactory.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityControllerFactory.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityControllerFactory.java
new file mode 100755
index 0000000..cd66ee9
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ManagedEntityControllerFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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.AdminDistributedSystem;
+import org.apache.geode.internal.admin.api.ManagedEntity;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.logging.log4j.LogMarker;
+
+/**
+ * Creates ManagedEntityController for administration (starting, stopping, etc.) of GemFire
+ * {@link ManagedEntity}s.
+ *
+ */
+public class ManagedEntityControllerFactory {
+
+ private static final Logger logger = LogService.getLogger();
+
+ private static final String ENABLED_MANAGED_ENTITY_CONTROLLER_CLASS_NAME = "EnabledManagedEntityController";
+
+ static ManagedEntityController createManagedEntityController(final AdminDistributedSystem system) {
+ if (isEnabledManagedEntityController()) {
+ logger.info(LogMarker.CONFIG,
+ "Local and remote OS command invocations are enabled for the Admin API.");
+ return createEnabledManagedEntityController(system);
+ } else {
+ logger.info(LogMarker.CONFIG,
+ "Local and remote OS command invocations are disabled for the Admin API.");
+ return new DisabledManagedEntityController();
+ }
+ }
+
+ public static boolean isEnabledManagedEntityController() {
+ try {
+ ClassPathLoader.getLatest().forName(ENABLED_MANAGED_ENTITY_CONTROLLER_CLASS_NAME);
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ private static ManagedEntityController createEnabledManagedEntityController(
+ final AdminDistributedSystem system) {
+ return new EnabledManagedEntityController(system);
+ }
+}