com.googlecode.psiprobe.beans.ResourceResolverBean.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.psiprobe.beans.ResourceResolverBean.java

Source

/*
 * Licensed under the GPL License.  You may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
package com.googlecode.psiprobe.beans;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.catalina.Context;
import org.apache.catalina.Server;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.modeler.Registry;
import org.apache.catalina.core.StandardServer;

import com.googlecode.psiprobe.model.ApplicationResource;
import com.googlecode.psiprobe.model.DataSourceInfo;
import com.googlecode.psiprobe.AbstractTomcatContainer;

/**
 * 
 * @author Vlad Ilyushchenko
 * @author Andy Shapoval
 * @author Mark Lewis
 * @author Henry Caballero
 */
public class ResourceResolverBean implements ResourceResolver {

    private Log logger = LogFactory.getLog(getClass());

    /**
     * The default resource prefix for JNDI objects in the global scope:
     * <code>java:</code>.
     */
    public static final String DEFAULT_GLOBAL_RESOURCE_PREFIX = "";

    /**
     * The default resource prefix for objects in a private application scope:
     * <code>java:comp/env/</code>.
     */
    public static final String DEFAULT_RESOURCE_PREFIX = DEFAULT_GLOBAL_RESOURCE_PREFIX + "java:comp/env/";

    private List datasourceMappers;

    public List getApplicationResources() throws NamingException {
        logger.info("Reading GLOBAL resources");
        List resources = new ArrayList();

        MBeanServer server = getMBeanServer();
        if (server != null) {
            try {
                Set dsNames = server.queryNames(new ObjectName("Catalina:type=Resource,resourcetype=Global,*"),
                        null);
                for (Iterator it = dsNames.iterator(); it.hasNext();) {
                    ObjectName objectName = (ObjectName) it.next();
                    ApplicationResource resource = new ApplicationResource();

                    logger.info("reading resource: " + objectName);
                    resource.setName(getStringAttribute(server, objectName, "name"));
                    resource.setType(getStringAttribute(server, objectName, "type"));
                    resource.setScope(getStringAttribute(server, objectName, "scope"));
                    resource.setAuth(getStringAttribute(server, objectName, "auth"));
                    resource.setDescription(getStringAttribute(server, objectName, "description"));

                    lookupResource(resource, true, true);

                    resources.add(resource);
                }
            } catch (Exception e) {
                logger.error("There was an error querying JMX server:", e);
            }
        }
        return resources;
    }

