org.jboss.test.cluster.classloader.leak.test.ClassloaderLeakTestBase.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.test.cluster.classloader.leak.test.ClassloaderLeakTestBase.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, 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.test.cluster.classloader.leak.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jboss.test.JBossClusteredTestCase;
import org.jboss.test.classloader.leak.clstore.ClassLoaderTrackerMBean;

/**
 * Abstract superclass of the EJB2 and EJB3 versions of the classloader leak
 * tests.
 * 
 * @author Brian Stansberry
 */
public abstract class ClassloaderLeakTestBase extends JBossClusteredTestCase {
    public static final String WEBAPP = "WEBAPP";
    public static final String SERVLET = "SERVLET";
    public static final String SERVLET_TCCL = "SERVLET_TCCL";
    public static final String JSP = "JSP";
    public static final String JSP_TCCL = "JSP_TCCL";

    public static final String[] WEB = new String[] { SERVLET, SERVLET_TCCL, WEBAPP };

    private static final Set<String> deployments = new HashSet<String>();

    private String baseURL = null;

    public ClassloaderLeakTestBase(String name) {
        super(name);
    }

    protected void setUp() throws Exception {
        super.setUp();
        cleanDeployments();

        for (int i = 0; i < WEB.length; i++)
            removeClassLoader(WEB[i]);

        String[] ejbs = getEjbKeys();
        for (int i = 0; i < ejbs.length; i++)
            removeClassLoader(ejbs[i]);

        baseURL = "/" + getWarContextPath() + "/";
    }

    protected void tearDown() throws Exception {
        cleanDeployments();

        for (int i = 0; i < WEB.length; i++)
            removeClassLoader(WEB[i]);

        String[] ejbs = getEjbKeys();
        for (int i = 0; i < ejbs.length; i++)
            removeClassLoader(ejbs[i]);

        super.tearDown();
    }

    protected abstract String getWarContextPath();

    protected abstract String[] getEjbKeys();

    protected void cleanDeployments() throws Exception {
        Iterator it = deployments.iterator();
        while (it.hasNext()) {
            undeployComponent((String) it.next(), false);
            it = deployments.iterator();
        }
    }

    protected void undeployComponent(String deployment, boolean propagateFailure) throws Exception {
        try {
            undeploy(deployment);
            deployments.remove(deployment);
        } catch (Exception e) {
            if (propagateFailure)
                throw e;
            else {
                log.error("Exception during undeploy of " + deployment, e);
                deployments.remove(deployment);
            }
        }
    }

    private void deployComponent(String deployment) throws Exception {
        deploy(deployment);
        deployments.add(deployment);
    }

    protected void warTest(String deployment) throws Exception {
        // Ensure we are starting with a clean slate
        checkCleanKeys(WEB);

        deployComponent(deployment);

        makeWebRequest(baseURL + "SimpleServlet", WEBAPP);

        // Make sure the expected registrations were done
        checkKeyRegistration(WEB);

        // This sleep is a workaround to JBAS-4060
        sleep(500);

        undeployComponent(deployment, true);

        // TODO - probably not needed anymore; remove
        flushSecurityCache("HsqlDbRealm");

        sleep(500);

        // Confirm the classloaders were released
        String unregistered = checkClassLoaderRelease(WEB);

        if (unregistered.trim().length() > 0) {
            fail("Classloaders unregistered: " + unregistered);
        }
    }

    protected void ejbTest(String deployment) throws Exception {
        // Ensure we are starting with a clean slate
        checkCleanKeys(getEjbKeys());

        deployComponent(deployment);

        makeEjbRequests();

        // Make sure the expected registrations were done
        checkKeyRegistration(getEjbKeys());

        undeployComponent(deployment, true);

        // TODO - probably not needed anymore; remove
        flushSecurityCache("HsqlDbRealm");

        sleep(500);

        // Confirm the classloaders were released
        String unregistered = checkClassLoaderRelease(getEjbKeys());

        if (unregistered.length() > 0) {
            fail("Classloaders unregistered: " + unregistered);
        }
    }

    protected void earTest(String deployment) throws Exception {
        // Ensure we are starting with a clean slate
        checkCleanKeys(WEB);
        checkCleanKeys(getEjbKeys());

        deployComponent(deployment);

        // Simple web requests
        makeWebRequest(baseURL + "SimpleServlet", WEBAPP);

        // Make sure the expected registrations were done      
        checkKeyRegistration(WEB);

        // EJB related requests
        makeWebRequest(baseURL + "EJBServlet", "EJB");

        makeEjbRequests();

        // Make sure the expected registrations were done      
        checkKeyRegistration(getEjbKeys());

        // This sleep is a workaround to JBAS-4060
        sleep(500);

        undeployComponent(deployment, true);

        // TODO - probably not needed anymore; remove
        flushSecurityCache("HsqlDbRealm");

        sleep(500);

        // Confirm the classloaders were released
        String unregistered = checkClassLoaderRelease(WEB);

        unregistered += checkClassLoaderRelease(getEjbKeys());

        if (unregistered.trim().length() > 0) {
            fail("Classloaders unregistered: " + unregistered);
        }
    }

    protected void checkCleanKeys(String[] keys) throws Exception {
        MBeanServerConnection[] adaptors = getAdaptors();
        for (MBeanServerConnection adaptor : adaptors) {
            for (int i = 0; i < keys.length; i++) {
                if (hasClassLoader(keys[i], adaptor))
                    throw new IllegalStateException("Classloader already registered for " + keys[i]);
            }
        }
    }

