[hibernate-commits] Hibernate SVN: r14381 - in core/trunk/cache-jbosscache2/src/test/java/org/hibernate/test: cache/jbc2/functional/classloader and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Feb 28 14:42:08 EST 2008


Author: bstansberry at 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={@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={@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={@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={@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={@QueryHint(name="org.hibernate.cacheable",value="true")}),
+//   @NamedQuery(name="account.bybranch.namedregion",query="select account from Account as account where account.branch = ?1",
+//               hints={@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;
+
+ at 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 at 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 at 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 at 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 at 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 at 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();
+   }
+   
+   
+
+}




More information about the hibernate-commits mailing list