org.jboss.test.cluster.testutil.SessionTestUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.test.cluster.testutil.SessionTestUtil.java

Source

/*
 * 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.test.cluster.testutil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.servlet.ServletException;

import org.apache.catalina.Context;
import org.apache.catalina.Manager;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.config.BuddyReplicationConfig;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
import org.jboss.cache.config.Configuration.CacheMode;
import org.jboss.cache.loader.FileCacheLoaderConfig;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.cache.pojo.PojoCacheFactory;
import org.jboss.metadata.javaee.spec.EmptyMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.jboss.PassivationConfig;
import org.jboss.metadata.web.jboss.ReplicationConfig;
import org.jboss.metadata.web.jboss.ReplicationGranularity;
import org.jboss.metadata.web.jboss.ReplicationTrigger;
import org.jboss.metadata.web.jboss.SnapshotMode;
import org.jboss.test.cluster.web.CacheHelper;
import org.jboss.test.cluster.web.mocks.MockEngine;
import org.jboss.test.cluster.web.mocks.MockHost;
import org.jboss.test.cluster.web.mocks.MockRequest;
import org.jboss.test.cluster.web.mocks.MockValve;
import org.jboss.test.cluster.web.mocks.RequestHandler;
import org.jboss.test.cluster.web.mocks.RequestHandlerValve;
import org.jboss.web.tomcat.service.session.JBossCacheManager;
import org.jboss.web.tomcat.service.session.distributedcache.impl.DistributedCacheManagerFactoryImpl;
import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManagerFactoryFactory;
import org.jgroups.Address;

/**
 * Utilities for session testing.
 * 
 * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
 * @version $Revision: 100315 $
 */
public class SessionTestUtil {
    private static final String[] STRING_ONLY_TYPES = { String.class.getName() };
    private static final String[] STRING_BOOLEAN_TYPES = { String.class.getName(), boolean.class.getName() };
    private static final String CONFIG_LOCATION = "cluster/http/jboss-web-test-service.xml";
    private static DistributedCacheManagerFactoryImpl distributedManagerFactory;
    static {
        try {
            distributedManagerFactory = (DistributedCacheManagerFactoryImpl) DistributedCacheManagerFactoryFactory
                    .getInstance().getDistributedCacheManagerFactory();
        } catch (ClusteringNotSupportedException e) {
            e.printStackTrace();
        }
    }

    public static JBossCacheManager createManager(String warName, int maxInactiveInterval, boolean local,
            String passivationDir, boolean totalReplication, boolean marshalling, String jvmRoute,
            Set<PojoCache> allCaches) {
        return createManager(warName, maxInactiveInterval, local, passivationDir, totalReplication, marshalling,
                false, jvmRoute, allCaches);
    }

    public static JBossCacheManager createManager(String warName, int maxInactiveInterval, boolean local,
            String passivationDir, boolean totalReplication, boolean marshalling, boolean purgeCacheLoader,
            String jvmRoute, Set<PojoCache> allCaches) {
        PojoCache cache = createCache(local, passivationDir, totalReplication, marshalling, allCaches);
        return createManager(warName, maxInactiveInterval, cache, jvmRoute);
    }

    public static JBossCacheManager createManager(String warName, int maxInactiveInterval, PojoCache cache,
            String jvmRoute) {
        if (distributedManagerFactory == null)
            throw new IllegalStateException("Failed to initialize distributedManagerFactory");

        distributedManagerFactory.setPojoCache(cache);
        JBossCacheManager jbcm = new JBossCacheManager(distributedManagerFactory);
        jbcm.setSnapshotMode(SnapshotMode.INSTANT);

        setupContainer(warName, jvmRoute, jbcm);

        // Do this after assigning the manager to the container, or else
        // the container's setting will override ours
        // Can't just set the container as their config is per minute not per second
        jbcm.setMaxInactiveInterval(maxInactiveInterval);

        return jbcm;
    }

    public static PojoCache createCache(boolean local, String passivationDir, boolean totalReplication,
            boolean marshalling, Set<PojoCache> allCaches) {
        return createCache(local, passivationDir, totalReplication, marshalling, false, allCaches);
    }

