Author: bstansberry(a)jboss.com
Date: 2008-02-28 14:42:08 -0500 (Thu, 28 Feb 2008)
New Revision: 14381
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/AccountHolder.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/CacheAccessListener.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/ClassLoaderTestDAO.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/OptimisticIsolatedClassLoaderTest.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/PessimisticIsolatedClassLoaderTest.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/CustomClassLoaderCacheFactory.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/IsolatedCacheTestSetup.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoader.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoaderTestSetup.java
Modified:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/DualNodeTestCaseBase.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionImpl.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionManagerImpl.java
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/TestCacheInstanceManager.java
Log:
Add tests of isolated-classloader environments
Modified:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/DualNodeTestCaseBase.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/DualNodeTestCaseBase.java 2008-02-28
19:41:20 UTC (rev 14380)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/DualNodeTestCaseBase.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -16,6 +16,8 @@
package org.hibernate.test.cache.jbc2.functional;
+import javax.transaction.TransactionManager;
+
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Mappings;
@@ -23,6 +25,7 @@
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.junit.functional.ExecutionEnvironment;
import org.hibernate.test.cache.jbc2.functional.util.DualNodeConnectionProviderImpl;
+import org.hibernate.test.cache.jbc2.functional.util.DualNodeJtaTransactionManagerImpl;
import org.hibernate.test.cache.jbc2.functional.util.DualNodeTestUtil;
import org.hibernate.test.cache.jbc2.functional.util.DualNodeTransactionManagerLookup;
import org.hibernate.test.cache.jbc2.functional.util.TestCacheInstanceManager;
@@ -138,12 +141,22 @@
@Override
protected void cleanupTest() throws Exception
{
- super.cleanupTest();
+ try {
+ super.cleanupTest();
- log.info( "Destroying second node locally managed execution env" );
- secondNodeEnvironment.complete();
- secondNodeEnvironment = null;
+ log.info( "Destroying second node locally managed execution env" );
+ secondNodeEnvironment.complete();
+ secondNodeEnvironment = null;
+ }
+ finally {
+ cleanupTransactionManagement();
+ }
}
+
+ protected void cleanupTransactionManagement() {
+ DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+ DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
+ }
public ExecutionEnvironment getSecondNodeEnvironment() {
return secondNodeEnvironment;
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ ~ Hibernate, Relational Persistence for Idiomatic Java
+ ~
+ ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ ~ indicated by the @author tags or express copyright attribution
+ ~ statements applied by the authors. All third-party contributions are
+ ~ distributed under license by Red Hat Middleware LLC.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, as published by the Free Software Foundation.
+ ~
+ ~ This program 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 distribution; if not, write to:
+ ~ Free Software Foundation, Inc.
+ ~ 51 Franklin Street, Fifth Floor
+ ~ Boston, MA 02110-1301 USA
+ -->
+<hibernate-mapping
+ package="org.hibernate.test.cache.jbc2.functional.classloader">
+
+ <class name="Account" table="Accounts">
+
+ <cache usage="transactional"/>
+
+ <id name="id">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="branch" not-null="true"/>
+ <property name="balance" not-null="true"/>
+ <property name="accountHolder" type="serializable"
not-null="true"/>
+
+ </class>
+
+</hibernate-mapping>
Property changes on:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
___________________________________________________________________
Name: svn:executable
+ *
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,142 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.cache.jbc2.functional.classloader;
+
+import java.io.Serializable;
+
+/**
+ * Comment
+ *
+ * @author Brian Stansberry
+ * @version $Revision: 60233 $
+ */
+// @NamedQuery(name="account.totalbalance.default",query="select
account.balance from Account as account where account.accountHolder = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheable",value="true")}),
+// @NamedQuery(name="account.totalbalance.namedregion",query="select
account.balance from Account as account where account.accountHolder = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheRegion",value="AccountRegion"),
+//
@QueryHint(name="org.hibernate.cacheable",value="true")
+// }),
+// @NamedQuery(name="account.branch.default",query="select
account.branch from Account as account where account.accountHolder = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheable",value="true")}),
+// @NamedQuery(name="account.branch.namedregion",query="select
account.branch from Account as account where account.accountHolder = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheRegion",value="AccountRegion"),
+//
@QueryHint(name="org.hibernate.cacheable",value="true")
+// }),
+// @NamedQuery(name="account.bybranch.default",query="select account
from Account as account where account.branch = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheable",value="true")}),
+// @NamedQuery(name="account.bybranch.namedregion",query="select account
from Account as account where account.branch = ?1",
+//
hints={(a)QueryHint(name="org.hibernate.cacheRegion",value="AccountRegion"),
+//
@QueryHint(name="org.hibernate.cacheable",value="true")
+// })
+public class Account implements Serializable
+{
+
+ private static final long serialVersionUID = 1L;
+
+ private Integer id;
+ private AccountHolder accountHolder;
+ private Integer balance;
+ private String branch;
+
+ public Integer getId()
+ {
+ return id;
+ }
+ public void setId(Integer id)
+ {
+ this.id = id;
+ }
+
+ public AccountHolder getAccountHolder()
+ {
+ return accountHolder;
+ }
+ public void setAccountHolder(AccountHolder accountHolder)
+ {
+ this.accountHolder = accountHolder;
+ }
+
+ public Integer getBalance()
+ {
+ return balance;
+ }
+ public void setBalance(Integer balance)
+ {
+ this.balance = balance;
+ }
+ public String getBranch()
+ {
+ return branch;
+ }
+ public void setBranch(String branch)
+ {
+ this.branch = branch;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this) return true;
+ if (!(obj instanceof Account)) return false;
+ Account acct = (Account)obj;
+ if (!safeEquals(id, acct.id)) return false;
+ if (!safeEquals(branch, acct.branch)) return false;
+ if (!safeEquals(balance, acct.balance)) return false;
+ if (!safeEquals(accountHolder, acct.accountHolder)) return false;
+ return true;
+ }
+
+ public int hashCode( )
+ {
+ int result = 17;
+ result = result * 31 + safeHashCode(id);
+ result = result * 31 + safeHashCode(branch);
+ result = result * 31 + safeHashCode(balance);
+ result = result * 31 + safeHashCode(accountHolder);
+ return result;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("[id=");
+ sb.append(id);
+ sb.append(",branch=");
+ sb.append(branch);
+ sb.append(",balance=");
+ sb.append(balance);
+ sb.append(",accountHolder=");
+ sb.append(accountHolder);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private static int safeHashCode(Object obj) {
+ return obj == null ? 0 : obj.hashCode();
+ }
+
+ private static boolean safeEquals(Object a, Object b) {
+ return (a == b || (a != null && a.equals(b)));
+ }
+
+}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/AccountHolder.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/AccountHolder.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/AccountHolder.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,97 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.cache.jbc2.functional.classloader;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+/**
+ * Comment
+ *
+ * @author Brian Stansberry
+ * @version $Revision: 60233 $
+ */
+public class AccountHolder implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ private String lastName;
+ private String ssn;
+ private transient boolean deserialized;
+
+ public AccountHolder( ) {
+ this("Stansberry", "123-456-7890");
+ }
+
+ public AccountHolder(String lastName, String ssn)
+ {
+ this.lastName = lastName;
+ this.ssn = ssn;
+ }
+
+ public String getLastName( ) { return this.lastName; }
+ public void setLastName(String lastName) { this.lastName = lastName; }
+
+ public String getSsn( ) { return ssn; }
+ public void setSsn(String ssn) { this.ssn = ssn; }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this) return true;
+ if (!(obj instanceof AccountHolder)) return false;
+ AccountHolder pk = (AccountHolder)obj;
+ if (!lastName.equals(pk.lastName)) return false;
+ if (!ssn.equals(pk.ssn)) return false;
+ return true;
+ }
+
+ public int hashCode( )
+ {
+ int result = 17;
+ result = result * 31 + lastName.hashCode();
+ result = result * 31 + ssn.hashCode();
+ return result;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("[lastName=");
+ sb.append(lastName);
+ sb.append(",ssn=");
+ sb.append(ssn);
+ sb.append(",deserialized=");
+ sb.append(deserialized);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException,
ClassNotFoundException
+ {
+ ois.defaultReadObject();
+ deserialized = true;
+ }
+
+}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/CacheAccessListener.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/CacheAccessListener.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/CacheAccessListener.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,111 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.cache.jbc2.functional.classloader;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.NodeCreated;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeVisited;
+import org.jboss.cache.notifications.event.NodeCreatedEvent;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.NodeVisitedEvent;
+
+@CacheListener
+public class CacheAccessListener
+{
+ HashSet<Fqn<String>> modified = new HashSet<Fqn<String>>();
+ HashSet<Fqn<String>> accessed = new HashSet<Fqn<String>>();
+
+ public void clear()
+ {
+ modified.clear();
+ accessed.clear();
+ }
+
+ @NodeModified
+ public void nodeModified(NodeModifiedEvent event)
+ {
+ if (!event.isPre())
+ {
+ Fqn<String> fqn = event.getFqn();
+ System.out.println("MyListener - Modified node " + fqn.toString());
+ modified.add(fqn);
+ }
+ }
+
+ @NodeCreated
+ public void nodeCreated(NodeCreatedEvent event)
+ {
+ if (!event.isPre())
+ {
+ Fqn<String> fqn = event.getFqn();
+ System.out.println("MyListener - Created node " + fqn.toString());
+ modified.add(fqn);
+ }
+ }
+
+ @NodeVisited
+ public void nodeVisited(NodeVisitedEvent event)
+ {
+ if (!event.isPre())
+ {
+ Fqn<String> fqn = event.getFqn();
+ System.out.println("MyListener - Visited node " + fqn.toString());
+ accessed.add(fqn);
+ }
+ }
+
+ public boolean getSawRegionModification(String regionName)
+ {
+ return getSawRegion(regionName, modified);
+ }
+
+ public boolean getSawRegionAccess(String regionName)
+ {
+ return getSawRegion(regionName, accessed);
+ }
+
+ private boolean getSawRegion(String regionName, Set<Fqn<String>>
sawEvent)
+ {
+ boolean saw = false;
+ Fqn<String> fqn = Fqn.fromString(regionName);
+ for (Iterator<Fqn<String>> it = sawEvent.iterator(); it.hasNext();)
+ {
+ Fqn<String> modified = (Fqn<String>) it.next();
+ if (modified.isChildOf(fqn))
+ {
+ it.remove();
+ saw = true;
+ }
+ }
+ return saw;
+
+ }
+
+}
\ No newline at end of file
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/ClassLoaderTestDAO.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/ClassLoaderTestDAO.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/ClassLoaderTestDAO.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,285 @@
+/*
+ * 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.hibernate.test.cache.jbc2.functional.classloader;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Comment
+ *
+ * @author Brian Stansberry
+ */
+public class ClassLoaderTestDAO
+{
+ private static final Logger log = LoggerFactory.getLogger(ClassLoaderTestDAO.class);
+
+ private SessionFactory sessionFactory;
+ private TransactionManager tm;
+
+ private Class acctClass;
+ private Class holderClass;
+ private Method setId;
+ private Method setBalance;
+ private Method setBranch;
+ private Method setHolder;
+ private Object smith;
+ private Object jones;
+ private Object barney;
+ private Method setName;
+ private Method setSsn;
+
+
+ public ClassLoaderTestDAO(SessionFactory factory, TransactionManager tm) throws
Exception
+ {
+ this.sessionFactory = factory;
+ this.tm = tm;
+
+ acctClass =
Thread.currentThread().getContextClassLoader().loadClass(getClass().getPackage().getName()
+ ".Account");
+ holderClass =
Thread.currentThread().getContextClassLoader().loadClass(getClass().getPackage().getName()
+ ".AccountHolder");
+ setId = acctClass.getMethod("setId", Integer.class);
+ setBalance = acctClass.getMethod("setBalance", Integer.class);
+ setBranch = acctClass.getMethod("setBranch", String.class);
+ setHolder = acctClass.getMethod("setAccountHolder", holderClass);
+
+
+ setName = holderClass.getMethod("setLastName", String.class);
+ setSsn = holderClass.getMethod("setSsn", String.class);
+
+ smith = holderClass.newInstance();
+ setName.invoke(smith, "Smith");
+ setSsn.invoke(smith, "1000");
+
+ jones = holderClass.newInstance();
+ setName.invoke(jones, "Jones");
+ setSsn.invoke(jones, "2000");
+
+ barney = holderClass.newInstance();
+ setName.invoke(barney, "Barney");
+ setSsn.invoke(barney, "3000");
+ }
+
+ public Object getSmith() {
+ return smith;
+ }
+
+ public Object getJones() {
+ return jones;
+ }
+
+ public Object getBarney() {
+ return barney;
+ }
+
+ public void updateAccountBranch(Integer id, String branch) throws Exception
+ {
+ log.debug("Updating account " + id + " to branch " + branch);
+ tm.begin();
+ try {
+ Session session = sessionFactory.getCurrentSession();
+ Object account = session.get(acctClass, id);
+ setBranch.invoke(account, branch);
+ session.update(account);
+ tm.commit();
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+ log.debug("Updated account " + id + " to branch " + branch);
+ }
+
+ public int getCountForBranch(String branch, boolean useRegion) throws Exception
+ {
+ tm.begin();
+ try {
+ Query query = sessionFactory.getCurrentSession().createQuery("select
account from Account as account where account.branch = :branch");
+ query.setString("branch", branch);
+ if (useRegion)
+ {
+ query.setCacheRegion("AccountRegion");
+ }
+ query.setCacheable(true);
+ int result = query.list().size();
+ tm.commit();
+ return result;
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+
+ }
+
+ public void createAccount(Object holder, Integer id, Integer openingBalance, String
branch) throws Exception
+ {
+ log.debug("Creating account " + id);
+ tm.begin();
+ try {
+ Object account = acctClass.newInstance();
+ setId.invoke(account, id);
+ setHolder.invoke(account, holder);
+ setBalance.invoke(account, openingBalance);
+ setBranch.invoke(account, branch);
+ sessionFactory.getCurrentSession().persist(account);
+ tm.commit();
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+
+ log.debug("Created account " + id);
+ }
+
+ public void updateAccountBalance(Integer id, Integer newBalance) throws Exception
+ {
+ log.debug("Updating account " + id + " to balance " +
newBalance);
+ tm.begin();
+ try {
+ Session session = sessionFactory.getCurrentSession();
+ Object account = session.get(acctClass, id);
+ setBalance.invoke(account, newBalance);
+ session.update(account);
+ tm.commit();
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+ log.debug("Updated account " + id + " to balance " +
newBalance);
+ }
+
+ public String getBranch(Object holder, boolean useRegion) throws Exception
+ {
+ tm.begin();
+ try {
+ Query query = sessionFactory.getCurrentSession().createQuery("select
account.branch from Account as account where account.accountHolder = ?");
+ query.setParameter(0, holder);
+ if (useRegion)
+ {
+ query.setCacheRegion("AccountRegion");
+ }
+ query.setCacheable(true);
+ String result = (String) query.list().get(0);
+ tm.commit();
+ return result;
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+ }
+
+ public int getTotalBalance(Object holder, boolean useRegion)
+ throws Exception
+ {
+ List results = null;
+ tm.begin();
+ try {
+ Query query = sessionFactory.getCurrentSession().createQuery("select
account.balance from Account as account where account.accountHolder = ?");
+ query.setParameter(0, holder);
+ query.setCacheable(true);
+ results = query.list();
+ tm.commit();
+ }
+ catch (Exception e) {
+ log.error("rolling back", e);
+ tm.rollback();
+ throw e;
+ }
+
+ int total = 0;
+ if (results != null)
+ {
+ for (Iterator it = results.iterator(); it.hasNext();)
+ {
+ total += ((Integer) it.next()).intValue();
+ System.out.println("Total = " + total);
+ }
+ }
+ return total;
+ }
+
+ public void cleanup() throws Exception
+ {
+ internalCleanup();
+ }
+
+ private void internalCleanup() throws Exception
+ {
+ if (sessionFactory != null)
+ {
+ tm.begin();
+ try {
+
+ Session session = sessionFactory.getCurrentSession();
+ Query query = session.createQuery("select account from Account as
account");
+ List accts = query.list();
+ if (accts != null)
+ {
+ for (Iterator it = accts.iterator(); it.hasNext();)
+ {
+ try
+ {
+ Object acct = it.next();
+ log.info("Removing " + acct);
+ session.delete(acct);
+ }
+ catch (Exception ignored) {}
+ }
+ }
+ tm.commit();
+ }
+ catch (Exception e) {
+ tm.rollback();
+ throw e;
+ }
+ }
+ }
+
+ public void remove()
+ {
+ try
+ {
+ internalCleanup();
+ }
+ catch (Exception e)
+ {
+ log.error("Caught exception in remove", e);
+ }
+ }
+}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/OptimisticIsolatedClassLoaderTest.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/OptimisticIsolatedClassLoaderTest.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/OptimisticIsolatedClassLoaderTest.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.hibernate.test.cache.jbc2.functional.classloader;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.cache.jbc2.functional.util.IsolatedCacheTestSetup;
+
+/**
+ * Optimistic locking version of IsolatedClassLoaderTest.
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class OptimisticIsolatedClassLoaderTest extends
PessimisticIsolatedClassLoaderTest
+{
+ private static final String CACHE_CONFIG = "optimistic-shared";
+
+ /**
+ * Create a new OptimisticIsolatedClassLoaderTest.
+ *
+ * @param name
+ */
+ public OptimisticIsolatedClassLoaderTest(String name)
+ {
+ super(name);
+ }
+
+ public static Test suite() throws Exception {
+ TestSuite suite = new TestSuite(OptimisticIsolatedClassLoaderTest.class);
+ String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE +
".AccountHolder" };
+ return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
+ }
+
+ protected String getEntityCacheConfigName() {
+ return CACHE_CONFIG;
+ }
+
+}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/PessimisticIsolatedClassLoaderTest.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/PessimisticIsolatedClassLoaderTest.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/PessimisticIsolatedClassLoaderTest.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,370 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.cache.jbc2.functional.classloader;
+
+
+import javax.transaction.TransactionManager;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.SessionFactory;
+import org.hibernate.cache.StandardQueryCache;
+import org.hibernate.cache.jbc2.BasicRegionAdapter;
+import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
+import org.hibernate.cache.jbc2.query.QueryResultsRegionImpl;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.test.cache.jbc2.functional.DualNodeTestCaseBase;
+import org.hibernate.test.cache.jbc2.functional.util.DualNodeJtaTransactionManagerImpl;
+import org.hibernate.test.cache.jbc2.functional.util.DualNodeTestUtil;
+import org.hibernate.test.cache.jbc2.functional.util.IsolatedCacheTestSetup;
+import org.hibernate.test.cache.jbc2.functional.util.TestCacheInstanceManager;
+import org.hibernate.test.cache.jbc2.functional.util.TestJBossCacheRegionFactory;
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheManager;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Region;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tests entity and query caching when class of objects being cached are not
+ * visible to JBoss Cache's classloader. Also serves as a general integration
+ * test.
+ * <p/>
+ * This test stores an object (AccountHolder) that isn't visible to the JBC
+ * classloader in the cache in two places:
+ *
+ * 1) As part of the value tuple in an Account entity
+ * 2) As part of the FQN in a query cache entry (see query in
+ * ClassLoaderTestDAO.getBranch())
+ */
+public class PessimisticIsolatedClassLoaderTest
+extends DualNodeTestCaseBase
+{
+ public static final String OUR_PACKAGE =
PessimisticIsolatedClassLoaderTest.class.getPackage().getName();
+
+ private static final String CACHE_CONFIG = "pessimistic-shared";
+
+ protected static final long SLEEP_TIME = 300L;
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+
+ static int test = 0;
+
+ public PessimisticIsolatedClassLoaderTest(String name)
+ {
+ super(name);
+ }
+
+ public static Test suite() throws Exception {
+ TestSuite suite = new TestSuite(PessimisticIsolatedClassLoaderTest.class);
+ String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE +
".AccountHolder" };
+ return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
+ }
+
+ @Override
+ protected Class getCacheRegionFactory()
+ {
+ return TestJBossCacheRegionFactory.class;
+ }
+
+ @Override
+ protected boolean getUseQueryCache()
+ {
+ return true;
+ }
+
+ @Override
+ public String[] getMappings()
+ {
+ return new String[] { "cache/jbc2/functional/classloader/Account.hbm.xml"
};
+ }
+
+ @Override
+ protected void configureCacheFactory(Configuration cfg)
+ {
+ cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP,
+ getEntityCacheConfigName());
+ cfg.setProperty(MultiplexingCacheInstanceManager.TIMESTAMP_CACHE_RESOURCE_PROP,
+ getEntityCacheConfigName());
+ }
+
+ protected String getEntityCacheConfigName() {
+ return CACHE_CONFIG;
+ }
+
+ @Override
+ protected void cleanupTransactionManagement() {
+ // Don't clean up the managers, just the transactions
+ // Managers are still needed by the long-lived caches
+ DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+ }
+
+ /**
+ * Simply confirms that the test fixture's classloader isolation setup
+ * is functioning as expected.
+ *
+ * @throws Exception
+ */
+ public void testIsolatedSetup() throws Exception
+ {
+ // Bind a listener to the "local" cache
+ // Our region factory makes its CacheManager available to us
+ org.jboss.cache.CacheManager localManager =
TestCacheInstanceManager.getTestCacheManager(DualNodeTestUtil.LOCAL);
+ org.jboss.cache.Cache localCache =
localManager.getCache(getEntityCacheConfigName(), true);
+
+ // Bind a listener to the "remote" cache
+ org.jboss.cache.CacheManager remoteManager =
TestCacheInstanceManager.getTestCacheManager(DualNodeTestUtil.REMOTE);
+ org.jboss.cache.Cache remoteCache =
remoteManager.getCache(getEntityCacheConfigName(), true);
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ log.info("TCCL is " + cl);
+ Thread.currentThread().setContextClassLoader(cl.getParent());
+
+ org.jboss.cache.Fqn fqn = org.jboss.cache.Fqn.fromString("/isolated1");
+ org.jboss.cache.Region r = localCache.getRegion(fqn, true);
+ r.activate();
+
+ r = remoteCache.getRegion(fqn, true);
+ r.activate();
+ Thread.currentThread().setContextClassLoader(cl);
+ Account acct = new Account();
+ acct.setAccountHolder(new AccountHolder());
+
+ try
+ {
+ localCache.put(fqn, "key", acct);
+ fail("Should not have succeeded in putting acct -- classloader not
isolated");
+ }
+ catch (Exception e) {
+ log.info("Caught exception as desired", e);
+ }
+
+ localCache.getRegion(fqn,
false).registerContextClassLoader(Thread.currentThread().getContextClassLoader());
+ remoteCache.getRegion(fqn,
false).registerContextClassLoader(Thread.currentThread().getContextClassLoader());
+
+ localCache.put(fqn, "key", acct);
+ assertEquals(acct.getClass().getName(), remoteCache.get(fqn,
"key").getClass().getName());
+ }
+
+ public void testClassLoaderHandlingNamedQueryRegion() throws Exception {
+ queryTest(true);
+ }
+
+ public void testClassLoaderHandlingStandardQueryCache() throws Exception {
+ queryTest(false);
+ }
+
+ protected void queryTest(boolean useNamedRegion) throws Exception
+ {
+ // Bind a listener to the "local" cache
+ // Our region factory makes its CacheManager available to us
+ CacheManager localManager =
TestCacheInstanceManager.getTestCacheManager(DualNodeTestUtil.LOCAL);
+ Cache localCache = localManager.getCache(getEntityCacheConfigName(), true);
+ CacheAccessListener localListener = new CacheAccessListener();
+ localCache.addCacheListener(localListener);
+
+ TransactionManager localTM =
localCache.getConfiguration().getRuntimeConfig().getTransactionManager();
+
+ // Bind a listener to the "remote" cache
+ CacheManager remoteManager =
TestCacheInstanceManager.getTestCacheManager(DualNodeTestUtil.REMOTE);
+ Cache remoteCache = remoteManager.getCache(getEntityCacheConfigName(), true);
+ CacheAccessListener remoteListener = new CacheAccessListener();
+ remoteCache.addCacheListener(remoteListener);
+
+ TransactionManager remoteTM =
remoteCache.getConfiguration().getRuntimeConfig().getTransactionManager();
+
+ SessionFactory localFactory = getEnvironment().getSessionFactory();
+ SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
+
+ ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO(localFactory, localTM);
+ ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO(remoteFactory, remoteTM);
+
+ // Determine whether our query region is already there (in which case it
+ // will receive remote messages immediately) or is yet to be created on
+ // first use (in which case it will initially discard remote messages)
+ String regionName = createRegionName(useNamedRegion ? "AccountRegion" :
StandardQueryCache.class.getName());
+ Region queryRegion = remoteCache.getRegion(Fqn.fromString(regionName), false);
+ boolean queryRegionExists = queryRegion != null && queryRegion.isActive();
+
+ // Initial ops on node 0
+ setupEntities(dao0);
+
+ // Query on post code count
+ assertEquals("63088 has correct # of accounts", 6,
dao0.getCountForBranch("63088", useNamedRegion));
+
+ assertTrue("Query cache used " + regionName,
+ localListener.getSawRegionModification(regionName));
+ // Clear the access state
+ localListener.getSawRegionAccess(regionName);
+
+ log.info("First query on node0 done");
+
+ // Sleep a bit to allow async repl to happen
+ sleep(SLEEP_TIME);
+
+ // If region isn't activated yet, should not have been modified
+ if (!queryRegionExists)
+ {
+ assertFalse("Query cache remotely modified " + regionName,
+ remoteListener.getSawRegionModification(regionName));
+ // Clear the access state
+ remoteListener.getSawRegionAccess(regionName);
+ }
+ else
+ {
+ assertTrue("Query cache remotely modified " + regionName,
+ remoteListener.getSawRegionModification(regionName));
+ // Clear the access state
+ remoteListener.getSawRegionAccess(regionName);
+ }
+
+ // Do query again from node 1
+ assertEquals("63088 has correct # of accounts", 6,
dao1.getCountForBranch("63088", useNamedRegion));
+
+ if (!queryRegionExists)
+ {
+ // Query should have activated the region and then been inserted
+ assertTrue("Query cache modified " + regionName,
+ remoteListener.getSawRegionModification(regionName));
+ // Clear the access state
+ remoteListener.getSawRegionAccess(regionName);
+ }
+
+ log.info("First query on node 1 done");
+
+ // We now have the query cache region activated on both nodes.
+
+ // Sleep a bit to allow async repl to happen
+ sleep(SLEEP_TIME);
+
+ // Do some more queries on node 0
+
+ assertEquals("Correct branch for Smith", "94536",
dao0.getBranch(dao0.getSmith(), useNamedRegion));
+
+ assertEquals("Correct high balances for Jones", 40,
dao0.getTotalBalance(dao0.getJones(), useNamedRegion));
+
+ assertTrue("Query cache used " + regionName,
+ localListener.getSawRegionModification(regionName));
+ // Clear the access state
+ localListener.getSawRegionAccess(regionName);
+
+ log.info("Second set of queries on node0 done");
+
+ // Sleep a bit to allow async repl to happen
+ sleep(SLEEP_TIME);
+
+ // Check if the previous queries replicated
+ assertTrue("Query cache remotely modified " + regionName,
+ remoteListener.getSawRegionModification(regionName));
+ // Clear the access state
+ remoteListener.getSawRegionAccess(regionName);
+
+ // Do queries again from node 1
+ assertEquals("Correct branch for Smith", "94536",
dao1.getBranch(dao1.getSmith(), useNamedRegion));
+
+ assertEquals("Correct high balances for Jones", 40,
dao1.getTotalBalance(dao1.getJones(), useNamedRegion));
+
+ // Should be no change; query was already there
+ assertFalse("Query cache modified " + regionName,
+ remoteListener.getSawRegionModification(regionName));
+ assertTrue("Query cache accessed " + regionName,
+ remoteListener.getSawRegionAccess(regionName));
+
+ log.info("Second set of queries on node1 done");
+
+ // allow async to propagate
+ sleep(SLEEP_TIME);
+
+ // Modify underlying data on node 1
+ modifyEntities(dao1);
+
+ // allow async timestamp change to propagate
+ sleep(SLEEP_TIME);
+
+ // Confirm query results are correct on node 0
+
+ assertEquals("63088 has correct # of accounts", 7,
dao0.getCountForBranch("63088", useNamedRegion));
+
+ assertEquals("Correct branch for Smith", "63088",
dao0.getBranch(dao0.getSmith(), useNamedRegion));
+
+ assertEquals("Correct high balances for Jones", 50,
dao0.getTotalBalance(dao0.getJones(), useNamedRegion));
+
+ log.info("Third set of queries on node0 done");
+ }
+
+ protected String createRegionName(String noPrefix)
+ {
+ String combined = getRegionPrefix() == null ? noPrefix : getRegionPrefix() +
'.' + noPrefix;
+ return BasicRegionAdapter.getTypeLastRegionFqn(combined, getRegionPrefix(),
QueryResultsRegionImpl.TYPE).toString();
+ }
+
+ protected void setupEntities(ClassLoaderTestDAO dao) throws Exception
+ {
+ dao.cleanup();
+
+ dao.createAccount(dao.getSmith(), new Integer(1001), new Integer(5),
"94536");
+ dao.createAccount(dao.getSmith(), new Integer(1002), new Integer(15),
"94536");
+ dao.createAccount(dao.getSmith(), new Integer(1003), new Integer(20),
"94536");
+
+ dao.createAccount(dao.getJones(), new Integer(2001), new Integer(5),
"63088");
+ dao.createAccount(dao.getJones(), new Integer(2002), new Integer(15),
"63088");
+ dao.createAccount(dao.getJones(), new Integer(2003), new Integer(20),
"63088");
+
+ dao.createAccount(dao.getBarney(), new Integer(3001), new Integer(5),
"63088");
+ dao.createAccount(dao.getBarney(), new Integer(3002), new Integer(15),
"63088");
+ dao.createAccount(dao.getBarney(), new Integer(3003), new Integer(20),
"63088");
+
+ log.info("Standard entities created");
+ }
+
+ protected void resetRegionUsageState(CacheAccessListener localListener,
CacheAccessListener remoteListener)
+ {
+ String stdName = createRegionName(StandardQueryCache.class.getName());
+ String acctName = createRegionName("AccountRegion");
+
+ localListener.getSawRegionModification(stdName);
+ localListener.getSawRegionModification(acctName);
+
+ localListener.getSawRegionAccess(stdName);
+ localListener.getSawRegionAccess(acctName);
+
+ remoteListener.getSawRegionModification(stdName);
+ remoteListener.getSawRegionModification(acctName);
+
+ remoteListener.getSawRegionAccess(stdName);
+ remoteListener.getSawRegionAccess(acctName);
+
+ log.info("Region usage state cleared");
+ }
+
+ protected void modifyEntities(ClassLoaderTestDAO dao) throws Exception
+ {
+ dao.updateAccountBranch(1001, "63088");
+ dao.updateAccountBalance(2001, 15);
+
+ log.info("Entities modified");
+ }
+}
Property changes on:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/PessimisticIsolatedClassLoaderTest.java
___________________________________________________________________
Name: svn:executable
+ *
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/CustomClassLoaderCacheFactory.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/CustomClassLoaderCacheFactory.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/CustomClassLoaderCacheFactory.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.hibernate.test.cache.jbc2.functional.util;
+
+import org.jboss.cache.CacheImpl;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.Configuration;
+
+/**
+ * CacheFactory impl that allows us to register a desired default classloader
+ * for deserializing RPCs.
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
+ */
+public class CustomClassLoaderCacheFactory<K, V> extends DefaultCacheFactory<K,
V>
+{
+ private ClassLoader customClassLoader;
+
+ /**
+ * Create a new CustomClassLoaderCacheFactory.
+ */
+ public CustomClassLoaderCacheFactory(ClassLoader customClassLoader)
+ {
+ super();
+ this.customClassLoader = customClassLoader;
+ }
+
+ @Override
+ protected void bootstrap(CacheImpl cache, CacheSPI spi, Configuration configuration)
+ {
+ super.bootstrap(cache, spi, configuration);
+
+ // Replace the deployerClassLoader
+ componentRegistry.registerComponent("deployerClassLoader",
customClassLoader, ClassLoader.class);
+ }
+
+}
Modified:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionImpl.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionImpl.java 2008-02-28
19:41:20 UTC (rev 14380)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionImpl.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -115,9 +115,11 @@
}
}
- for ( int i = 0; i < synchronizations.size(); i++ ) {
- Synchronization s = ( Synchronization ) synchronizations.get( i );
- s.afterCompletion( status );
+ if (synchronizations != null) {
+ for ( int i = 0; i < synchronizations.size(); i++ ) {
+ Synchronization s = ( Synchronization ) synchronizations.get( i );
+ s.afterCompletion( status );
+ }
}
//status = Status.STATUS_NO_TRANSACTION;
Modified:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionManagerImpl.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionManagerImpl.java 2008-02-28
19:41:20 UTC (rev 14380)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/DualNodeJtaTransactionManagerImpl.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -35,6 +35,11 @@
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
+import org.hibernate.test.cache.jbc2.functional.classloader.ClassLoaderTestDAO;
+import org.hsqldb.lib.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Variant of SimpleJtaTransactionManagerImpl that doesn't use a VM-singleton,
* but rather a set of impls keyed by a node id.
@@ -42,18 +47,44 @@
* @author Brian Stansberry
*/
public class DualNodeJtaTransactionManagerImpl implements TransactionManager {
- private static final Hashtable INSTANCES = new Hashtable();
+
+ private static final Logger log =
LoggerFactory.getLogger(DualNodeJtaTransactionManagerImpl.class);
+
+ private static final Hashtable INSTANCES = new Hashtable();
private DualNodeJtaTransactionImpl currentTransaction;
-
+ private String nodeId;
+
public synchronized static DualNodeJtaTransactionManagerImpl getInstance(String nodeId)
{
DualNodeJtaTransactionManagerImpl tm = (DualNodeJtaTransactionManagerImpl)
INSTANCES.get(nodeId);
if (tm == null) {
- tm = new DualNodeJtaTransactionManagerImpl();
+ tm = new DualNodeJtaTransactionManagerImpl(nodeId);
INSTANCES.put(nodeId, tm);
}
return tm;
}
+
+ public synchronized static void cleanupTransactions() {
+ for (java.util.Iterator it = INSTANCES.values().iterator(); it.hasNext();) {
+ TransactionManager tm = (TransactionManager) it.next();
+ try
+ {
+ tm.suspend();
+ }
+ catch (Exception e)
+ {
+ log.error("Exception cleaning up TransactionManager " + tm);
+ }
+ }
+ }
+
+ public synchronized static void cleanupTransactionManagers() {
+ INSTANCES.clear();
+ }
+
+ private DualNodeJtaTransactionManagerImpl(String nodeId) {
+ this.nodeId = nodeId;
+ }
public int getStatus() throws SystemException {
return currentTransaction == null ? Status.STATUS_NO_TRANSACTION :
currentTransaction.getStatus();
@@ -72,7 +103,8 @@
}
public Transaction suspend() throws SystemException {
- DualNodeJtaTransactionImpl suspended = currentTransaction;
+ log.trace(nodeId + ": Suspending " + currentTransaction + " for
thread " + Thread.currentThread().getName());
+ DualNodeJtaTransactionImpl suspended = currentTransaction;
currentTransaction = null;
return suspended;
}
@@ -80,6 +112,7 @@
public void resume(Transaction transaction)
throws InvalidTransactionException, IllegalStateException, SystemException {
currentTransaction = ( DualNodeJtaTransactionImpl ) transaction;
+ log.trace(nodeId + ": Resumed " + currentTransaction + " for thread
" + Thread.currentThread().getName());
}
public void commit()
@@ -112,4 +145,12 @@
currentTransaction = null;
}
}
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("[nodeId=");
+ sb.append(nodeId);
+ sb.append("]");
+ return sb.toString();
+ }
}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/IsolatedCacheTestSetup.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/IsolatedCacheTestSetup.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/IsolatedCacheTestSetup.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.hibernate.test.cache.jbc2.functional.util;
+
+import junit.framework.Test;
+
+import org.hibernate.test.util.SelectedClassnameClassLoader;
+import org.hibernate.test.util.SelectedClassnameClassLoaderTestSetup;
+import org.jboss.cache.Cache;
+import org.jboss.cache.config.Configuration;
+
+/**
+ * A TestSetup that uses SelectedClassnameClassLoader to ensure that
+ * certain classes are not visible to JBoss Cache or JGroups' classloader.
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class IsolatedCacheTestSetup extends SelectedClassnameClassLoaderTestSetup
+{
+
+ public static final String DEF_CACHE_FACTORY_RESOURCE =
"org/hibernate/cache/jbc2/builder/jbc2-configs.xml";
+ public static final String DEF_JGROUPS_RESOURCE =
"org/hibernate/cache/jbc2/builder/jgroups-stacks.xml";
+
+ private String[] isolatedClasses;
+ private String cacheConfig;
+
+ /**
+ * Create a new IsolatedCacheTestSetup.
+ */
+ public IsolatedCacheTestSetup(Test test,
+ String[] isolatedClasses,
+ String cacheConfig)
+ {
+ super(test, null, null, isolatedClasses);
+ this.isolatedClasses = isolatedClasses;
+ this.cacheConfig = cacheConfig;
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ // At this point the TCCL cannot see the isolatedClasses
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+
+ org.jgroups.ChannelFactory cf = new org.jgroups.JChannelFactory();
+ cf.setMultiplexerConfig(DEF_JGROUPS_RESOURCE);
+
+ org.jboss.cache.CacheManagerImpl cm = new
org.jboss.cache.CacheManagerImpl(DEF_CACHE_FACTORY_RESOURCE, cf);
+ cm.start();
+ TestCacheInstanceManager.addTestCacheManager(DualNodeTestUtil.LOCAL, cm);
+
+ // Inject the desired defaultClassLoader into our caches
+ Configuration cfg = cm.getConfigurationRegistry().getConfiguration(cacheConfig);
+ Cache cache = new CustomClassLoaderCacheFactory(tccl).createCache(cfg, false);
+
cache.getConfiguration().getRuntimeConfig().setMuxChannelFactory(cm.getChannelFactory());
+ cm.registerCache(cache, cacheConfig);
+
+ cf = new org.jgroups.JChannelFactory();
+ cf.setMultiplexerConfig(DEF_JGROUPS_RESOURCE);
+
+ cm = new org.jboss.cache.CacheManagerImpl(DEF_CACHE_FACTORY_RESOURCE, cf);
+ cm.start();
+ TestCacheInstanceManager.addTestCacheManager(DualNodeTestUtil.REMOTE, cm);
+
+ cfg = cm.getConfigurationRegistry().getConfiguration(cacheConfig);
+ cache = new CustomClassLoaderCacheFactory(tccl).createCache(cfg, false);
+
cache.getConfiguration().getRuntimeConfig().setMuxChannelFactory(cm.getChannelFactory());
+ cm.registerCache(cache, cacheConfig);
+
+ // Now make the isolatedClasses visible
+ SelectedClassnameClassLoader visible = new
SelectedClassnameClassLoader(isolatedClasses, null, null, tccl);
+ Thread.currentThread().setContextClassLoader(visible);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try {
+ super.tearDown();
+ }
+ finally {
+ TestCacheInstanceManager.clearCacheManagers();
+ DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+ DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
+ }
+ }
+
+}
Modified:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/TestCacheInstanceManager.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/TestCacheInstanceManager.java 2008-02-28
19:41:20 UTC (rev 14380)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/util/TestCacheInstanceManager.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -30,6 +30,9 @@
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
import org.hibernate.cfg.Settings;
import org.jboss.cache.CacheManager;
+import org.jboss.cache.CacheManagerImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
@@ -40,6 +43,8 @@
* @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
*/
public class TestCacheInstanceManager extends MultiplexingCacheInstanceManager {
+
+ private static final Logger log =
LoggerFactory.getLogger(TestCacheInstanceManager.class);
private static final Hashtable cacheManagers = new Hashtable();
@@ -47,7 +52,28 @@
return (CacheManager) cacheManagers.get(name);
}
+ public static void addTestCacheManager(String name,CacheManager manager) {
+ cacheManagers.put(name, manager);
+ }
+
+ public static void clearCacheManagers() {
+ for (java.util.Iterator it = cacheManagers.values().iterator(); it.hasNext();) {
+ CacheManager cm = (CacheManager) it.next();
+ try
+ {
+ if (cm instanceof CacheManagerImpl)
+ ((CacheManagerImpl) cm).stop();
+ }
+ catch (Exception e)
+ {
+ log.error("Exception cleaning up CacheManager " + cm);
+ }
+ }
+ cacheManagers.clear();
+ }
+
private String cacheManagerName;
+ private boolean locallyAdded;
/**
* Create a new TestCacheInstanceManager.
@@ -58,17 +84,26 @@
@Override
public void start(Settings settings, Properties properties) throws CacheException {
+
+ cacheManagerName = properties.getProperty(DualNodeTestUtil.NODE_ID_PROP);
+ CacheManager existing = getTestCacheManager(cacheManagerName);
+ locallyAdded = (existing == null);
+ if (!locallyAdded) {
+ setCacheFactory(existing);
+ }
+
super.start(settings, properties);
- cacheManagerName = properties.getProperty(DualNodeTestUtil.NODE_ID_PROP);
- cacheManagers.put(cacheManagerName, getCacheFactory());
+ if (locallyAdded)
+ cacheManagers.put(cacheManagerName, getCacheFactory());
}
@Override
public void stop()
{
- cacheManagers.remove(cacheManagerName);
+ if (locallyAdded)
+ cacheManagers.remove(cacheManagerName);
super.stop();
}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoader.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoader.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoader.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,288 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A ClassLoader that loads classes whose classname begins with one of a
+ * given set of strings, without attempting first to delegate to its
+ * parent loader.
+ * <p>
+ * This class is intended to allow emulation of 2 different types of common J2EE
+ * classloading situations.
+ * <ul>
+ * <li>Servlet-style child-first classloading, where this class is the
+ * child loader.</li>
+ * <li>Parent-first classloading where the parent does not have access to
+ * certain classes</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This class can also be configured to raise a ClassNotFoundException if
+ * asked to load certain classes, thus allowing classes on the classpath
+ * to be hidden from a test environment.
+ * </p>
+ *
+ * @author Brian Stansberry
+ */
+public class SelectedClassnameClassLoader extends ClassLoader
+{
+ private Logger log = LoggerFactory.getLogger(SelectedClassnameClassLoader.class);
+
+ private String[] includedClasses = null;
+ private String[] excludedClasses = null;
+ private String[] notFoundClasses = null;
+
+ private Map<String, Class> classes = new java.util.HashMap<String,
Class>();
+
+ /**
+ * Creates a new classloader that loads the given classes.
+ *
+ * @param includedClasses array of class or package names that should be
+ * directly loaded by this loader. Classes
+ * whose name starts with any of the strings
+ * in this array will be loaded by this class,
+ * unless their name appears in
+ * <code>excludedClasses</code>.
+ * Can be <code>null</code>
+ * @param excludedClasses array of class or package names that should NOT
+ * be directly loaded by this loader. Loading of
+ * classes whose name starts with any of the
+ * strings in this array will be delegated to
+ * <code>parent</code>, even if the classes
+ * package or classname appears in
+ * <code>includedClasses</code>. Typically this
+ * parameter is used to exclude loading one or
+ * more classes in a package whose other classes
+ * are loaded by this object.
+ * @param parent ClassLoader to which loading of classes should
+ * be delegated if necessary
+ */
+ public SelectedClassnameClassLoader(String[] includedClasses,
+ String[] excludedClasses,
+ ClassLoader parent)
+ {
+ this(includedClasses, excludedClasses, null, parent);
+ }
+
+ /**
+ * Creates a new classloader that loads the given classes.
+ *
+ * @param includedClasses array of class or package names that should be
+ * directly loaded by this loader. Classes
+ * whose name starts with any of the strings
+ * in this array will be loaded by this class,
+ * unless their name appears in
+ * <code>excludedClasses</code>.
+ * Can be <code>null</code>
+ * @param excludedClasses array of class or package names that should NOT
+ * be directly loaded by this loader. Loading of
+ * classes whose name starts with any of the
+ * strings in this array will be delegated to
+ * <code>parent</code>, even if the classes
+ * package or classname appears in
+ * <code>includedClasses</code>. Typically this
+ * parameter is used to exclude loading one or
+ * more classes in a package whose other classes
+ * are loaded by this object.
+ * @param notFoundClasses array of class or package names for which this
+ * should raise a ClassNotFoundException
+ * @param parent ClassLoader to which loading of classes should
+ * be delegated if necessary
+ */
+ public SelectedClassnameClassLoader(String[] includedClasses,
+ String[] excludedClasses,
+ String[] notFoundClasses,
+ ClassLoader parent)
+ {
+ super(parent);
+ this.includedClasses = includedClasses;
+ this.excludedClasses = excludedClasses;
+ this.notFoundClasses = notFoundClasses;
+
+ log.debug("created " + this);
+ }
+
+ protected synchronized Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ log.trace("loadClass(" + name + "," + resolve +
")");
+ if (isIncluded(name) && (isExcluded(name) == false))
+ {
+ Class c = findClass(name);
+
+ if (resolve)
+ {
+ resolveClass(c);
+ }
+ return c;
+ }
+ else if (isNotFound(name))
+ {
+ throw new ClassNotFoundException(name + " is discarded");
+ }
+ else
+ {
+ return super.loadClass(name, resolve);
+ }
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ log.trace("findClass(" + name + ")");
+ Class result = classes.get(name);
+ if (result != null)
+ {
+ return result;
+ }
+
+ if (isIncluded(name) && (isExcluded(name) == false))
+ {
+ result = createClass(name);
+ }
+ else if (isNotFound(name))
+ {
+ throw new ClassNotFoundException(name + " is discarded");
+ }
+ else
+ {
+ result = super.findClass(name);
+ }
+
+ classes.put(name, result);
+
+ return result;
+ }
+
+ protected Class createClass(String name) throws ClassFormatError,
ClassNotFoundException
+ {
+ log.info("createClass(" + name + ")");
+ try
+ {
+ InputStream is = getResourceAsStream(name.replace('.',
'/').concat(".class"));
+ byte[] bytes = new byte[1024];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ int read;
+ while ((read = is.read(bytes)) > -1)
+ {
+ baos.write(bytes, 0, read);
+ }
+ bytes = baos.toByteArray();
+ return this.defineClass(name, bytes, 0, bytes.length);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new ClassNotFoundException("cannot find " + name, e);
+ }
+ catch (IOException e)
+ {
+ throw new ClassNotFoundException("cannot read " + name, e);
+ }
+ }
+
+ protected boolean isIncluded(String className)
+ {
+
+ if (includedClasses != null)
+ {
+ for (int i = 0; i < includedClasses.length; i++)
+ {
+ if (className.startsWith(includedClasses[i]))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean isExcluded(String className)
+ {
+
+ if (excludedClasses != null)
+ {
+ for (int i = 0; i < excludedClasses.length; i++)
+ {
+ if (className.startsWith(excludedClasses[i]))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean isNotFound(String className)
+ {
+
+ if (notFoundClasses != null)
+ {
+ for (int i = 0; i < notFoundClasses.length; i++)
+ {
+ if (className.startsWith(notFoundClasses[i]))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public String toString() {
+ String s = getClass().getName();
+ s += "[includedClasses=";
+ s += listClasses(includedClasses);
+ s += ";excludedClasses=";
+ s += listClasses(excludedClasses);
+ s += ";notFoundClasses=";
+ s += listClasses(notFoundClasses);
+ s += ";parent=";
+ s += getParent();
+ s += "]";
+ return s;
+ }
+
+ private static String listClasses(String[] classes) {
+ if (classes == null) return null;
+ String s = "";
+ for (int i = 0; i < classes.length; i++) {
+ if (i > 0)
+ s += ",";
+ s += classes[i];
+ }
+ return s;
+ }
+
+}
Added:
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoaderTestSetup.java
===================================================================
---
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoaderTestSetup.java
(rev 0)
+++
core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test/util/SelectedClassnameClassLoaderTestSetup.java 2008-02-28
19:42:08 UTC (rev 14381)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.hibernate.test.util;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+/**
+ * A TestSetup that makes SelectedClassnameClassLoader the thread
+ * context classloader for the duration of the test.
+ *
+ * @author <a href="brian.stansberry(a)jboss.com">Brian
Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class SelectedClassnameClassLoaderTestSetup extends TestSetup
+{
+ private ClassLoader originalTCCL;
+ private String[] includedClasses;
+ private String[] excludedClasses;
+ private String[] notFoundClasses;
+
+
+ /**
+ * Create a new SelectedClassnameClassLoaderTestSetup.
+ *
+ * @param test
+ */
+ public SelectedClassnameClassLoaderTestSetup(Test test,
+ String[] includedClasses,
+ String[] excludedClasses,
+ String[] notFoundClasses)
+ {
+ super(test);
+ this.includedClasses = includedClasses;
+ this.excludedClasses = excludedClasses;
+ this.notFoundClasses = notFoundClasses;
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ originalTCCL = Thread.currentThread().getContextClassLoader();
+ ClassLoader parent = originalTCCL == null ? getClass().getClassLoader() :
originalTCCL;
+ ClassLoader selectedTCCL = new SelectedClassnameClassLoader(includedClasses,
excludedClasses, notFoundClasses, parent);
+ Thread.currentThread().setContextClassLoader(selectedTCCL);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ Thread.currentThread().setContextClassLoader(originalTCCL);
+ super.tearDown();
+ }
+
+
+
+}