modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java |
42 ++++++++++
modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java |
14 ++-
2 files changed, 53 insertions(+), 3 deletions(-)
New commits:
commit 1a82b2b9bbf077709f6aeaef1117ba218dd02489
Author: John Sanda <jsanda(a)redhat.com>
Date: Tue Mar 29 20:58:17 2011 -0400
Removing file that was accidentally committed from merge conflict
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
deleted file mode 100644
index 8f8b205..0000000
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 Red Hat, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.rhq.core.pc;
-
-import java.beans.Introspector;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import javax.security.auth.login.Configuration;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.rhq.core.clientapi.agent.bundle.BundleAgentService;
-import org.rhq.core.clientapi.agent.configuration.ConfigurationAgentService;
-import org.rhq.core.clientapi.agent.content.ContentAgentService;
-import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
-import org.rhq.core.clientapi.agent.inventory.ResourceFactoryAgentService;
-import org.rhq.core.clientapi.agent.measurement.MeasurementAgentService;
-import org.rhq.core.clientapi.agent.operation.OperationAgentService;
-import org.rhq.core.clientapi.agent.support.SupportAgentService;
-import org.rhq.core.pc.agent.AgentRegistrar;
-import org.rhq.core.pc.agent.AgentService;
-import org.rhq.core.pc.agent.AgentServiceLifecycleListener;
-import org.rhq.core.pc.agent.AgentServiceStreamRemoter;
-import org.rhq.core.pc.bundle.BundleManager;
-import org.rhq.core.pc.configuration.ConfigurationManager;
-import org.rhq.core.pc.configuration.ConfigurationManagerInitializer;
-import org.rhq.core.pc.content.ContentManager;
-import org.rhq.core.pc.event.EventManager;
-import org.rhq.core.pc.inventory.InventoryManager;
-import org.rhq.core.pc.inventory.ResourceContainer;
-import org.rhq.core.pc.inventory.ResourceFactoryManager;
-import org.rhq.core.pc.measurement.MeasurementManager;
-import org.rhq.core.pc.operation.OperationManager;
-import org.rhq.core.pc.plugin.PluginComponentFactory;
-import org.rhq.core.pc.plugin.PluginManager;
-import org.rhq.core.pc.support.SupportManager;
-import org.rhq.core.pluginapi.util.FileUtils;
-
-/**
- * This is the embeddable container that houses all plugins and the infrastructure that
binds them together. It contains
- * all the managers such as {@link PluginManager} and {@link InventoryManager}.
- *
- * <p>This container is controlled by its lifecycle methods ({@link #initialize()}
and {@link #shutdown()}. Prior to
- * initialization, this container's configuration should be set via
- * {@link #setConfiguration(PluginContainerConfiguration)}. If this is not done, a
default configuration will be
- * created.</p>
- *
- * @author Greg Hinkle
- * @author John Mazzitelli
- */
-public class PluginContainer implements ContainerService {
- private static final PluginContainer INSTANCE = new PluginContainer();
-
- private final Log log = LogFactory.getLog(PluginContainer.class);
-
-<<<<<<< HEAD
-=======
- private static final class NullRebootRequestListener implements RebootRequestListener
{
- @Override
- public void reboot() {
- }
- }
-
- /**
- * Invoked by the plugin container immediately after it is initialized
- */
- public static interface InitializationListener {
- /**
- * Notifies the listener that the plugin container has been initialized. This
method executes in the same
- * thread in which {@link PluginContainer#initialize()} is executing.
- */
- void initialized();
- }
-
->>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
- // our management interface
- private PluginContainerMBeanImpl mbean;
-
- private PluginContainerConfiguration configuration;
- private String version;
- private boolean started = false;
-
- private PluginManager pluginManager;
- private PluginComponentFactory pluginComponentFactory;
- private InventoryManager inventoryManager;
- private MeasurementManager measurementManager;
- private ConfigurationManager configurationManager;
- private OperationManager operationManager;
- private ResourceFactoryManager resourceFactoryManager;
- private ContentManager contentManager;
- private EventManager eventManager;
- private SupportManager supportManager;
- private BundleManager bundleManager;
-
- private Collection<AgentServiceLifecycleListener> agentServiceListeners = new
LinkedHashSet<AgentServiceLifecycleListener>();
- private AgentServiceStreamRemoter agentServiceStreamRemoter = null;
- private AgentRegistrar agentRegistrar = null;
-
- // this is to prevent race conditions on startup between components from all the
different managers
- private ReadWriteLock rwLock = new ReentrantReadWriteLock();
-
- private List<InitializationListener> initListeners;
- private Object initListenersLock = new Object();
-
- /**
- * Returns the singleton instance.
- *
- * @return the plugin container
- */
- public static PluginContainer getInstance() {
- return INSTANCE;
- }
-
- private PluginContainer() {
- // for why we need to do this, see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6727821
- try {
- Configuration.getConfiguration();
- } catch (Throwable t) {
- }
- }
-
- /**
- * Sets this plugin container's configuration which also provides configuration
settings for all the internal
- * services.
- *
- * @param configuration
- */
- public void setConfiguration(PluginContainerConfiguration configuration) {
- this.configuration = configuration;
- }
-
- /**
- * Adds a listener that will be notified whenever an {@link AgentService} hosted
within this plugin container is
- * started or stopped.
- *
- * @param listener
- */
- public void addAgentServiceLifecycleListener(AgentServiceLifecycleListener listener)
{
- agentServiceListeners.add(listener);
- }
-
- /**
- * Removes the given listener such that it will no longer receive {@link
AgentService} notifications.
- *
- * @param listener
- */
- public void removeAgentServiceLifecycleListener(AgentServiceLifecycleListener
listener) {
- agentServiceListeners.remove(listener);
- }
-
- /**
- * Returns a remoter object that can be used to remote streams. If
<code>null</code>, the plugin container will not
- * be able to remote streams to external clients, as in the case when the plugin
container is not running inside an
- * agent (i.e. embedded mode).
- *
- * @return remoter the object that will prepare a stream to be accessed by remote
clients (may be <code>null</code>)
- */
- public AgentServiceStreamRemoter getAgentServiceStreamRemoter() {
- return agentServiceStreamRemoter;
- }
-
- /**
- * Adds a remoter object that is responsible for remoting streams. If
<code>null</code>, the plugin container will
- * not be able to remote streams to external clients, as in the case when the plugin
container is not running inside
- * an agent (i.e. embedded mode).
- *
- * @param streamRemoter
- */
- public void setAgentServiceStreamRemoter(AgentServiceStreamRemoter streamRemoter) {
- agentServiceStreamRemoter = streamRemoter;
- }
-
- /**
- * Sets the given registrar as the object responsible for registering the plugin
container with a remote server. If
- * <code>null</code>, the plugin container will not be considered running
in an agent containing needing to be
- * registered with a remote server.
- *
- * @return the object that can be used to register this plugin container (may be
<code>null</code>)
- */
- public AgentRegistrar getAgentRegistrar() {
- return agentRegistrar;
- }
-
- /**
- * Sets the given registrar as the object responsible for registering the plugin
container with a remote server. If
- * <code>null</code>, the plugin container will not be considered running
in an agent containing needing to be
- * registered with a remote server.
- *
- * @param registrar
- */
- public void setAgentRegistrar(AgentRegistrar registrar) {
- agentRegistrar = registrar;
- }
-
- /**
- * If the plugin container has been initialized and plugins have started work, this
returns <code>true</code>.
- *
- * @return <code>true</code> if the plugin container was initialized and
started; <code>false</code> otherwise
- */
- public boolean isStarted() {
- Lock lock = obtainReadLock();
- try {
- return started;
- } finally {
- releaseLock(lock);
- }
- }
-
- /**
- * Initializes the plugin container which initializes all internal managers. Once
initialized, all plugins will be
- * activated, metrics will begin getting collected and automatic discovery will
start.
- *
- * <p>Note that if no configuration was {@link
#setConfiguration(PluginContainerConfiguration) set} prior to this
- * method being called, a default configuration will be created and used.</p>
- *
- * <p>If the plugin container has already been initialized, this method does
nothing and returns.</p>
- */
- public void initialize() {
- initListeners = new LinkedList<InitializationListener>();
- Lock lock = obtainWriteLock();
- try {
- if (!started) {
- version = PluginContainer.class.getPackage().getImplementationVersion();
- log.info("Initializing Plugin Container" + ((version != null) ?
(" v" + version) : "") + "...");
-
- if (configuration == null) {
- configuration = new PluginContainerConfiguration();
- }
-
- purgeTmpDirectoryContents();
-
- mbean = new PluginContainerMBeanImpl(this);
- mbean.register();
-
- ResourceContainer.initialize();
-
- pluginManager = new PluginManager();
- pluginComponentFactory = new PluginComponentFactory();
- inventoryManager = new InventoryManager();
- measurementManager = new MeasurementManager();
- configurationManager = new ConfigurationManager();
- operationManager = new OperationManager();
- resourceFactoryManager = new ResourceFactoryManager();
- contentManager = new ContentManager();
- eventManager = new EventManager();
- supportManager = new SupportManager();
- bundleManager = new BundleManager();
-
- startContainerService(pluginManager);
- startContainerService(pluginComponentFactory);
- startContainerService(inventoryManager);
- startContainerService(measurementManager);
- startContainerService(configurationManager);
- startContainerService(operationManager);
- startContainerService(resourceFactoryManager);
- startContainerService(contentManager);
- startContainerService(eventManager);
- startContainerService(supportManager);
- startContainerService(bundleManager);
-
- started = true;
-
- log.info("Plugin Container initialized.");
- }
- } finally {
- releaseLock(lock);
- }
-
-<<<<<<< HEAD
-=======
- synchronized (initListenersLock) {
- if (started) {
- for (InitializationListener listener : initListeners) {
- listener.initialized();
- }
- }
- initListeners.clear();
- }
-
->>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
- return;
- }
-
- /**
- * Shuts down the plugin container and all its internal services. If the plugin
container has already been shutdown,
- * this method does nothing and returns.
- */
- public void shutdown() {
- Lock lock = obtainWriteLock();
- try {
- if (started) {
-
- log.info("Plugin container is being shutdown...");
-
- if (mbean != null) {
- mbean.unregister();
- mbean = null;
- }
-
- boolean isInsideAgent = configuration.isInsideAgent();
-
- bundleManager.shutdown();
- supportManager.shutdown();
- eventManager.shutdown();
- contentManager.shutdown();
- resourceFactoryManager.shutdown();
- operationManager.shutdown();
- configurationManager.shutdown();
- measurementManager.shutdown();
- inventoryManager.shutdown();
- pluginComponentFactory.shutdown();
- pluginManager.shutdown();
-
- agentServiceListeners.clear();
- agentServiceListeners = new
LinkedHashSet<AgentServiceLifecycleListener>();
- agentServiceStreamRemoter = null;
- agentRegistrar = null;
-
- purgeTmpDirectoryContents();
-
- ResourceContainer.shutdown();
-
- bundleManager = null;
- supportManager = null;
- eventManager = null;
- contentManager = null;
- resourceFactoryManager = null;
- operationManager = null;
- configurationManager = null;
- measurementManager = null;
- inventoryManager = null;
- pluginComponentFactory = null;
- pluginManager = null;
-
- configuration = null;
-
- started = false;
-
- log.info("Plugin container is now shutdown.");
-
- // we typically do not want to do this if embedded somewhere other than
the agent VM
- if (isInsideAgent) {
- cleanMemory();
- }
- }
- } finally {
- releaseLock(lock);
- }
-
- return;
- }
-
- /**
- * Does things that help the garbage collector clean up the memory.
- * Only call this after the plugin container has been shutdown.
- */
- private void cleanMemory() {
- Introspector.flushCaches();
- LogFactory.releaseAll();
-
- // for why we need to do this, see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6727821
- try {
- Configuration.setConfiguration(null);
- } catch (Throwable t) {
- }
-
- System.gc();
- }
-
- private void purgeTmpDirectoryContents() {
- try {
- FileUtils.purge(configuration.getTemporaryDirectory(), false);
- } catch (IOException e) {
- log.warn("Failed to purge contents of temporary directory - cause:
" + e);
- }
- }
-
- private void startContainerService(ContainerService containerService) {
- log.debug("Starting and configuring container service: " +
containerService.getClass().getSimpleName());
-
- containerService.setConfiguration(configuration);
-
- AgentService agentService = null;
-
- if (containerService instanceof AgentService) {
- agentService = (AgentService) containerService;
-
- agentService.setAgentServiceStreamRemoter(agentServiceStreamRemoter);
-
- for (AgentServiceLifecycleListener agentServiceListener :
agentServiceListeners) {
- agentService.addLifecycleListener(agentServiceListener);
- }
-
- if (containerService instanceof ConfigurationManager) {
- ConfigurationManagerInitializer initializer = new
ConfigurationManagerInitializer();
- initializer.initialize((ConfigurationManager) containerService);
- }
- }
-
- containerService.initialize();
-
- if (agentService != null) {
-
agentService.notifyLifecycleListenersOfNewState(AgentService.LifecycleState.STARTED);
- }
- }
-
- private Lock obtainReadLock() {
- // try to obtain the lock, but if we can't get the lock in 60 seconds,
- // keep going. The PC is usually fine within seconds after its initializes,
- // so not getting this lock within 60 seconds probably isn't detrimental.
- // But if there is a deadlock, blocking forever here would be detrimental,
- // so we do not do it. We'll just log a warning and let the thread keep
going.
- Lock readLock = rwLock.readLock();
- try {
- if (!readLock.tryLock(60L, TimeUnit.SECONDS)) {
- String msg = "There may be a deadlock in the plugin
container.";
- //noinspection ThrowableInstanceNeverThrown
- log.warn(msg, new Throwable(msg));
- readLock = null;
- }
- } catch (InterruptedException e) {
- readLock = null;
- }
- return readLock;
- }
-
- private Lock obtainWriteLock() {
- // try to obtain the lock, but if we can't get the lock in 60 seconds,
- // keep going. The PC is usually fine within seconds after its initializes,
- // so not getting this lock within 60 seconds probably isn't detrimental.
- // But if there is a deadlock, blocking forever here would be detrimental,
- // so we do not do it. We'll just log a warning and let the thread keep
going.
- Lock writeLock = rwLock.writeLock();
- try {
- if (!writeLock.tryLock(60L, TimeUnit.SECONDS)) {
- String msg = "There may be a deadlock in the plugin
container.";
- //noinspection ThrowableInstanceNeverThrown
- log.warn(msg, new Throwable(msg));
- writeLock = null;
- }
- } catch (InterruptedException e) {
- writeLock = null;
- }
- return writeLock;
- }
-
- private void releaseLock(Lock lock) {
- if (lock != null) {
- lock.unlock();
- }
- }
-
- // The methods below return the actual manager implementation objects.
- // Only those objects inside the plugin container should be calling these
getXXXManager() methods.
-
- public PluginManager getPluginManager() {
- Lock lock = obtainReadLock();
- try {
- return pluginManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public PluginComponentFactory getPluginComponentFactory() {
- Lock lock = obtainReadLock();
- try {
- return pluginComponentFactory;
- } finally {
- releaseLock(lock);
- }
- }
-
- public InventoryManager getInventoryManager() {
- Lock lock = obtainReadLock();
- try {
- return inventoryManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public ConfigurationManager getConfigurationManager() {
- Lock lock = obtainReadLock();
- try {
- return configurationManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public MeasurementManager getMeasurementManager() {
- Lock lock = obtainReadLock();
- try {
- return measurementManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public OperationManager getOperationManager() {
- Lock lock = obtainReadLock();
- try {
- return operationManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public ResourceFactoryManager getResourceFactoryManager() {
- Lock lock = obtainReadLock();
- try {
- return resourceFactoryManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public ContentManager getContentManager() {
- Lock lock = obtainReadLock();
- try {
- return contentManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public EventManager getEventManager() {
- Lock lock = obtainReadLock();
- try {
- return eventManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public SupportManager getSupportManager() {
- Lock lock = obtainReadLock();
- try {
- return supportManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- public BundleManager getBundleManager() {
- Lock lock = obtainReadLock();
- try {
- return bundleManager;
- } finally {
- releaseLock(lock);
- }
- }
-
- // The methods below return the manager implementations wrapped in their remote
client interfaces.
- // External clients to the plugin container should probably use these rather than the
getXXXManager() methods.
-
- public DiscoveryAgentService getDiscoveryAgentService() {
- return getInventoryManager();
- }
-
- public ConfigurationAgentService getConfigurationAgentService() {
- return getConfigurationManager();
- }
-
- public MeasurementAgentService getMeasurementAgentService() {
- return getMeasurementManager();
- }
-
- public OperationAgentService getOperationAgentService() {
- return getOperationManager();
- }
-
- public ResourceFactoryAgentService getResourceFactoryAgentService() {
- return getResourceFactoryManager();
- }
-
- public ContentAgentService getContentAgentService() {
- return getContentManager();
- }
-
- public SupportAgentService getSupportAgentService() {
- return getSupportManager();
- }
-
- public BundleAgentService getBundleAgentService() {
- return getBundleManager();
- }
-
- public boolean isInsideAgent() {
- return (this.configuration != null &&
this.configuration.isInsideAgent());
- }
-<<<<<<< HEAD
-=======
-
- public void setRebootRequestListener(RebootRequestListener listener) {
- rebootListener = listener;
- }
-
- public void notifyRebootRequestListener() {
- rebootListener.reboot();
- }
-
- /**
- * Add the callback listener to notify when the plugin container is initialized. If
this method is invoked and
- * the PC is already initialized, then <code>listener</code> will be
invoked immediately.
- * @param listener The callback object to notify
- */
- public void addInitializationListener(InitializationListener listener) {
- synchronized (initListenersLock) {
- if (started) {
- listener.initialized();
- } else {
- initListeners.add(listener);
- }
- }
- }
-
->>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
-}
commit 97fde8e669a981f393000b8c7c8e52f78e9eda88
Author: John Sanda <jsanda(a)redhat.com>
Date: Tue Mar 29 20:49:06 2011 -0400
[BZ 677349] Adding logic to avoid deadlock during PC initialization
This commit adds an InitializationListener api to PluginContainer. When
plugin components start up while the PC is still initializing and
register event pollers, they now do so by way of this
InitializationListener api. EventContextImpl now registers a listener,
which does not require a lock and therefore eliminates the possibility
for deadlock. When the listener is invoked, the PC has already
released the write lock, EventManager is already up and running, and
there should be no problem registering the event poller at this point.
Also note the listener runs in the same thread that executes
PluginContainer.initialize.
Conflicts:
modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java
index 081e067..8f825f1 100644
--- a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java
+++ b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java
@@ -26,6 +26,8 @@ import java.beans.Introspector;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
@@ -80,6 +82,17 @@ public class PluginContainer implements ContainerService {
private final Log log = LogFactory.getLog(PluginContainer.class);
+ /**
+ * Invoked by the plugin container immediately after it is initialized
+ */
+ public static interface InitializationListener {
+ /**
+ * Notifies the listener that the plugin container has been initialized. This
method executes in the same
+ * thread in which {@link PluginContainer#initialize()} is executing.
+ */
+ void initialized();
+ }
+
// our management interface
private PluginContainerMBeanImpl mbean;
@@ -106,6 +119,9 @@ public class PluginContainer implements ContainerService {
// this is to prevent race conditions on startup between components from all the
different managers
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
+ private List<InitializationListener> initListeners;
+ private Object initListenersLock = new Object();
+
/**
* Returns the singleton instance.
*
@@ -220,6 +236,7 @@ public class PluginContainer implements ContainerService {
* <p>If the plugin container has already been initialized, this method does
nothing and returns.</p>
*/
public void initialize() {
+ initListeners = new LinkedList<InitializationListener>();
Lock lock = obtainWriteLock();
try {
if (!started) {
@@ -269,6 +286,15 @@ public class PluginContainer implements ContainerService {
releaseLock(lock);
}
+ synchronized (initListenersLock) {
+ if (started) {
+ for (InitializationListener listener : initListeners) {
+ listener.initialized();
+ }
+ }
+ initListeners.clear();
+ }
+
return;
}
@@ -581,4 +607,20 @@ public class PluginContainer implements ContainerService {
public boolean isInsideAgent() {
return (this.configuration != null &&
this.configuration.isInsideAgent());
}
+
+ /**
+ * Add the callback listener to notify when the plugin container is initialized. If
this method is invoked and
+ * the PC is already initialized, then <code>listener</code> will be
invoked immediately.
+ * @param listener The callback object to notify
+ */
+ public void addInitializationListener(InitializationListener listener) {
+ synchronized (initListenersLock) {
+ if (started) {
+ listener.initialized();
+ } else {
+ initListeners.add(listener);
+ }
+ }
+ }
+
}
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
new file mode 100644
index 0000000..8f8b205
--- /dev/null
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/PluginContainer.java.orig
@@ -0,0 +1,649 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.core.pc;
+
+import java.beans.Introspector;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.security.auth.login.Configuration;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.clientapi.agent.bundle.BundleAgentService;
+import org.rhq.core.clientapi.agent.configuration.ConfigurationAgentService;
+import org.rhq.core.clientapi.agent.content.ContentAgentService;
+import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
+import org.rhq.core.clientapi.agent.inventory.ResourceFactoryAgentService;
+import org.rhq.core.clientapi.agent.measurement.MeasurementAgentService;
+import org.rhq.core.clientapi.agent.operation.OperationAgentService;
+import org.rhq.core.clientapi.agent.support.SupportAgentService;
+import org.rhq.core.pc.agent.AgentRegistrar;
+import org.rhq.core.pc.agent.AgentService;
+import org.rhq.core.pc.agent.AgentServiceLifecycleListener;
+import org.rhq.core.pc.agent.AgentServiceStreamRemoter;
+import org.rhq.core.pc.bundle.BundleManager;
+import org.rhq.core.pc.configuration.ConfigurationManager;
+import org.rhq.core.pc.configuration.ConfigurationManagerInitializer;
+import org.rhq.core.pc.content.ContentManager;
+import org.rhq.core.pc.event.EventManager;
+import org.rhq.core.pc.inventory.InventoryManager;
+import org.rhq.core.pc.inventory.ResourceContainer;
+import org.rhq.core.pc.inventory.ResourceFactoryManager;
+import org.rhq.core.pc.measurement.MeasurementManager;
+import org.rhq.core.pc.operation.OperationManager;
+import org.rhq.core.pc.plugin.PluginComponentFactory;
+import org.rhq.core.pc.plugin.PluginManager;
+import org.rhq.core.pc.support.SupportManager;
+import org.rhq.core.pluginapi.util.FileUtils;
+
+/**
+ * This is the embeddable container that houses all plugins and the infrastructure that
binds them together. It contains
+ * all the managers such as {@link PluginManager} and {@link InventoryManager}.
+ *
+ * <p>This container is controlled by its lifecycle methods ({@link #initialize()}
and {@link #shutdown()}. Prior to
+ * initialization, this container's configuration should be set via
+ * {@link #setConfiguration(PluginContainerConfiguration)}. If this is not done, a
default configuration will be
+ * created.</p>
+ *
+ * @author Greg Hinkle
+ * @author John Mazzitelli
+ */
+public class PluginContainer implements ContainerService {
+ private static final PluginContainer INSTANCE = new PluginContainer();
+
+ private final Log log = LogFactory.getLog(PluginContainer.class);
+
+<<<<<<< HEAD
+=======
+ private static final class NullRebootRequestListener implements RebootRequestListener
{
+ @Override
+ public void reboot() {
+ }
+ }
+
+ /**
+ * Invoked by the plugin container immediately after it is initialized
+ */
+ public static interface InitializationListener {
+ /**
+ * Notifies the listener that the plugin container has been initialized. This
method executes in the same
+ * thread in which {@link PluginContainer#initialize()} is executing.
+ */
+ void initialized();
+ }
+
+>>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
+ // our management interface
+ private PluginContainerMBeanImpl mbean;
+
+ private PluginContainerConfiguration configuration;
+ private String version;
+ private boolean started = false;
+
+ private PluginManager pluginManager;
+ private PluginComponentFactory pluginComponentFactory;
+ private InventoryManager inventoryManager;
+ private MeasurementManager measurementManager;
+ private ConfigurationManager configurationManager;
+ private OperationManager operationManager;
+ private ResourceFactoryManager resourceFactoryManager;
+ private ContentManager contentManager;
+ private EventManager eventManager;
+ private SupportManager supportManager;
+ private BundleManager bundleManager;
+
+ private Collection<AgentServiceLifecycleListener> agentServiceListeners = new
LinkedHashSet<AgentServiceLifecycleListener>();
+ private AgentServiceStreamRemoter agentServiceStreamRemoter = null;
+ private AgentRegistrar agentRegistrar = null;
+
+ // this is to prevent race conditions on startup between components from all the
different managers
+ private ReadWriteLock rwLock = new ReentrantReadWriteLock();
+
+ private List<InitializationListener> initListeners;
+ private Object initListenersLock = new Object();
+
+ /**
+ * Returns the singleton instance.
+ *
+ * @return the plugin container
+ */
+ public static PluginContainer getInstance() {
+ return INSTANCE;
+ }
+
+ private PluginContainer() {
+ // for why we need to do this, see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6727821
+ try {
+ Configuration.getConfiguration();
+ } catch (Throwable t) {
+ }
+ }
+
+ /**
+ * Sets this plugin container's configuration which also provides configuration
settings for all the internal
+ * services.
+ *
+ * @param configuration
+ */
+ public void setConfiguration(PluginContainerConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ /**
+ * Adds a listener that will be notified whenever an {@link AgentService} hosted
within this plugin container is
+ * started or stopped.
+ *
+ * @param listener
+ */
+ public void addAgentServiceLifecycleListener(AgentServiceLifecycleListener listener)
{
+ agentServiceListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener such that it will no longer receive {@link
AgentService} notifications.
+ *
+ * @param listener
+ */
+ public void removeAgentServiceLifecycleListener(AgentServiceLifecycleListener
listener) {
+ agentServiceListeners.remove(listener);
+ }
+
+ /**
+ * Returns a remoter object that can be used to remote streams. If
<code>null</code>, the plugin container will not
+ * be able to remote streams to external clients, as in the case when the plugin
container is not running inside an
+ * agent (i.e. embedded mode).
+ *
+ * @return remoter the object that will prepare a stream to be accessed by remote
clients (may be <code>null</code>)
+ */
+ public AgentServiceStreamRemoter getAgentServiceStreamRemoter() {
+ return agentServiceStreamRemoter;
+ }
+
+ /**
+ * Adds a remoter object that is responsible for remoting streams. If
<code>null</code>, the plugin container will
+ * not be able to remote streams to external clients, as in the case when the plugin
container is not running inside
+ * an agent (i.e. embedded mode).
+ *
+ * @param streamRemoter
+ */
+ public void setAgentServiceStreamRemoter(AgentServiceStreamRemoter streamRemoter) {
+ agentServiceStreamRemoter = streamRemoter;
+ }
+
+ /**
+ * Sets the given registrar as the object responsible for registering the plugin
container with a remote server. If
+ * <code>null</code>, the plugin container will not be considered running
in an agent containing needing to be
+ * registered with a remote server.
+ *
+ * @return the object that can be used to register this plugin container (may be
<code>null</code>)
+ */
+ public AgentRegistrar getAgentRegistrar() {
+ return agentRegistrar;
+ }
+
+ /**
+ * Sets the given registrar as the object responsible for registering the plugin
container with a remote server. If
+ * <code>null</code>, the plugin container will not be considered running
in an agent containing needing to be
+ * registered with a remote server.
+ *
+ * @param registrar
+ */
+ public void setAgentRegistrar(AgentRegistrar registrar) {
+ agentRegistrar = registrar;
+ }
+
+ /**
+ * If the plugin container has been initialized and plugins have started work, this
returns <code>true</code>.
+ *
+ * @return <code>true</code> if the plugin container was initialized and
started; <code>false</code> otherwise
+ */
+ public boolean isStarted() {
+ Lock lock = obtainReadLock();
+ try {
+ return started;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ /**
+ * Initializes the plugin container which initializes all internal managers. Once
initialized, all plugins will be
+ * activated, metrics will begin getting collected and automatic discovery will
start.
+ *
+ * <p>Note that if no configuration was {@link
#setConfiguration(PluginContainerConfiguration) set} prior to this
+ * method being called, a default configuration will be created and used.</p>
+ *
+ * <p>If the plugin container has already been initialized, this method does
nothing and returns.</p>
+ */
+ public void initialize() {
+ initListeners = new LinkedList<InitializationListener>();
+ Lock lock = obtainWriteLock();
+ try {
+ if (!started) {
+ version = PluginContainer.class.getPackage().getImplementationVersion();
+ log.info("Initializing Plugin Container" + ((version != null) ?
(" v" + version) : "") + "...");
+
+ if (configuration == null) {
+ configuration = new PluginContainerConfiguration();
+ }
+
+ purgeTmpDirectoryContents();
+
+ mbean = new PluginContainerMBeanImpl(this);
+ mbean.register();
+
+ ResourceContainer.initialize();
+
+ pluginManager = new PluginManager();
+ pluginComponentFactory = new PluginComponentFactory();
+ inventoryManager = new InventoryManager();
+ measurementManager = new MeasurementManager();
+ configurationManager = new ConfigurationManager();
+ operationManager = new OperationManager();
+ resourceFactoryManager = new ResourceFactoryManager();
+ contentManager = new ContentManager();
+ eventManager = new EventManager();
+ supportManager = new SupportManager();
+ bundleManager = new BundleManager();
+
+ startContainerService(pluginManager);
+ startContainerService(pluginComponentFactory);
+ startContainerService(inventoryManager);
+ startContainerService(measurementManager);
+ startContainerService(configurationManager);
+ startContainerService(operationManager);
+ startContainerService(resourceFactoryManager);
+ startContainerService(contentManager);
+ startContainerService(eventManager);
+ startContainerService(supportManager);
+ startContainerService(bundleManager);
+
+ started = true;
+
+ log.info("Plugin Container initialized.");
+ }
+ } finally {
+ releaseLock(lock);
+ }
+
+<<<<<<< HEAD
+=======
+ synchronized (initListenersLock) {
+ if (started) {
+ for (InitializationListener listener : initListeners) {
+ listener.initialized();
+ }
+ }
+ initListeners.clear();
+ }
+
+>>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
+ return;
+ }
+
+ /**
+ * Shuts down the plugin container and all its internal services. If the plugin
container has already been shutdown,
+ * this method does nothing and returns.
+ */
+ public void shutdown() {
+ Lock lock = obtainWriteLock();
+ try {
+ if (started) {
+
+ log.info("Plugin container is being shutdown...");
+
+ if (mbean != null) {
+ mbean.unregister();
+ mbean = null;
+ }
+
+ boolean isInsideAgent = configuration.isInsideAgent();
+
+ bundleManager.shutdown();
+ supportManager.shutdown();
+ eventManager.shutdown();
+ contentManager.shutdown();
+ resourceFactoryManager.shutdown();
+ operationManager.shutdown();
+ configurationManager.shutdown();
+ measurementManager.shutdown();
+ inventoryManager.shutdown();
+ pluginComponentFactory.shutdown();
+ pluginManager.shutdown();
+
+ agentServiceListeners.clear();
+ agentServiceListeners = new
LinkedHashSet<AgentServiceLifecycleListener>();
+ agentServiceStreamRemoter = null;
+ agentRegistrar = null;
+
+ purgeTmpDirectoryContents();
+
+ ResourceContainer.shutdown();
+
+ bundleManager = null;
+ supportManager = null;
+ eventManager = null;
+ contentManager = null;
+ resourceFactoryManager = null;
+ operationManager = null;
+ configurationManager = null;
+ measurementManager = null;
+ inventoryManager = null;
+ pluginComponentFactory = null;
+ pluginManager = null;
+
+ configuration = null;
+
+ started = false;
+
+ log.info("Plugin container is now shutdown.");
+
+ // we typically do not want to do this if embedded somewhere other than
the agent VM
+ if (isInsideAgent) {
+ cleanMemory();
+ }
+ }
+ } finally {
+ releaseLock(lock);
+ }
+
+ return;
+ }
+
+ /**
+ * Does things that help the garbage collector clean up the memory.
+ * Only call this after the plugin container has been shutdown.
+ */
+ private void cleanMemory() {
+ Introspector.flushCaches();
+ LogFactory.releaseAll();
+
+ // for why we need to do this, see
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6727821
+ try {
+ Configuration.setConfiguration(null);
+ } catch (Throwable t) {
+ }
+
+ System.gc();
+ }
+
+ private void purgeTmpDirectoryContents() {
+ try {
+ FileUtils.purge(configuration.getTemporaryDirectory(), false);
+ } catch (IOException e) {
+ log.warn("Failed to purge contents of temporary directory - cause:
" + e);
+ }
+ }
+
+ private void startContainerService(ContainerService containerService) {
+ log.debug("Starting and configuring container service: " +
containerService.getClass().getSimpleName());
+
+ containerService.setConfiguration(configuration);
+
+ AgentService agentService = null;
+
+ if (containerService instanceof AgentService) {
+ agentService = (AgentService) containerService;
+
+ agentService.setAgentServiceStreamRemoter(agentServiceStreamRemoter);
+
+ for (AgentServiceLifecycleListener agentServiceListener :
agentServiceListeners) {
+ agentService.addLifecycleListener(agentServiceListener);
+ }
+
+ if (containerService instanceof ConfigurationManager) {
+ ConfigurationManagerInitializer initializer = new
ConfigurationManagerInitializer();
+ initializer.initialize((ConfigurationManager) containerService);
+ }
+ }
+
+ containerService.initialize();
+
+ if (agentService != null) {
+
agentService.notifyLifecycleListenersOfNewState(AgentService.LifecycleState.STARTED);
+ }
+ }
+
+ private Lock obtainReadLock() {
+ // try to obtain the lock, but if we can't get the lock in 60 seconds,
+ // keep going. The PC is usually fine within seconds after its initializes,
+ // so not getting this lock within 60 seconds probably isn't detrimental.
+ // But if there is a deadlock, blocking forever here would be detrimental,
+ // so we do not do it. We'll just log a warning and let the thread keep
going.
+ Lock readLock = rwLock.readLock();
+ try {
+ if (!readLock.tryLock(60L, TimeUnit.SECONDS)) {
+ String msg = "There may be a deadlock in the plugin
container.";
+ //noinspection ThrowableInstanceNeverThrown
+ log.warn(msg, new Throwable(msg));
+ readLock = null;
+ }
+ } catch (InterruptedException e) {
+ readLock = null;
+ }
+ return readLock;
+ }
+
+ private Lock obtainWriteLock() {
+ // try to obtain the lock, but if we can't get the lock in 60 seconds,
+ // keep going. The PC is usually fine within seconds after its initializes,
+ // so not getting this lock within 60 seconds probably isn't detrimental.
+ // But if there is a deadlock, blocking forever here would be detrimental,
+ // so we do not do it. We'll just log a warning and let the thread keep
going.
+ Lock writeLock = rwLock.writeLock();
+ try {
+ if (!writeLock.tryLock(60L, TimeUnit.SECONDS)) {
+ String msg = "There may be a deadlock in the plugin
container.";
+ //noinspection ThrowableInstanceNeverThrown
+ log.warn(msg, new Throwable(msg));
+ writeLock = null;
+ }
+ } catch (InterruptedException e) {
+ writeLock = null;
+ }
+ return writeLock;
+ }
+
+ private void releaseLock(Lock lock) {
+ if (lock != null) {
+ lock.unlock();
+ }
+ }
+
+ // The methods below return the actual manager implementation objects.
+ // Only those objects inside the plugin container should be calling these
getXXXManager() methods.
+
+ public PluginManager getPluginManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return pluginManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public PluginComponentFactory getPluginComponentFactory() {
+ Lock lock = obtainReadLock();
+ try {
+ return pluginComponentFactory;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public InventoryManager getInventoryManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return inventoryManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public ConfigurationManager getConfigurationManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return configurationManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public MeasurementManager getMeasurementManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return measurementManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public OperationManager getOperationManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return operationManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public ResourceFactoryManager getResourceFactoryManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return resourceFactoryManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public ContentManager getContentManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return contentManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public EventManager getEventManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return eventManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public SupportManager getSupportManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return supportManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ public BundleManager getBundleManager() {
+ Lock lock = obtainReadLock();
+ try {
+ return bundleManager;
+ } finally {
+ releaseLock(lock);
+ }
+ }
+
+ // The methods below return the manager implementations wrapped in their remote
client interfaces.
+ // External clients to the plugin container should probably use these rather than the
getXXXManager() methods.
+
+ public DiscoveryAgentService getDiscoveryAgentService() {
+ return getInventoryManager();
+ }
+
+ public ConfigurationAgentService getConfigurationAgentService() {
+ return getConfigurationManager();
+ }
+
+ public MeasurementAgentService getMeasurementAgentService() {
+ return getMeasurementManager();
+ }
+
+ public OperationAgentService getOperationAgentService() {
+ return getOperationManager();
+ }
+
+ public ResourceFactoryAgentService getResourceFactoryAgentService() {
+ return getResourceFactoryManager();
+ }
+
+ public ContentAgentService getContentAgentService() {
+ return getContentManager();
+ }
+
+ public SupportAgentService getSupportAgentService() {
+ return getSupportManager();
+ }
+
+ public BundleAgentService getBundleAgentService() {
+ return getBundleManager();
+ }
+
+ public boolean isInsideAgent() {
+ return (this.configuration != null &&
this.configuration.isInsideAgent());
+ }
+<<<<<<< HEAD
+=======
+
+ public void setRebootRequestListener(RebootRequestListener listener) {
+ rebootListener = listener;
+ }
+
+ public void notifyRebootRequestListener() {
+ rebootListener.reboot();
+ }
+
+ /**
+ * Add the callback listener to notify when the plugin container is initialized. If
this method is invoked and
+ * the PC is already initialized, then <code>listener</code> will be
invoked immediately.
+ * @param listener The callback object to notify
+ */
+ public void addInitializationListener(InitializationListener listener) {
+ synchronized (initListenersLock) {
+ if (started) {
+ listener.initialized();
+ } else {
+ initListeners.add(listener);
+ }
+ }
+ }
+
+>>>>>>> a12a99c... [BZ 677349] Adding logic to avoid deadlock during
PC initialization
+}
diff --git
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
index 943ed40..64a6ff7 100644
---
a/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
+++
b/modules/core/plugin-container/src/main/java/org/rhq/core/pc/event/EventContextImpl.java
@@ -104,12 +104,20 @@ public class EventContextImpl implements EventContext {
return getEventManager().getSigar();
}
- private void registerEventPollerInternal(EventPoller poller, int pollingInterval,
String sourceLocation) {
+ private void registerEventPollerInternal(final EventPoller poller, int
pollingInterval,
+ final String sourceLocation) {
EventDefinition eventDefinition =
EventUtility.getEventDefinition(poller.getEventType(), this.resource.getResourceType());
if (eventDefinition == null)
throw new IllegalArgumentException("Poller has unknown event type - no
EventDefinition exists with name '" + poller.getEventType() +
"'.");
- int adjustedPollingInterval = Math.max(EventContext.MINIMUM_POLLING_INTERVAL,
pollingInterval);
- getEventManager().registerEventPoller(poller, adjustedPollingInterval,
this.resource, sourceLocation);
+ final int adjustedPollingInterval =
Math.max(EventContext.MINIMUM_POLLING_INTERVAL, pollingInterval);
+ // Registering the event poller has to be done in a callback listener to avoid a
potential deadlock.
+ // See
https://bugzilla.redhat.com/show_bug.cgi?id=677349 for a detailed
explaination.
+ PluginContainer.getInstance().addInitializationListener(new
PluginContainer.InitializationListener() {
+ @Override
+ public void initialized() {
+ getEventManager().registerEventPoller(poller, adjustedPollingInterval,
resource, sourceLocation);
+ }
+ });
}
private void unregisterEventPollerInternal(String eventType, String sourceLocation)
{