    public static PojoCache createCache(boolean local, String passivationDir, boolean totalReplication,
            boolean marshalling, boolean purgeCacheLoader, Set<PojoCache> allCaches) {
        Configuration cfg = getConfiguration(local, passivationDir, totalReplication, marshalling,
                purgeCacheLoader);
        PojoCache cache = PojoCacheFactory.createCache(cfg, true);

        if (allCaches != null)
            allCaches.add(cache);
        return cache;
    }

    public static Configuration getConfiguration(boolean local, String passivationDir, boolean totalReplication,
            boolean marshalling, boolean purgeCacheLoader) {
        PojoCache temp = PojoCacheFactory.createCache(CONFIG_LOCATION, false);
        Configuration config = temp.getCache().getConfiguration();
        if (local)
            config.setCacheMode(CacheMode.LOCAL);
        if (passivationDir == null) {
            config.setCacheLoaderConfig(null);
        } else {
            CacheLoaderConfig clc = config.getCacheLoaderConfig();
            FileCacheLoaderConfig fclc = new FileCacheLoaderConfig();
            fclc.setProperties(clc.getFirstCacheLoaderConfig().getProperties());
            fclc.setLocation(passivationDir);
            fclc.setFetchPersistentState(true);
            fclc.setPurgeOnStartup(purgeCacheLoader);
            ArrayList<IndividualCacheLoaderConfig> iclcs = new ArrayList<IndividualCacheLoaderConfig>();
            iclcs.add(fclc);
            clc.setIndividualCacheLoaderConfigs(iclcs);
        }

        BuddyReplicationConfig brc = config.getBuddyReplicationConfig();
        brc.setEnabled(!local && !totalReplication);

        config.setUseRegionBasedMarshalling(marshalling);
        config.setInactiveOnStartup(marshalling);

        // No async marshalling or notifications
        config.setSerializationExecutorPoolSize(0);
        config.setListenerAsyncPoolSize(0);

        // Block for commits -- no races between test driver and replication
        config.setSyncCommitPhase(true);
        config.setSyncRollbackPhase(true);

        return config;
    }

    public static PojoCache getDistributedCacheManagerFactoryPojoCache() {
        return distributedManagerFactory.getPojoCache();
    }

    @SuppressWarnings("unchecked")
    public static Cache<Object, Object> getDistributedCacheManagerFactoryPlainCache() {
        return distributedManagerFactory.getPlainCache();
    }

    public static void clearDistributedCacheManagerFactory() {
        distributedManagerFactory.clearCaches();
    }

    public static void setupContainer(String warName, String jvmRoute, Manager mgr) {
        MockEngine engine = new MockEngine();
        engine.setJvmRoute(jvmRoute);
        MockHost host = new MockHost();
        engine.addChild(host);
        host.setName("localhost");
        StandardContext container = new StandardContext();
        container.setName(warName);
        host.addChild(container);
        container.setManager(mgr);
    }

    public static JBossWebMetaData createWebMetaData(int maxSessions) {
        return createWebMetaData(ReplicationGranularity.SESSION, ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
                maxSessions, false, -1, -1, false, 0);
    }

    public static JBossWebMetaData createWebMetaData(int maxSessions, boolean passivation, int maxIdle,
            int minIdle) {
        return createWebMetaData(ReplicationGranularity.SESSION, ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
                maxSessions, passivation, maxIdle, minIdle, false, 60);
    }

    public static JBossWebMetaData createWebMetaData(ReplicationGranularity granularity, ReplicationTrigger trigger,
            boolean batchMode, int maxUnreplicated) {
        return createWebMetaData(granularity, trigger, -1, false, -1, -1, batchMode, maxUnreplicated);
    }

    public static JBossWebMetaData createWebMetaData(ReplicationGranularity granularity, ReplicationTrigger trigger,
            int maxSessions, boolean passivation, int maxIdle, int minIdle, boolean batchMode,
            int maxUnreplicated) {
        JBossWebMetaData webMetaData = new JBossWebMetaData();
        webMetaData.setDistributable(new EmptyMetaData());
        webMetaData.setMaxActiveSessions(new Integer(maxSessions));
        PassivationConfig pcfg = new PassivationConfig();
        pcfg.setUseSessionPassivation(Boolean.valueOf(passivation));
        pcfg.setPassivationMaxIdleTime(new Integer(maxIdle));
        pcfg.setPassivationMinIdleTime(new Integer(minIdle));
        webMetaData.setPassivationConfig(pcfg);
        ReplicationConfig repCfg = new ReplicationConfig();
        repCfg.setReplicationGranularity(granularity);
        repCfg.setReplicationTrigger(trigger);
        repCfg.setReplicationFieldBatchMode(Boolean.valueOf(batchMode));
        repCfg.setMaxUnreplicatedInterval(Integer.valueOf(maxUnreplicated));
        webMetaData.setReplicationConfig(repCfg);
        return webMetaData;
    }

