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); + } +}
