Add tests of isolated-classloader environments
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14381 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
ed518d42c0
commit
ada6552638
|
@ -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.dialect.Dialect;
|
|||
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,11 +141,21 @@ public abstract class DualNodeTestCaseBase extends CacheTestCaseBase
|
|||
@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() {
|
||||
|
|
46
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
vendored
Executable file
46
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.hbm.xml
vendored
Executable file
|
@ -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>
|
142
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java
vendored
Normal file
142
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/classloader/Account.java
vendored
Normal file
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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@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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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@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);
|
||||
}
|
||||
|
||||
}
|
|
@ -115,9 +115,11 @@ public class DualNodeJtaTransactionImpl implements Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -35,6 +35,11 @@ import javax.transaction.SystemException;
|
|||
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 @@ import javax.transaction.TransactionManager;
|
|||
* @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 class DualNodeJtaTransactionManagerImpl implements TransactionManager {
|
|||
}
|
||||
|
||||
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 class DualNodeJtaTransactionManagerImpl implements TransactionManager {
|
|||
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 @@ public class DualNodeJtaTransactionManagerImpl implements TransactionManager {
|
|||
currentTransaction = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(getClass().getName());
|
||||
sb.append("[nodeId=");
|
||||
sb.append(nodeId);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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@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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,9 @@ import org.hibernate.cache.CacheException;
|
|||
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 @@ import org.jboss.cache.CacheManager;
|
|||
* @author <a href="brian.stansberry@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 @@ public class TestCacheInstanceManager extends MultiplexingCacheInstanceManager {
|
|||
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 @@ public class TestCacheInstanceManager extends MultiplexingCacheInstanceManager {
|
|||
|
||||
@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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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@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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue