/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.naming;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.jboss.ejb.Container;
import org.jboss.ejb.EjbModule;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.web.AbstractWebDeployerMBean;
import org.jboss.web.WebApplication;
/**
* A simple utlity mbean that allows one to recursively list the default
* JBoss InitialContext.
*
* @author <a href="mailto:Scott.Stark@jboss.org">Scott Stark</a>.
* @author Vladimir Blagojevic <vladimir@xisnext.2y.net>
* @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
* @version <tt>$Revision: 81030 $</tt>
* @jmx:mbean name="jboss:type=JNDIView"
* extends="org.jboss.system.ServiceMBean"
*/
public class JNDIView
extends ServiceMBeanSupport
implements JNDIViewMBean
{
/**
* The HANamingService attributes, order is significant in getHAUrl()
*/
protected static final String[] g_haAttributes = new String[]{"BindAddress", "Port"};
/**
* The HANamingService service name
*/
protected String haNamingService;
/**
* Provided for JMX compliance.
*/
public JNDIView()
{
}
/**
* List deployed application java:comp namespaces, the java:
* namespace as well as the global InitialContext JNDI namespace.
*
* @param verbose, if true, list the class of each object in addition to its name
* @jmx:managed-operation
*/
public String list(boolean verbose)
{
StringBuffer buffer = new StringBuffer(4096);
Context context = null;
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
try
{
// Get all deployed web applications so that we can list their
// java: namespaces which are ClassLoader local
Iterator it = (Iterator) server.getAttribute(AbstractWebDeployerMBean.OBJECT_NAME, "DeployedApplications");
if (it.hasNext() == true)
{
buffer.append("<h1>Web Applications</h1>\n");
}
while (it.hasNext() == true)
{
WebApplication webApplication = (WebApplication) it.next();
Thread.currentThread().setContextClassLoader(webApplication.getMetaData().getENCLoader());
buffer.append("<h2>java:comp namespace of the " + webApplication.getCanonicalName()
+ " application:</h2>\n");
try
{
context = new InitialContext();
context = (Context) context.lookup("java:comp");
}
catch (NamingException e)
{
buffer.append("Failed on lookup, " + e.toString(true));
formatException(buffer, e);
continue;
}
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
}
catch (Throwable e)
{
log.debug("Unable to list web applications ENC", e);
}
// Get all deployed applications so that we can list their
// java: namespaces which are ClassLoader local
Set ejbModules = null;
try
{
ejbModules = server.queryNames(EjbModule.EJB_MODULE_QUERY_NAME, null);
}
catch (Throwable e)
{
log.error("getDeployedApplications failed", e);
buffer.append("Failed to getDeployedApplications\n");
formatException(buffer, e);
buffer.insert(0, "<pre>");
buffer.append("</pre>");
return buffer.toString();
}
// List each application JNDI namespace
HashSet ejb2Ids = new HashSet();
for (Iterator i = ejbModules.iterator(); i.hasNext();)
{
ObjectName app = (ObjectName) i.next();
String module = app.getKeyProperty("module");
if (module == null)
module = app.toString();
buffer.append("<h1>Ejb 2.1 Module: " + module + "</h1>\n");
try
{
Collection containers = (Collection) server.getAttribute(app, "Containers");
for (Iterator iter = containers.iterator(); iter.hasNext();)
{
Container con = (Container) iter.next();
/* Set the thread class loader to that of the container as
the class loader is used by the java: context object
factory to partition the container namespaces.
*/
Thread.currentThread().setContextClassLoader(con.getClassLoader());
String bean = con.getBeanMetaData().getEjbName();
Object on = con.getJmxName();
buffer.append("<h2>java:comp namespace of the " + bean + " bean:</h2>\n");
context = ENCFactory.getEncById().get(on);
ejb2Ids.add(on);
if (context == null)
{
buffer.append("Failed to retrieve context for " + on);
continue;
}
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
}
catch (Throwable e)
{
log.error("getConainers failed", e);
buffer.append("<pre>");
buffer.append("Failed to get ejbs in module\n");
formatException(buffer, e);
buffer.append("</pre>");
}
}
buffer.append("<h1> Other components with java:comp namespace</h1>\n");
for (Object key : ENCFactory.getEncById().keySet())
{
// skip EJB 2.1 keys
if (ejb2Ids.contains(key)) continue;
context = ENCFactory.getEncById().get(key);
buffer.append("<h2>java:comp namespace of the component " + key + " :</h2>\n");
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
// List the java: namespace
Thread.currentThread().setContextClassLoader(currentLoader);
try
{
context = new InitialContext();
context = (Context) context.lookup("java:");
buffer.append("<h1>java: Namespace</h1>\n");
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
catch (NamingException e)
{
log.error("lookup for java: failed", e);
buffer.append("Failed to get InitialContext, " + e.toString(true));
formatException(buffer, e);
}
// List the global JNDI namespace
try
{
context = new InitialContext();
buffer.append("<h1>Global JNDI Namespace</h1>\n");
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
catch (NamingException e)
{
log.error("Failed to get InitialContext", e);
buffer.append("Failed to get InitialContext, " + e.toString(true));
formatException(buffer, e);
}
// List the HA-JNDI namespace if the HAJNDI service is available
try
{
String url = getHAUrl();
if (url != null)
{
java.util.Hashtable env = new java.util.Hashtable();
env.put(Context.PROVIDER_URL, url);
context = new InitialContext(env);
buffer.append("<h1>HA-JNDI Namespace</h1>\n");
buffer.append("<pre>\n");
list(context, " ", buffer, verbose);
buffer.append("</pre>\n");
}
}
catch (NamingException ne)
{
log.error("Failed to get InitialContext", ne);
buffer.append("Failed to get InitialContext, " + ne.toString(true));
formatException(buffer, ne);
}
return buffer.toString();
}
/**
* List deployed application java:comp namespaces, the java:
* namespace as well as the global InitialContext JNDI namespace in a
* XML Format.
*
* @jmx:managed-operation
*/
public String listXML()
{
StringBuffer buffer = new StringBuffer(4096);
Set ejbModules = null;
Context context = null;
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
openJndiTag(buffer);
try
{
// Get all deployed web applications so that we can list their
// java: namespaces which are ClassLoader local
Iterator it = (Iterator) server.getAttribute(AbstractWebDeployerMBean.OBJECT_NAME, "DeployedApplications");
while (it.hasNext() == true)
{
WebApplication webApplication = (WebApplication) it.next();
openWebModuleTag(buffer, webApplication.getCanonicalName());
Thread.currentThread().setContextClassLoader(webApplication.getMetaData().getENCLoader());
try
{
context = new InitialContext();
context = (Context) context.lookup("java:comp");
listXML(context, buffer);
}
catch (NamingException e)
{
buffer.append("Failed on lookup, " + e.toString(true));
formatException(buffer, e);
continue;
}
finally
{
closeWebModuleTag(buffer);
}
}
}
catch (Throwable e)
{
log.debug("Unable to list web applications ENC", e);
}
/* Get all deployed applications so that we can list their
java: namespaces which are ClassLoader local
*/
try
{
ejbModules = server.queryNames(EjbModule.EJB_MODULE_QUERY_NAME, null);
}
catch (Exception e)
{
log.error("getDeployedApplications failed", e);
appendErrorTag(buffer,
"Failed to getDeployedApplications " + e.toString());
closeJndiTag(buffer);
return buffer.toString();
}
HashSet ejb2Ids = new HashSet();
// List each application JNDI namespace
for (Iterator i = ejbModules.iterator(); i.hasNext();)
{
ObjectName app = (ObjectName) i.next();
openEjbModuleTag(buffer, app.getKeyProperty("url"));
Collection containers = null;
try
{
containers = (Collection) server.getAttribute(app, "Containers");
}
catch (Throwable t)
{
log.error("getContainers failed", t);
appendPreExceptionTag(buffer, "Failed to get ejbs in module", t);
}
for (Iterator iter = containers.iterator(); iter.hasNext();)
{
Container con = (Container) iter.next();
Object on = con.getJmxName();
ejb2Ids.add(on);
/* Set the thread class loader to that of the container as
the class loader is used by the java: context object
factory to partition the container namespaces.
*/
Thread.currentThread().setContextClassLoader(con.getClassLoader());
String bean = con.getBeanMetaData().getEjbName();
openContextTag(buffer);
appendBeanTag(buffer, bean);
Context context1 = ENCFactory.getEncById().get(on);
if (context1 == null)
{
appendErrorTag(buffer,
"Failed to find ENC of EJB: " + on);
context1 = null;
}
if (context1 != null)
{
try
{
listXML(context1, buffer);
}
catch (Throwable t)
{
appendErrorTag(buffer,
"Failed on list contents, " + t.toString());
}
} // if ( context != null )
closeContextTag(buffer);
}
closeEjbModuleTag(buffer);
}
//buffer.append("<h1> Other components with java:comp namespace</h1>\n");
for (Object key : ENCFactory.getEncById().keySet())
{
// skip EJB 2.1 keys
if (ejb2Ids.contains(key)) continue;
context = ENCFactory.getEncById().get(key);
buffer.append("<other-encs>");
openContextTag(buffer);
appendBeanTag(buffer, key.toString());
listXML(context, buffer);
closeContextTag(buffer);
buffer.append("</other-encs>");
}
// List the java: namespace
Thread.currentThread().setContextClassLoader(currentLoader);
try
{
context = new InitialContext();
context = (Context) context.lookup("java:");
}
catch (NamingException e)
{
log.error("Failed to get InitialContext for (java:)", e);
appendErrorTag(buffer,
"Failed to get InitialContext for (java:), " +
e.toString(true));
}
if (context != null)
{
openContextTag(buffer);
appendJavaNameTag(buffer);
try
{
listXML(context, buffer);
}
catch (Throwable t)
{
log.error("Failed to list contents of (java:)", t);
appendErrorTag(buffer,
"Failed to list contents of (java:), " +
t.toString());
}
closeContextTag(buffer);
} // if ( context != null )
// List the global JNDI namespace
try
{
context = new InitialContext();
}
catch (NamingException e)
{
log.error("Failed to get InitialContext", e);
appendErrorTag(buffer,
"Failed to get InitialContext, " + e.toString(true));
}
if (context != null)
{
openContextTag(buffer);
appendGlobalNameTag(buffer);
try
{
listXML(context, buffer);
}
catch (Throwable t)
{
log.error("Failed to list global contents ", t);
appendErrorTag(buffer,
"Failed to list global contents, " + t.toString());
}
closeContextTag(buffer);
} // if ( context != null )
// List the HA-JNDI namespace if the HAJNDI service is available
String url = null;
try
{
url = getHAUrl();
if (url != null)
{
java.util.Hashtable env = new java.util.Hashtable();
env.put(Context.PROVIDER_URL, url);
context = new InitialContext(env);
}
}
catch (NamingException e)
{
log.error("Failed to get InitialContext", e);
appendErrorTag(buffer,
"Failed to get InitialContext, " + e.toString(true));
}
if (url != null && context != null)
{
openContextTag(buffer);
appendHANameTag(buffer);
try
{
listXML(context, buffer);
}
catch (Throwable t)
{
log.error("Failed to list HA-JNDI contents ", t);
appendErrorTag(buffer,
"Failed to list HA-JNDI contents, " + t.toString());
}
closeContextTag(buffer);
} // if ( url != null && context != null )
closeJndiTag(buffer);
return buffer.toString();
}
public String getHANamingService()
{
return haNamingService;
}
public void setHANamingService(String serviceName)
{
haNamingService = serviceName;
}
protected ObjectName getObjectName(MBeanServer server, ObjectName name)
throws javax.management.MalformedObjectNameException
{
return name == null ? OBJECT_NAME : name;
}
private void list(Context ctx, String indent, StringBuffer buffer, boolean verbose)
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
NamingEnumeration ne = ctx.list("");
while (ne.hasMore())
{
NameClassPair pair = (NameClassPair) ne.next();
log.trace("pair: " + pair);
String name = pair.getName();
String className = pair.getClassName();
boolean recursive = false;
boolean isLinkRef = false;
boolean isProxy = false;
Class c = null;
try
{
c = loader.loadClass(className);
log.trace("type: " + c);
if (Context.class.isAssignableFrom(c))
recursive = true;
if (LinkRef.class.isAssignableFrom(c))
isLinkRef = true;
isProxy = Proxy.isProxyClass(c);
}
catch (ClassNotFoundException cnfe)
{
// If this is a $Proxy* class its a proxy
if (className.startsWith("$Proxy"))
{
isProxy = true;
// We have to get the class from the binding
try
{
Object p = ctx.lookup(name);
c = p.getClass();
}
catch (NamingException e)
{
Throwable t = e.getRootCause();
if (t instanceof ClassNotFoundException)
{
// Get the class name from the exception msg
String msg = t.getMessage();
if (msg != null)
{
// Reset the class name to the CNFE class
className = msg;
}
}
}
}
}
buffer.append(indent + " +- " + name);
// Display reference targets
if (isLinkRef)
{
// Get the
try
{
log.trace("looking up LinkRef; name=" + name);
Object obj = ctx.lookupLink(name);
log.trace("Object type: " + obj.getClass());
LinkRef link = (LinkRef) obj;
buffer.append("[link -> ");
buffer.append(link.getLinkName());
buffer.append(']');
}
catch (Throwable t)
{
log.debug("Invalid LinkRef for: " + name, t);
buffer.append("invalid]");
}
}
// Display proxy interfaces
if (isProxy)
{
buffer.append(" (proxy: " + pair.getClassName());
if (c != null)
{
Class[] ifaces = c.getInterfaces();
buffer.append(" implements ");
for (int i = 0; i < ifaces.length; i++)
{
buffer.append(ifaces[i]);
buffer.append(',');
}
buffer.setCharAt(buffer.length() - 1, ')');
}
else
{
buffer.append(" implements " + className + ")");
}
}
else if (verbose)
{
buffer.append(" (class: " + pair.getClassName() + ")");
}
buffer.append('\n');
if (recursive)
{
try
{
Object value = ctx.lookup(name);
if (value instanceof Context)
{
Context subctx = (Context) value;
list(subctx, indent + " | ", buffer, verbose);
}
else
{
buffer.append(indent + " | NonContext: " + value);
buffer.append('\n');
}
}
catch (Throwable t)
{
buffer.append("Failed to lookup: " + name + ", errmsg=" + t.getMessage());
buffer.append('\n');
}
}
}
ne.close();
}
catch (NamingException ne)
{
buffer.append("error while listing context " + ctx.toString() + ": " + ne.toString(true));
formatException(buffer, ne);
}
}
private void listXML(Context ctx, StringBuffer buffer)
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
NamingEnumeration ne = ctx.list("");
while (ne.hasMore())
{
NameClassPair pair = (NameClassPair) ne.next();
boolean recursive = false;
boolean isLinkRef = false;
try
{
Class c = loader.loadClass(pair.getClassName());
if (Context.class.isAssignableFrom(c))
recursive = true;
if (LinkRef.class.isAssignableFrom(c))
isLinkRef = true;
}
catch (ClassNotFoundException cnfe)
{
}
String name = pair.getName();
if (isLinkRef)
{
Object obj = null;
LinkRef link = null;
try
{
obj = ctx.lookupLink(name);
link = (LinkRef) obj;
}
catch (Throwable t)
{
log.error("Invalid LinkRef for: " + name, t);
appendLinkRefErrorTag(buffer);
}
appendLinkRefTag(buffer, link, pair);
}
else
{
if (recursive)
{
Object value = null;
try
{
value = ctx.lookup(name);
}
catch (Throwable t)
{
appendErrorTag(buffer,
"Failed to lookup: " + name +
", errmsg=" + t.getMessage());
}
if (value instanceof Context)
{
Context subctx = (Context) value;
openContextTag(buffer);
appendNCPTag(buffer, pair);
try
{
listXML(subctx, buffer);
}
catch (Throwable t)
{
appendErrorTag(buffer,
"Failed to list contents of: " + name +
", errmsg=" + t.getMessage());
}
closeContextTag(buffer);
}
else
{
appendNonContextTag(buffer, pair);
}
}
else
{
appendLeafTag(buffer, pair);
}
}
}
ne.close();
}
catch (NamingException ne)
{
appendErrorTag(buffer,
"error while listing context " +
ctx.toString() + ": " + ne.toString(true));
}
}
private void openJndiTag(StringBuffer buffer)
{
buffer.append("<jndi>\n");
}
private void closeJndiTag(StringBuffer buffer)
{
buffer.append("</jndi>\n");
}
private void openWebModuleTag(StringBuffer buffer, String file)
{
buffer.append("<webmodule>\n");
buffer.append("<file>").append(file).append("</file>\n");
}
private void closeWebModuleTag(StringBuffer buffer)
{
buffer.append("</webmodule>\n");
}
private void openEjbModuleTag(StringBuffer buffer, String file)
{
buffer.append("<ejbmodule>\n");
buffer.append("<file>" + file + "</file>\n");
}
private void closeEjbModuleTag(StringBuffer buffer)
{
buffer.append("</ejbmodule>\n");
}
private void appendPreExceptionTag(StringBuffer buffer,
String msg,
Throwable t)
{
buffer.append("<pre>\n" + msg + "\n");
formatException(buffer, t);
buffer.append("</pre>\n");
}
private void appendBeanTag(StringBuffer buffer, String bean)
{
buffer.append("<name>java:comp</name>\n");
buffer.append("<attribute name='bean'>" + bean + "</attribute>\n");
}
private void appendJavaNameTag(StringBuffer buffer)
{
buffer.append("<name>java:</name>\n");
}
private void appendGlobalNameTag(StringBuffer buffer)
{
buffer.append("<name>Global</name>\n");
}
private void appendHANameTag(StringBuffer buffer)
{
buffer.append("<name>HA</name>\n");
}
private void appendLinkRefTag(StringBuffer buffer,
LinkRef link,
NameClassPair ncp)
{
buffer.append("<link-ref>\n");
buffer.append("<name>" + ncp.getName() + "</name>\n");
try
{
String lName = link.getLinkName();
buffer.append("<link>" + lName + "</link>\n");
}
catch (NamingException e)
{
appendErrorTag(buffer,
"Failed to getLinkName, " + e.toString(true));
}
buffer.append("<attribute name='class'>" + ncp.getClassName() +
"</attribute>\n");
buffer.append("</link-ref>\n");
}
private void appendLinkRefErrorTag(StringBuffer buffer)
{
buffer.append("<link-ref>\n");
buffer.append("<name>Invalid</name>\n");
buffer.append("</link-ref>\n");
}
private void openContextTag(StringBuffer buffer)
{
buffer.append("<context>\n");
}
private void closeContextTag(StringBuffer buffer)
{
buffer.append("</context>\n");
}
private void appendNonContextTag(StringBuffer buffer, NameClassPair ncp)
{
buffer.append("<non-context>\n");
appendNCPTag(buffer, ncp);
buffer.append("</non-context>\n");
}
private void appendLeafTag(StringBuffer buffer, NameClassPair ncp)
{
buffer.append("<leaf>\n");
appendNCPTag(buffer, ncp);
buffer.append("</leaf>\n");
}
private void appendNCPTag(StringBuffer buffer, NameClassPair ncp)
{
buffer.append("<name>" + ncp.getName() + "</name>\n");
buffer.append("<attribute name='class'>" + ncp.getClassName() +
"</attribute>\n");
}
private void appendErrorTag(StringBuffer buffer, String msg)
{
buffer.append("<error>\n");
buffer.append("<message>" + msg + "</message>\n");
buffer.append("</error>\n");
}
private void formatException(StringBuffer buffer, Throwable t)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
buffer.append("<pre>\n");
t.printStackTrace(pw);
buffer.append(sw.toString());
buffer.append("</pre>\n");
}
private String getHAUrl()
{
String bindAddress = null;
String portNumber = null;
AttributeList list = getHAJndiAttributes();
// list will be null if HA-JNDI service couldn't be retrieved
if (list == null)
return null;
// list[0] is BindAddress
Object o = list.get(0);
if (o != null)
bindAddress = ((Attribute) o).getValue().toString();
// list[1] is Port
o = list.get(1);
if (o != null)
portNumber = ((Attribute) o).getValue().toString();
if (bindAddress != null && portNumber != null)
return "jnp://" + bindAddress + ":" + portNumber;
return null;
}
private AttributeList getHAJndiAttributes()
{
if (haNamingService == null)
{
// HA-JNDI is not deployed, so there will be no attributes
return null;
}
try
{
ObjectName name = new ObjectName(haNamingService);
return server.getAttributes(name, g_haAttributes);
}
catch (InstanceNotFoundException e1)
{
// this is expected if HA-JNDI service isn't deployed - do not report it
return null;
}
catch (Exception e)
{
// this is not expected - report it
log.error("JNDIView.getHAJndiAttributes() failed", e);
return null;
}
}
}