/*
* Copyright 2001-2006 C:1 Financial Services GmbH
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License Version 2.1, as published by the Free Software Foundation.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
package de.finix.contelligent.core;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.RequiredModelMBean;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Appender;
import org.apache.log4j.Hierarchy;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.RollingFileAppender;
import com.adventnet.utils.jmx.Utilities;
import de.finix.contelligent.CallData;
import de.finix.contelligent.ComponentManager;
import de.finix.contelligent.ComponentPath;
import de.finix.contelligent.Contelligent;
import de.finix.contelligent.RelationsManager;
import de.finix.contelligent.Session;
import de.finix.contelligent.core.security.ContelligentSecurityManager;
import de.finix.contelligent.exception.ContelligentException;
import de.finix.contelligent.logging.LoggingService;
import de.finix.contelligent.xml.export.LocalXMLExport;
/**
* This mbean may be used to configure the Contelligent System at runtime, for
* example to change logging levels or the mode Contelligent runs in.
*/
public class ContelligentJMX implements ContelligentJMXMBean {
final static org.apache.log4j.Logger log = LoggingService.getLogger(ContelligentJMX.class);
final static public String CONTELLIGENT_MBEAN_DOMAIN = "Contelligent";
private static MBeanServer JMXServer;
public static MBeanServer getMBeanServer() throws Exception {
if (JMXServer == null) {
JMXServer = retrieveMBeanServer();
}
return JMXServer;
}
private static MBeanServer retrieveMBeanServer() throws Exception {
MBeanServer answer = null;
// try the JBoss way
List serverList = MBeanServerFactory.findMBeanServer(null);
Iterator servers = serverList.iterator();
if (servers.hasNext()) {
answer = (MBeanServer) servers.next();
log.info("found server: " + answer);
return answer;
}
// now the WebLogic 6.1 way
try {
Context context = new InitialContext();
answer = (MBeanServer) context.lookup("weblogic.management.server");
if (answer != null) {
return answer;
}
} catch (NamingException ignore) {
}
log.info("No MBean server found - starting new one ...");
answer = MBeanServerFactory.createMBeanServer();
log.info("Created new MBean server: " + answer);
String port = System.getProperty("jmx.port");
if (port == null) {
port = "8082";
}
final ObjectName name = new ObjectName("Server:name=HttpAdaptor, port=" + port);
try {
Class clazz = Class.forName("com.sun.jdmk.comm.HtmlAdaptorServer");
Object adaptor = clazz.newInstance();
Method method = clazz.getMethod("setPort", new Class[] { Integer.TYPE });
method.invoke(adaptor, new Object[] { new Integer(port) });
answer.registerMBean(adaptor, name);
method = clazz.getMethod("start", new Class[0]);
method.invoke(adaptor, new Object[0]);
Thread thread = ThreadFactory.getInstance().createThread("Http Adaptor Shutdown Thread", new Runnable() {
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
break;
}
}
log.info("Thread was interrupted, stopping http adaptor ...");
List serverList = MBeanServerFactory.findMBeanServer(null);
Iterator servers = serverList.iterator();
if (servers.hasNext()) {
MBeanServer server = (MBeanServer) servers.next();
try {
server.invoke(name, "stop", new Object[0], new String[0]);
} catch (Exception e) {
// ignore, if not found we have nothing to
// do
}
}
log.info("Http adaptor stopped");
}
});
thread.setDaemon(true);
thread.start();
log.info("Created and started http adaptor on port " + port);
} catch (Exception e) {
log.info("Could not create http adaptor (" + e.getMessage() + ")");
}
// ObjectInstance adaptor =
// answer.createMBean("com.sun.jdmk.comm.HtmlAdaptorServer", name,
// null);
// log.info("Created HttpAdaptor: " + adaptor);
// answer.setAttribute(name, new Attribute("Port", new Integer(port)));
// Object result = answer.invoke(name, "start", null, null);
// log.info("Started HttpAdaptor: " + result);
return answer;
}
public static void registerMBean(String name) throws ContelligentException {
ContelligentJMX instance = new ContelligentJMX();
try {
log.info("searching for mbean server ...");
ObjectName objectName = new ObjectName(CONTELLIGENT_MBEAN_DOMAIN, "name", name);
ObjectInstance inst = null;
try {
inst = getMBeanServer().getObjectInstance(objectName);
} catch (InstanceNotFoundException e) {
}
if (inst != null) {
try {
getMBeanServer().unregisterMBean(objectName);
log.info("Unregistered MBean already bound to name '" + objectName + "'");
} catch (JMException e) {
log.error("Could not unregister existing MBean '" + objectName + "':" + e, e);
return;
}
}
// InputStream jmxConfigStream =
// ((ContelligentImpl)ContelligentImpl.getInstance()).getContelligentConfigResourceAsStream();
String file = ContelligentImpl.getInstance().getContelligentDir() + Contelligent.DIR_CONFIG
+ Contelligent.JMX_CONFIGURATION_FILE;
ModelMBeanInfo mbeanInfo = Utilities.convertXmlToModelMBeanInfo(file);
RequiredModelMBean mbeanInstance = new RequiredModelMBean(mbeanInfo);
mbeanInstance.setManagedResource(instance, "ObjectReference");
ObjectInstance mbean = getMBeanServer().registerMBean(mbeanInstance, objectName);
log.info("registered '" + mbean.getObjectName() + "' in server '" + getMBeanServer() + "'.");
} catch (RuntimeException e) {
log.error("throwable catched while instanciating mbean '" + name + "'", e);
throw e;
} catch (Exception e) {
log.error("exception while registering service '" + name + "' as mbean: " + e, e);
throw new ContelligentException("[Exception while registering service '" + name + "' as mbean: " + e);
}
}
/**
* @param instance
* @return
*/
private static ModelMBeanInfo getMBeanInfoFor(ContelligentJMX instance) throws IntrospectionException,
SecurityException {
Class instanceClass = instance.getClass();
try {
return new ModelMBeanInfoSupport(instance.getClass().getName(),
"The Contelligent Adminstration JMX Interface",
new ModelMBeanAttributeInfo[] { new ModelMBeanAttributeInfo("actualCacheSize",
"the current Cache size", instanceClass.getMethod("getActualCacheSize", new Class[] {}),
null) }, null, null, null);
} catch (NoSuchMethodException e) {
log.error("undefined attribute exception: " + e, e);
}
return null;
}
public static void unregisterMBean(String name) throws ContelligentException {
try {
ObjectName objectName = new ObjectName(CONTELLIGENT_MBEAN_DOMAIN, "name", name);
getMBeanServer().unregisterMBean(objectName);
log.info("unregistered '" + objectName + "' in server '" + getMBeanServer() + "'.");
} catch (Exception e) {
log.error("exception while unregistering service '" + name + "': " + e, e);
throw new ContelligentException("Exception while unregistering service '" + name + "': " + e);
}
}
// ============================================================================-
// mbean methods
// ============================================================================-
/**
* Implementation of {@link ContelligentJMXMbean#checkDeadRelations}.
*/
public String checkDeadRelations(String managerName) {
try {
RelationsManager relationsManager = ContelligentImpl.getInstance().getRelationsManager();
ComponentManagerHierarchy hierarchy = ContelligentImpl.getInstance().getComponentManagerHierarchy();
ComponentManagerInternal manager = null;
if (managerName == null || managerName.length() == 0) {
manager = (ComponentManagerInternal) hierarchy.getRootComponentManager();
} else {
manager = (ComponentManagerInternal) hierarchy.getComponentManager(managerName);
}
long[] ids = manager.getIdsUpToRoot();
Map deadRelations = relationsManager.getDeadRelations(ComponentPath.ROOT_PATH, ids, true);
if (deadRelations.isEmpty()) {
return ("No dead relations found!");
} else {
StringBuffer sb = new StringBuffer();
sb.append("<pre>dead relations (source->target):\n");
Iterator entries = deadRelations.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
ComponentPath source = (ComponentPath) entry.getKey();
Iterator targets = ((Set) entry.getValue()).iterator();
while (targets.hasNext()) {
sb.append(source).append(" -> ").append(targets.next()).append("\n");
}
sb.append("\n");
}
sb.append("</pre>");
return sb.toString();
}
} catch (Exception e) {
log.error("Exception while checking for dead relations: ", e);
return ("Exception while checking for dead relations! " + e);
}
}
public String exportSystem(String baseDir, int txTimeout) {
Contelligent contelligent = ContelligentImpl.getInstance();
Session session = null;
try {
ContelligentSecurityManager securityManager = ContelligentSecurityManager.getInstance();
File base = new File(baseDir);
session = contelligent.beginSession(ContelligentSecurityManager.getSystemUser(), contelligent
.getRootComponentManager());
CallData callData = contelligent.createCallData(session);
contelligent.beginTx(txTimeout);
LocalXMLExport exporter = new LocalXMLExport(base);
exporter.exportSystem(contelligent, callData);
return ("Successfully exported Contelligent into directory '" + base + "'!");
} catch (Exception e) {
log.error("Exception while exporting system: ", e);
return ("Exception while exporting system: " + e);
} finally {
if (session != null) {
contelligent.invalidateSession(session);
}
try {
contelligent.commitTx();
} catch (Exception e) {
log.error("Exception while commit of transaction (ignored): ", e);
return ("Exception while commit of transaction (ignored): " + e);
}
}
}
public String exportPackage(String pkgName, String exportDir, int txTimeout, boolean omitDependsUpdate,
boolean isMinorChange, boolean autoArchive) {
ContelligentImpl contelligent = ContelligentImpl.getInstance();
Session session = null;
try {
ContelligentSecurityManager securityManager = ContelligentSecurityManager.getInstance();
File exportFileDir = new File(exportDir);
File toDir = new File(exportFileDir, pkgName);
session = contelligent.beginSession(ContelligentSecurityManager.getSystemUser(), contelligent
.getRootComponentManager());
CallData callData = contelligent.createCallData(session);
contelligent.beginTx(txTimeout);
contelligent.exportPackage(pkgName, toDir, !omitDependsUpdate, !isMinorChange, autoArchive, callData);
return ("Successfully exported package '" + pkgName + "' into directory '" + toDir + "'!");
} catch (Exception e) {
log.error("Exception while exporting package '" + pkgName + "': ", e);
return ("Exception while exporting package '" + pkgName + "': " + e);
} finally {
if (session != null) {
contelligent.invalidateSession(session);
}
try {
contelligent.commitTx();
} catch (Exception e) {
log.error("Exception while commit of transaction (ignored): ", e);
return ("Exception while commit of transaction (ignored): " + e);
}
}
}
/**
* Implementation of {@link ContelligentJMXMbean#getNumberOfSessions}.
*/
public String getNumberOfSessions() {
return String.valueOf(ContelligentImpl.getInstance().numberOfSessions());
}
/**
* Implementation of {@link ContelligentJMXMbean#getNumberOfClientSessions}.
*/
public String getNumberOfClientSessions() {
return String.valueOf(ContelligentImpl.getInstance().numberOfClientSessions());
}
public String getSystemProperty(String property) {
String p = System.getProperty(property);
return ((p == null) ? ("property '" + property + "' not set") : ("current value of property '" + property
+ "' is '" + p + "'."));
}
public String setSystemProperty(String key, String value) {
try {
System.setProperty(key, value);
return ("successfully set property '" + key + "' to '" + value + "'.");
} catch (Exception e) {
return ("Exception while setting property '" + key + "': " + e);
}
}
/**
* Implementation of {@link ContelligentJMXMbean#getMaxCacheSize}.
*/
public String getMaxCacheSize() {
ComponentManager rootManager = ContelligentImpl.getInstance().getRootComponentManager();
if (rootManager instanceof ComponentManagerInternal) {
return String.valueOf(((ComponentManagerInternal) rootManager).getMaxCacheSize());
} else {
return "The current rootManager does not support this feature!";
}
}
/**
* Implementation of {@link ContelligentJMXMbean#setMaxCacheSize}.
*/
public String setMaxCacheSize(int maxSize) {
ComponentManager rootManager = ContelligentImpl.getInstance().getRootComponentManager();
if (rootManager instanceof ComponentManagerInternal) {
((ComponentManagerInternal) rootManager).setMaxCacheSize(maxSize);
return ("maximum cache-size set to " + ((ComponentManagerInternal) rootManager).getMaxCacheSize());
} else {
return "The current rootManager does not support this feature!";
}
}
public String getSmallBinaryThreshold() {
return String.valueOf(ContelligentImpl.getInstance().getSmallBinaryThreshold());
}
public String setSmallBinaryThreshold(int threshold) {
ContelligentImpl.getInstance().setSmallBinaryThreshold(threshold);
return "small binary threshold set to " + String.valueOf(ContelligentImpl.getInstance().getSmallBinaryThreshold());
}
public String getCacheCalls() {
ComponentManager rootManager = ContelligentImpl.getInstance().getRootComponentManager();
if (rootManager instanceof ComponentManagerInternal) {
return String.valueOf(((ComponentManagerInternal) rootManager).getCacheCalls());
} else {
return "The current rootManager does not support this feature!";
}
}
public String getCacheMisses() {
ComponentManager rootManager = ContelligentImpl.getInstance().getRootComponentManager();
if (rootManager instanceof ComponentManagerInternal) {
return String.valueOf(((ComponentManagerInternal) rootManager).getCacheMisses());
} else {
return "The current rootManager does not support this feature!";
}
}
/**
* Implementation of {@link ContelligentJMXMbean#getActualCacheSize}.
*/
public String getActualCacheSize() {
ComponentManager rootManager = ContelligentImpl.getInstance().getRootComponentManager();
if (rootManager instanceof ComponentManagerInternal) {
return ("" + ((ComponentManagerInternal) rootManager).getActualCacheSize());
} else {
return "The current rootManager does not support this feature!";
}
}
/**
* Implementation of {@link ContelligentJMXMbean#invalidateCache}.
*/
public void invalidateCache() {
BasicComponentManager manager = (BasicComponentManager) ContelligentImpl.getInstance()
.getRootComponentManager();
manager.invalidatePath(ComponentPath.ROOT_PATH, true);
}
/**
* Implementation of {@link ContelligentJMXMBean#invalidateCache}.
*/
public String invalidateCache(String managerName) {
BasicComponentManager manager = (BasicComponentManager) ContelligentImpl.getInstance().getComponentManager(
managerName);
if (manager != null) {
manager.invalidatePath(ComponentPath.ROOT_PATH, true);
return ("Cache of manager '" + managerName + "' invalidated.");
} else {
return ("manager '" + managerName + "' does not exist!");
}
}
/**
* Implementation of {@link ContelligentJMXMBean#invalidatePath}.
*/
public String invalidatePath(String path) {
BasicComponentManager manager = (BasicComponentManager) ContelligentImpl.getInstance()
.getRootComponentManager();
manager.invalidatePath(new ComponentPath(path), true);
return ("Cache path '" + path + "' invalidated.");
}
/**
* Implementation of {@link ContelligentJMXMBean#getContelligentMode}. It
* simply calls {@link Contelligent#getContelligentMode}.
*/
public String getContelligentMode() {
return ContelligentImpl.getInstance().getContelligentMode();
}
/**
* Implementation of {@link ContelligentJMXMBean#setContelligentMode}. Just
* passes the given string to {@link Contelligent#setContelligentMode}.
*/
public String setContelligentMode(String mode) {
return ContelligentImpl.getInstance().setContelligentMode(mode);
}
/**
* This is the implementation of
* {@link ContelligentJMXMBean#getCurrentLogLevels}, look there for a
* description.
*
* @return a <code>String[]</code> value
*/
public String[] getCurrentLogLevels() {
Enumeration loggers = LoggingService.getHierarchy().getCurrentLoggers();
SortedSet names = new TreeSet();
// List names = new Vector();
while (loggers.hasMoreElements()) {
Logger logger = (Logger) loggers.nextElement();
Level p = logger.getLevel();
if (p != null)
names.add(logger.getName() + " [" + p.toString() + "]");
else
names.add(logger.getName());
}
return (String[]) names.toArray(new String[0]);
}
/**
* This is the implementation of {@link ContelligentJMXMBean#getLevel},
* look there for a description.
*
* @param loggerName
* a <code>String</code> value
* @return a <code>String</code> value
*/
public String getLogLevel(String loggerName) {
Logger logger = null;
Hierarchy hierarchy = LoggingService.getHierarchy();
if (loggerName == null || loggerName.length() == 0)
logger = hierarchy.getRootLogger();
else
logger = hierarchy.exists(loggerName);
if (logger == null) {
return ("logger '" + loggerName + "' doesn't exist");
} else {
return getLevel(logger);
}
}
/**
* This is the implementation of
* {@link ContelligentJMXMBean#getEffectiveLevel}, look there for a
* description.
*
* @param loggerName
* a <code>String</code> value
* @return a <code>String</code> value
*/
public String getEffectiveLogLevel(String loggerName) {
Logger logger = null;
Hierarchy hierarchy = LoggingService.getHierarchy();
if (loggerName == null || loggerName.length() == 0)
logger = hierarchy.getRootLogger();
else
logger = hierarchy.exists(loggerName);
if (logger == null) {
return ("logger '" + loggerName + "' doesn't exist");
} else {
return getEffectiveLevel(logger);
}
}
/**
* This is the implementation of {@link ContelligentJMXMBean#setLevel},
* look there for a description.
*
* @param loggerName
* a <code>String</code> value
* @param level
* a <code>String</code> value
* @return a <code>String</code> value
*/
public String setLogLevel(String loggerName, String level) {
Logger logger = null;
Hierarchy hierarchy = LoggingService.getHierarchy();
if (loggerName == null || loggerName.length() == 0)
logger = hierarchy.getRootLogger();
else
logger = hierarchy.exists(loggerName);
if (logger != null) {
logger.setLevel(Level.toLevel(level));
return getLevel(logger);
} else {
return ("logger '" + loggerName + "' doesn't exist");
}
}
/**
* This is the implementation of {@link ContelligentJMXMBean#resetLevel},
* look there for a description.
*
* @param loggerName
* a <code>String</code> value
* @return a <code>String</code> value
*/
public String resetLogLevel(String loggerName) {
if (loggerName == null || loggerName.length() == 0)
return ("cannot reset the level of the root logger!");
Logger logger = LoggingService.getHierarchy().exists(loggerName);
if (logger != null) {
logger.setLevel(null);
return getEffectiveLevel(logger);
} else {
return ("logger '" + loggerName + "' doesn't exist");
}
}
/**
* This is the implementation of {@link ContelligentJMXMBean#rollOver},
* look there for a description.
*
* @param loggerName
* a <code>String</code> value
* @return a <code>String</code> value describing the success or failure
* of this method.
*/
public String rollOverLog(String loggerName) {
Logger logger = null;
Hierarchy hierarchy = LoggingService.getHierarchy();
if (loggerName == null || loggerName.length() == 0)
logger = hierarchy.getRootLogger();
else
logger = hierarchy.exists(loggerName);
if (logger != null) {
StringBuffer result = new StringBuffer(64);
boolean foundOne = false;
Enumeration appenders = logger.getAllAppenders();
while (appenders.hasMoreElements()) {
Appender ap = (Appender) appenders.nextElement();
if (ap instanceof RollingFileAppender) {
((RollingFileAppender) ap).rollOver();
result.append("... invoked method 'rollOver' of appender <B>").append(ap.getName()).append(
"</B>.<BR>");
foundOne = true;
}
}
if (foundOne) {
result.append("[got appenders from logger '").append(logger.getName()).append("']");
return result.toString();
} else {
return ("logger '" + logger.getName() + "' has no 'RollingFileAppender' associated!");
}
} else {
return ("logger '" + loggerName + "' doesn't exist");
}
}
public String dumpVmInfo() {
ThreadGroup topThreadGroup = Thread.currentThread().getThreadGroup();
while (topThreadGroup.getParent() != null)
topThreadGroup = topThreadGroup.getParent();
ThreadGroup[] allGroups = new ThreadGroup[1000];
int nr = topThreadGroup.enumerate(allGroups, true);
StringBuffer buffer = new StringBuffer();
dumpThreadGroupInfo(topThreadGroup, buffer);
for (int i = 0; i < nr; i++) {
dumpThreadGroupInfo(allGroups[i], buffer);
}
return buffer.toString();
}
private void dumpThreadGroupInfo(ThreadGroup tg, StringBuffer buffer) {
String parentName = (tg.getParent() == null ? "NO PARENT" : tg.getParent().getName());
buffer.append("----------\n");
buffer.append("Group:" + tg.getName() + " Parent:" + parentName + (tg.isDaemon() ? " DAEMON" : " ")
+ (tg.isDestroyed() ? " DESTROYED\n" : " \n"));
System.out.println("----------");
System.out.println("Group:" + tg.getName() + " Parent:" + parentName + (tg.isDaemon() ? " DAEMON" : " ")
+ (tg.isDestroyed() ? " DESTROYED \n" : " \n"));
Thread[] allThreads = new Thread[1000];
int threadCount = tg.enumerate(allThreads, false);
for (int i = 0; i < threadCount; i++) {
buffer.append("Thread:" + allThreads[i].getName() + (allThreads[i].isDaemon() ? " DAEMON" : " ")
+ (allThreads[i].isAlive() ? " ALIVE \n" : " DEAD \n"));
System.out.println("Thread:" + allThreads[i].getName() + (allThreads[i].isDaemon() ? " DAEMON" : " ")
+ (allThreads[i].isAlive() ? " ALIVE" : " DEAD "));
}
}
public String reloadDynamicConfiguration() {
ContelligentImpl.getInstance().reloadDynamicConfiguration();
return "Configuration reloaded.";
}
// ============================================================================-
// non-public methods
// ============================================================================-
/**
* Returns a <code>String</code> containing information about the
* <code>Level</code> the given <code>Logger</code> has assigned.
*
* @param logger
* a non-null <code>Logger</code> value
* @return a <code>String</code> value
*/
private String getLevel(Logger logger) {
Level p = logger.getLevel();
if (p == null) {
return ("logger '" + logger.getName() + "' has no level assigned.");
} else {
return ("logger '" + logger.getName() + "' has level " + p.toString());
}
}
/**
* Returns a <code>String</code> containing information about the
* effectived <code>Level</code> the given <code>Logger</code> currently
* has, that is either the assigned level or the inherited one.
*
* @param logger
* a non-null <code>Logger</code> value
* @return a <code>String</code> value
*/
private String getEffectiveLevel(Logger logger) {
Level p = logger.getEffectiveLevel();
return ("logger '" + logger.getName() + "' has (effective) level " + p.toString());
}
}
|