    public static void invokeRequest(Manager manager, RequestHandler handler, String sessionId)
            throws ServletException, IOException {
        Valve valve = setupPipeline(manager, handler);
        Request request = setupRequest(manager, sessionId);
        invokeRequest(valve, request);
    }

    public static void invokeRequest(Valve pipelineHead, Request request) throws ServletException, IOException {
        pipelineHead.invoke(request, request.getResponse());
        // StandardHostValve calls request.getSession(false) on way out, so we will too
        request.getSession(false);
        request.recycle();
    }

    public static Valve setupPipeline(Manager manager, RequestHandler requestHandler) {
        Pipeline pipeline = manager.getContainer().getPipeline();

        // Clean out any existing request handler
        Valve[] valves = pipeline.getValves();
        RequestHandlerValve mockValve = null;
        for (Valve valve : valves) {
            if (valve instanceof RequestHandlerValve) {
                mockValve = (RequestHandlerValve) valve;
                break;
            }
        }

        if (mockValve == null) {
            mockValve = new RequestHandlerValve(requestHandler);
            pipeline.addValve(mockValve);
        } else {
            mockValve.setRequestHandler(requestHandler);
        }

        return pipeline.getFirst();
    }

    public static Request setupRequest(Manager manager, String sessionId) {
        MockRequest request = new MockRequest();
        request.setRequestedSessionId(sessionId);
        request.setContext((Context) manager.getContainer());
        Response response = new Response();
        request.setResponse(response);
        return request;

    }

    public static void cleanupPipeline(Manager manager) {
        Pipeline pipeline = manager.getContainer().getPipeline();

        Valve[] valves = pipeline.getValves();
        for (Valve valve : valves) {
            if (valve instanceof MockValve) {
                ((MockValve) valve).clear();
            }
        }
    }

    public static Object getSessionVersion(MBeanServerConnection adaptor, String sessionFqn) throws Exception {
        return adaptor.invoke(CacheHelper.OBJECT_NAME, "getSessionVersion", new Object[] { sessionFqn },
                STRING_ONLY_TYPES);
    }

    public static Object getBuddySessionVersion(MBeanServerConnection adaptor, String sessionFqn) throws Exception {

        return adaptor.invoke(CacheHelper.OBJECT_NAME, "getBuddySessionVersion", new Object[] { sessionFqn },
                STRING_ONLY_TYPES);
    }

    public static void setCacheConfigName(MBeanServerConnection adaptor, String cacheConfigName,
            boolean usePojoCache) throws Exception {
        adaptor.invoke(CacheHelper.OBJECT_NAME, "setCacheConfigName",
                new Object[] { cacheConfigName, Boolean.valueOf(usePojoCache) },
                new String[] { String.class.getName(), boolean.class.getName() });
    }

    @SuppressWarnings("unchecked")
    public static Set<String> getSessionIds(MBeanServerConnection adaptor, String warFqn) throws Exception {
        return (Set<String>) adaptor.invoke(CacheHelper.OBJECT_NAME, "getSessionIds", new Object[] { warFqn },
                STRING_ONLY_TYPES);
    }

    @SuppressWarnings("unchecked")
    public static Set<String> getSessionIds(MBeanServerConnection adaptor, String warFqn, boolean includeBuddies)
            throws Exception {
        return (Set<String>) adaptor.invoke(CacheHelper.OBJECT_NAME, "getSessionIds",
                new Object[] { warFqn, Boolean.valueOf(includeBuddies) }, STRING_BOOLEAN_TYPES);
    }

    public static boolean isBuddyReplication() throws Exception {
        return Boolean.parseBoolean(System.getProperty("jbosstest.cluster.web.cache.br", "false"));
    }

