/*
* Copyright (C) 2003-2011 eXo Platform SAS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.etk.kernel.container.management;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.management.MBeanServer;
import org.etk.kernel.container.CachingContainer;
import org.etk.kernel.container.jmx.MX4JComponentAdapterFactory;
import org.etk.kernel.container.monitor.jvm.J2EEServerInfo;
import org.etk.kernel.management.annotations.Managed;
import org.etk.kernel.management.annotations.ManagedDescription;
import org.etk.kernel.management.annotations.ManagedName;
import org.etk.kernel.management.jmx.JMXManagementProvider;
import org.etk.kernel.management.spi.ManagementContext;
import org.etk.kernel.management.spi.ManagementProvider;
import org.picocontainer.ComponentAdapter;
import org.picocontainer.PicoContainer;
import org.picocontainer.PicoException;
import org.picocontainer.PicoRegistrationException;
import org.picocontainer.defaults.ComponentAdapterFactory;
/**
* Created by The eXo Platform SAS
* Author : eXoPlatform
* exo@exoplatform.com
* Jul 28, 2011
*/
public class ManageableContainer extends CachingContainer {
private static MBeanServer findMBeanServer() {
J2EEServerInfo serverenv_ = new J2EEServerInfo();
return serverenv_.getMBeanServer();
}
/** . */
private static final ThreadLocal<ManageableComponentAdapterFactory> hack = new ThreadLocal<ManageableComponentAdapterFactory>();
/** . */
final ManagementContextImpl managementContext;
/** . */
private MBeanServer server;
/** . */
private final Set<ManagementProvider> providers;
/** . */
private final ManageableContainer parent;
public ManageableContainer() {
this((PicoContainer) null);
}
public ManageableContainer(PicoContainer parent) {
this(new MX4JComponentAdapterFactory(), parent);
}
public ManageableContainer(ComponentAdapterFactory componentAdapterFactory, PicoContainer parent) {
super(getComponentAdapterFactory(componentAdapterFactory), parent);
// Yeah this is not pretty but a necessary evil to make it work
ManageableComponentAdapterFactory factory = hack.get();
factory.container = this;
hack.set(null);
// The synchronized wrapper, here will not impact runtime performances
// so it's fine
this.providers = Collections.synchronizedSet(new HashSet<ManagementProvider>());
//
ManagementContextImpl parentCtx = null;
if (parent instanceof ManageableContainer) {
ManageableContainer manageableParent = (ManageableContainer) parent;
parentCtx = manageableParent.managementContext;
}
//
this.parent = parent instanceof ManageableContainer ? (ManageableContainer) parent : null;
//
if (parentCtx != null) {
server = parentCtx.container.server;
managementContext = new ManagementContextImpl(parentCtx, this);
} else {
server = findMBeanServer();
managementContext = new ManagementContextImpl(this);
addProvider(new JMXManagementProvider(server));
}
}
public ManageableContainer(ComponentAdapterFactory componentAdapterFactory) {
this(componentAdapterFactory, null);
}
@Managed
@ManagedName("RegisteredComponentNames")
@ManagedDescription("Return the list of the registered component names")
public Set<String> getRegisteredComponentNames() throws PicoException {
Set<String> names = new HashSet<String>();
Collection<ComponentAdapter> adapters = getComponentAdapters();
for (ComponentAdapter adapter : adapters) {
Object key = adapter.getComponentKey();
String name = String.valueOf(key);
names.add(name);
}
return names;
}
private static ManageableComponentAdapterFactory getComponentAdapterFactory(ComponentAdapterFactory componentAdapterFactory) {
ManageableComponentAdapterFactory factory = new ManageableComponentAdapterFactory(componentAdapterFactory);
hack.set(factory);
return factory;
}
public ManagementContext getManagementContext() {
return managementContext;
}
public final MBeanServer getMBeanServer() {
return server;
}
/**
* This code to register the ComponentKey and ComponentAdapter to Pico
* and then uses the managementContext.register(ComponentInstance)
*/
public ComponentAdapter registerComponentInstance(Object componentKey, Object componentInstance) throws PicoRegistrationException {
ComponentAdapter adapter = super.registerComponentInstance(componentKey, componentInstance);
if (managementContext != null) {
managementContext.register(componentInstance);
// Register if it is a management provider
if (componentInstance instanceof ManagementProvider) {
ManagementProvider provider = (ManagementProvider) componentInstance;
addProvider(provider);
}
}
return adapter;
}
/**
* Returns the list of the providers which are relevant for this container.
*
* @return the providers
*/
Collection<ManagementProvider> getProviders() {
HashSet<ManagementProvider> allProviders = new HashSet<ManagementProvider>();
computeAllProviders(allProviders);
return allProviders;
}
private void computeAllProviders(Set<ManagementProvider> allProviders) {
if (parent != null) {
parent.computeAllProviders(allProviders);
}
//
allProviders.addAll(providers);
}
boolean addProvider(ManagementProvider provider) {
// Prevent double registration just in case...
if (providers.contains(provider)) {
return false;
}
//
providers.add(provider);
// Perform registration of already registered managed components
managementContext.install(provider);
//
return true;
}
}