    public synchronized List getApplicationResources(Context context, ContainerWrapperBean containerWrapper)
            throws NamingException {

        List resourceList = new ArrayList();

        boolean contextAvailable = containerWrapper.getTomcatContainer().getAvailable(context);
        if (contextAvailable) {

            logger.info("Reading CONTEXT " + context.getName());

            boolean contextBound = false;

            try {
                ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).bindToContext(context);
                contextBound = true;
            } catch (NamingException e) {
                logger.error("Cannot bind to context. useNaming=false ?");
                logger.debug("  Stack trace:", e);
            }

            try {
                containerWrapper.getTomcatContainer().addContextResource(context, resourceList, contextBound);

                containerWrapper.getTomcatContainer().addContextResourceLink(context, resourceList, contextBound);
                for (int i = 0; i < resourceList.size(); i++) {
                    lookupResource((ApplicationResource) resourceList.get(i), contextBound, false);
                }

            } finally {
                if (contextBound) {
                    ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).unbindFromContext(context);
                }
            }
        }

        return resourceList;
    }

    public void lookupResource(ApplicationResource resource, boolean contextBound, boolean global) {
        DataSourceInfo dataSourceInfo = null;
        if (contextBound) {
            try {
                javax.naming.Context ctx = !global ? new InitialContext() : getGlobalNamingContext();
                String jndiName = resolveJndiName(resource.getName(), global);
                Object o = ctx.lookup(jndiName);
                resource.setLookedUp(true);
                for (Iterator it = datasourceMappers.iterator(); it.hasNext();) {
                    DatasourceAccessor accessor = (DatasourceAccessor) it.next();
                    dataSourceInfo = accessor.getInfo(o);
                    if (dataSourceInfo != null) {
                        break;
                    }
                }

            } catch (Throwable e) {
                resource.setLookedUp(false);
                dataSourceInfo = null;
                logger.error("Failed to lookup: " + resource.getName(), e);
                //
                // make sure we always re-throw ThreadDeath
                //
                if (e instanceof ThreadDeath) {
                    throw (ThreadDeath) e;
                }
            }
        } else {
            resource.setLookedUp(false);
        }

        //
        // Tomcat 5.0.x DBCP datasources would have URL set to null if they incorrectly configured
        // so we need to deal with this little feature
        //
        if (dataSourceInfo != null && dataSourceInfo.getJdbcURL() == null) {
            resource.setLookedUp(false);
        }

        if (resource.isLookedUp() && dataSourceInfo != null) {
            resource.setDataSourceInfo(dataSourceInfo);
        }
    }

    public synchronized boolean resetResource(final Context context, String resourceName,
            ContainerWrapperBean containerWrapper) throws NamingException {
        if (context != null) {
            ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).bindToContext(context);
        }
        try {
            javax.naming.Context ctx = (context != null) ? new InitialContext() : getGlobalNamingContext();
            String jndiName = resolveJndiName(resourceName, (context == null));
            Object o = ctx.lookup(jndiName);
            try {
                for (Iterator it = datasourceMappers.iterator(); it.hasNext();) {
                    DatasourceAccessor accessor = (DatasourceAccessor) it.next();
                    if (accessor.reset(o)) {
                        return true;
                    }
                }
                return false;
            } catch (Throwable e) {
                //
                // make sure we always re-throw ThreadDeath
                //
                if (e instanceof ThreadDeath) {
                    throw (ThreadDeath) e;
                }
                return false;
            }
        } finally {
            if (context != null) {
                ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).unbindFromContext(context);
            }
        }
    }

    public synchronized DataSource lookupDataSource(final Context context, String resourceName,
            ContainerWrapperBean containerWrapper) throws NamingException {
        if (context != null) {
            ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).bindToContext(context);
        }
        try {
            javax.naming.Context ctx = (context != null) ? new InitialContext() : getGlobalNamingContext();
            String jndiName = resolveJndiName(resourceName, (context == null));
            Object o = ctx.lookup(jndiName);

            if (o instanceof DataSource) {
                return (DataSource) o;
            } else {
                return null;
            }
        } finally {
            if (context != null) {
                ((AbstractTomcatContainer) containerWrapper.getTomcatContainer()).unbindFromContext(context);
            }
        }
    }

    public List getDatasourceMappers() {
        return datasourceMappers;
    }

    public void setDatasourceMappers(List datasourceMappers) {
        this.datasourceMappers = datasourceMappers;
    }

    public boolean supportsPrivateResources() {
        return true;
    }

    public boolean supportsGlobalResources() {
        return true;
    }

    public boolean supportsDataSourceLookup() {
        return true;
    }

    public MBeanServer getMBeanServer() {
        return new Registry().getMBeanServer();
    }

    /**
     * Resolves a JNDI resource name by prepending the scope-appropriate prefix.
     *
     * @param global whether to use the global prefix
     * @param name the JNDI name of the resource
     * 
     * @return the JNDI resource name with the prefix appended
     *
     * @see #DEFAULT_GLOBAL_RESOURCE_PREFIX
     * @see #DEFAULT_RESOURCE_PREFIX
     */
    protected static String resolveJndiName(String name, boolean global) {
        return (global ? DEFAULT_GLOBAL_RESOURCE_PREFIX : DEFAULT_RESOURCE_PREFIX) + name;
    }

    private String getStringAttribute(MBeanServer server, ObjectName objectName, String attributeName) {
        try {
            return (String) server.getAttribute(objectName, attributeName);
        } catch (Exception e) {
            logger.error("Error getting attribute '" + attributeName + "' from '" + objectName + "'", e);
            return null;
        }
    }

    /**
      * Returns the Server's global naming context
      *
      * @return the global JNDI context
      */
    protected javax.naming.Context getGlobalNamingContext() {

        javax.naming.Context globalContext = null;
        MBeanServer mBeanServer = getMBeanServer();
        if (mBeanServer != null) {
            try {
                ObjectName name = new ObjectName("Catalina:type=Server");
                Server server = (Server) mBeanServer.getAttribute(name, "managedResource");
                //getGlobalNamingContext() was added to Server interface in Tomcat 7.0.11
                if (server instanceof StandardServer) {
                    globalContext = ((StandardServer) server).getGlobalNamingContext();
                }
            } catch (Exception e) {
                logger.error("There was an error getting globalContext through JMX server:", e);
            }
        }

        return globalContext;
    }
}