    public static String getSessionFqn(String contextPath, String sessionId) {
        return "/JSESSION/" + SessionTestUtil.getContextHostPath("localhost", contextPath) + "/" + sessionId;
    }

    public static String getContextHostPath(String hostname, String contextPath) {
        return contextPath + "_" + hostname;
    }

    /**
     * Loops, continually calling {@link #areCacheViewsComplete(org.jboss.cache.Cache[])}
     * until it either returns true or <code>timeout</code> ms have elapsed.
     *
     * @param caches  caches which must all have consistent views
     * @param timeout max number of ms to loop
     * @throws RuntimeException if <code>timeout</code> ms have elapse without
     *                          all caches having the same number of members.
     */
    public static void blockUntilViewsReceived(Cache<?, ?>[] caches, long timeout) {
        long failTime = System.currentTimeMillis() + timeout;

        while (System.currentTimeMillis() < failTime) {
            sleepThread(100);
            if (areCacheViewsComplete(caches)) {
                return;
            }
        }

        throw new RuntimeException("timed out before caches had complete views");
    }

    /**
     * Checks each cache to see if the number of elements in the array
     * returned by {@link CacheSPI#getMembers()} matches the size of
     * the <code>caches</code> parameter.
     *
     * @param caches caches that should form a View
     * @return <code>true</code> if all caches have
     *         <code>caches.length</code> members; false otherwise
     * @throws IllegalStateException if any of the caches have MORE view
     *                               members than caches.length
     */
    public static boolean areCacheViewsComplete(Cache<?, ?>[] caches) {
        return areCacheViewsComplete(caches, true);
    }

    public static boolean areCacheViewsComplete(Cache<?, ?>[] caches, boolean barfIfTooManyMembers) {
        int memberCount = caches.length;

        for (int i = 0; i < memberCount; i++) {
            if (!isCacheViewComplete(caches[i], memberCount, barfIfTooManyMembers)) {
                return false;
            }
        }

        return true;
    }

    public static boolean isCacheViewComplete(Cache<?, ?> c, int memberCount, boolean barfIfTooManyMembers) {
        CacheSPI<?, ?> cache = (CacheSPI<?, ?>) c;
        List<Address> members = cache.getMembers();
        if (members == null || memberCount > members.size()) {
            return false;
        } else if (memberCount < members.size()) {
            if (barfIfTooManyMembers) {
                // This is an exceptional condition
                StringBuffer sb = new StringBuffer("Cache at address ");
                sb.append(cache.getLocalAddress());
                sb.append(" had ");
                sb.append(members.size());
                sb.append(" members; expecting ");
                sb.append(memberCount);
                sb.append(". Members were (");
                for (int j = 0; j < members.size(); j++) {
                    if (j > 0) {
                        sb.append(", ");
                    }
                    sb.append(members.get(j));
                }
                sb.append(')');

                throw new IllegalStateException(sb.toString());
            } else
                return false;
        }

        return true;
    }

    public static Cookie getSessionCookie(HttpClient client) {
        // 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;
        }
        return sessionID;
    }

    public static void setCookieDomainToThisServer(HttpClient client, String server) {
        // Get the session cookie
        Cookie sessionID = getSessionCookie(client);
        if (sessionID == null)
            throw new IllegalStateException("No session cookie found on " + client);
        // Reset the domain so that the cookie will be sent to server1
        sessionID.setDomain(server);
        client.getState().addCookie(sessionID);
    }

    /**
     * Puts the current thread to sleep for the desired number of ms, suppressing
     * any exceptions.
     *
     * @param sleeptime number of ms to sleep
     */
    public static void sleepThread(long sleeptime) {
        try {
            Thread.sleep(sleeptime);
        } catch (InterruptedException ie) {
        }
    }

    public static Object getAttributeValue(int value) {
        return Integer.valueOf(value);
    }

    public static void cleanPassivationDir(File root) {
        if (root.exists()) {
            if (root.isDirectory()) {
                for (File child : root.listFiles()) {
                    cleanPassivationDir(child);
                }
            }
            if (!root.delete()) {
                root.deleteOnExit();
            }
        }
    }

    private SessionTestUtil() {
    }
}