/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.test.cmp2.ageout.test;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import org.jboss.ejb.plugins.cmp.jdbc.JDBCUtil;
import org.jboss.ejb.plugins.cmp.jdbc2.schema.Cache;
import org.jboss.test.JBossTestCase;
import org.jboss.test.util.ejb.EJBTestCase;
import org.jboss.test.cmp2.ejbselect.ALocal;
import org.jboss.test.cmp2.ejbselect.ALocalHome;
import org.jboss.test.cmp2.ejbselect.AUtil;
import org.jboss.mx.util.MBeanServerLocator;
import junit.framework.Test;
/**
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
* @version <tt>$Revision: 81036 $</tt>
*/
public class JDBC2PmAgeOutUnitTestCase
extends EJBTestCase
{
private int maxAgeMs = 3000;
private int overagerPeriodMs = 1000;
private DataSource ds;
private TransactionManager tm;
private CacheListener cacheListener;
public JDBC2PmAgeOutUnitTestCase(String methodName)
{
super(methodName);
}
public static Test suite() throws Exception
{
return JBossTestCase.getDeploySetup(JDBC2PmAgeOutUnitTestCase.class, "cmp2-jdbc2pm-ageout.jar");
}
public void setUpEJB(Properties props) throws Exception
{
MBeanServer server = MBeanServerLocator.locateJBoss();
cacheListener = new CacheListener();
server.invoke(new ObjectName("jboss.cmp:ejbname=A,service=tablecache,table=TEST_A"),
"registerListener", new Object[]{
cacheListener
}, new String[]{Cache.Listener.class.getName()});
}
public void testAgeOut() throws Exception
{
Transaction tx = suspendTx();
String id = "a1";
try
{
beginTx();
ALocalHome ah = AUtil.getLocalHome();
ALocal a = ah.create(id);
a.setIntField(1);
commitTx();
long lastUpdated = System.currentTimeMillis();
checkAge(lastUpdated);
assertValue(id, 1);
checkAge(lastUpdated);
jdbcUpdate(id, 2);
checkAge(lastUpdated);
assertValue(id, 1);
sleepUntilEvicted();
long lastEvicted = cacheListener.lastEvicted;
assertValue(id, 2);
// test ejb update
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
beginTx();
a = ah.findByPrimaryKey(id);
a.setIntField(3);
commitTx();
sleepUntilEvicted();
assertTrue(cacheListener.lastEvicted - lastEvicted >= maxAgeMs + 1000);
}
finally
{
resumeTx(tx);
}
}
private void sleepUntilEvicted()
{
int sleepTime = 0;
while(!cacheListener.evicted)
{
try
{
Thread.sleep(1000);
sleepTime += 1000;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
if(!cacheListener.evicted && sleepTime > maxAgeMs + overagerPeriodMs)
{
fail("The instance must have been evicted!");
}
}
cacheListener.evicted = false;
}
private void checkAge(long lastUpdated)
throws Exception
{
if(System.currentTimeMillis() - lastUpdated > maxAgeMs)
{
throw new Exception("maxAgeMs should be increased for this test to work.");
}
}
private void assertValue(String id, int value) throws Exception
{
beginTx();
try
{
ALocalHome ah = AUtil.getLocalHome();
ALocal a = ah.findByPrimaryKey(id);
assertEquals(value, a.getIntField());
}
finally
{
commitTx();
}
}
private void jdbcUpdate(String id, int value) throws Exception
{
DataSource ds = getDS();
Connection con = null;
Statement st = null;
try
{
con = ds.getConnection();
st = con.createStatement();
int rows = st.executeUpdate("update TEST_A set INT_FIELD=" +
value + " where ID='" + id + "'"
);
if(rows != 1)
{
throw new Exception("Expected one updated row but got " + rows);
}
}
finally
{
JDBCUtil.safeClose(st);
JDBCUtil.safeClose(con);
}
}
private DataSource getDS() throws NamingException
{
if(ds == null)
{
ds = (DataSource)new InitialContext().lookup("java:/DefaultDS");
}
return ds;
}
private Transaction suspendTx() throws Exception
{
return getTM().suspend();
}
private void resumeTx(Transaction tx) throws Exception
{
getTM().resume(tx);
}
private Transaction beginTx() throws Exception
{
getTM().begin();
return getTM().getTransaction();
}
private void commitTx() throws Exception
{
getTM().commit();
}
private TransactionManager getTM()
throws NamingException
{
if(tm == null)
{
tm = (TransactionManager)new InitialContext().lookup("java:/TransactionManager");
}
return tm;
}
private static class CacheListener implements Cache.Listener
{
public long lastEvicted;
public boolean evicted;
public void contention(int partitionIndex, long time)
{
}
public void eviction(int partitionIndex, Object pk, int size)
{
lastEvicted = System.currentTimeMillis();
evicted = true;
}
public void hit(int partitionIndex)
{
}
public void miss(int partitionIndex)
{
}
}
}