    protected void checkKeyRegistration(String[] keys) throws Exception {
        MBeanServerConnection[] adaptors = getAdaptors();
        int nodeNum = 0;
        for (MBeanServerConnection adaptor : adaptors) {
            for (int i = 0; i < keys.length; i++) {
                assertTrue(keys[i] + " classloader registered with node " + nodeNum,
                        hasClassLoader(keys[i], adaptor));
            }
            nodeNum++;
        }
    }

    protected String checkClassLoaderRelease(String[] keys) throws Exception {
        String faillist = "";
        MBeanServerConnection[] adaptors = getAdaptors();
        int nodeNum = 0;
        for (MBeanServerConnection adaptor : adaptors) {
            for (int i = 0; i < keys.length; i++) {
                if (!hasClassLoaderBeenReleased(keys[i], adaptor)) {
                    faillist += "node" + nodeNum + "/" + keys[i] + " ";
                    return faillist; // don't check the others; don't want multiple reports
                }
            }

            nodeNum++;
        }

        return faillist;
    }

    private boolean hasClassLoader(String key, MBeanServerConnection adaptor) throws Exception {
        ObjectName on = new ObjectName(ClassLoaderTrackerMBean.OBJECT_NAME);
        Object[] params = { key };
        String[] signature = new String[] { String.class.getName() };
        return ((Boolean) adaptor.invoke(on, "hasClassLoader", params, signature)).booleanValue();
    }

    private boolean hasClassLoaderBeenReleased(String key, MBeanServerConnection adaptor) throws Exception {
        ObjectName on = new ObjectName(ClassLoaderTrackerMBean.OBJECT_NAME);
        Object[] params = { key };
        String[] signature = new String[] { String.class.getName() };
        return ((Boolean) adaptor.invoke(on, "hasClassLoaderBeenReleased", params, signature)).booleanValue();
    }

    private void removeClassLoader(String key) throws Exception {
        try {
            ObjectName on = new ObjectName(ClassLoaderTrackerMBean.OBJECT_NAME);
            Object[] params = { key };
            String[] signature = new String[] { String.class.getName() };
            MBeanServerConnection[] adaptors = getAdaptors();
            for (MBeanServerConnection adaptor : adaptors) {
                adaptor.invoke(on, "removeClassLoader", params, signature);
            }
        } catch (Exception e) {
            log.error("Caught exception removing classloader under key " + key, e);
        }
    }

    private void flushSecurityCache(String domain) throws Exception {
        log.debug("Flushing security cache " + domain);
        ObjectName on = new ObjectName(ClassLoaderTrackerMBean.OBJECT_NAME);
        Object[] params = { domain };
        String[] signature = new String[] { String.class.getName() };
        MBeanServerConnection[] adaptors = getAdaptors();
        for (MBeanServerConnection adaptor : adaptors) {
            adaptor.invoke(on, "flushSecurityCache", params, signature);
        }
    }

    private void makeWebRequest(String url, String responseContent) throws Exception {
        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod(getHttpURLs()[0] + url);
        checkWebRequest(client, method, url, responseContent);

        setCookieDomainToThisServer(client, getHttpURLs()[1]);
        method = new GetMethod(getHttpURLs()[1] + url);
        checkWebRequest(client, method, url, responseContent);
    }

    private void setCookieDomainToThisServer(HttpClient client, String server) {
        // Get the session cookie
        Cookie sessionID = getSessionCookie(client, server);
        // Reset the domain so that the cookie will be sent to server1
        sessionID.setDomain(server);
        client.getState().addCookie(sessionID);
    }

    protected Cookie getSessionCookie(HttpClient client, String server) {
        // Get the state for the JSESSIONID
        HttpState state = client.getState();
        // Get the JSESSIONID so we can reset the host
        Cookie[] cookies = state.getCookies();
        Cookie sessionID = null;
        for (int c = 0; c < cookies.length; c++) {
            Cookie k = cookies[c];
            if (k.getName().equalsIgnoreCase("JSESSIONID"))
                sessionID = k;
        }
        if (sessionID == null) {
            fail("setCookieDomainToThisServer(): fail to find session id. Server name: " + server);
        }
        log.info("Saw JSESSIONID=" + sessionID);
        return sessionID;
    }

    /**
     * FIXME Comment this
     * 
     * @param client
     * @param method
     * @param url
     * @param responseContent
     */
    private void checkWebRequest(HttpClient client, GetMethod method, String url, String responseContent) {
        int responseCode = 0;
        try {
            responseCode = client.executeMethod(method);

            assertTrue("Get OK with url: " + url + " responseCode: " + responseCode,
                    responseCode == HttpURLConnection.HTTP_OK);

            InputStream rs = method.getResponseBodyAsStream();
            InputStreamReader reader = new InputStreamReader(rs);
            StringWriter writer = new StringWriter();
            int c;
            while ((c = reader.read()) != -1)
                writer.write(c);

            String rsp = writer.toString();

            assertTrue("Response contains " + responseContent, rsp.indexOf(responseContent) >= 0);
        } catch (IOException e) {
            e.printStackTrace();
            fail("HttpClient executeMethod fails." + e.toString());
        } finally {
            method.releaseConnection();
        }
    }

    protected abstract void makeEjbRequests() throws Exception;
}