/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., 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.as.test.integration.jpa.secondlevelcache;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import javax.ejb.Stateful;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import org.hibernate.Session;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics;
/**
* SFSB for Second level cache tests
*
* @author Zbynek Roubalik
*/
@Stateful
@TransactionManagement(TransactionManagementType.CONTAINER)
public class SFSB2LC {
@PersistenceUnit(unitName = "mypc")
EntityManagerFactory emf;
@PersistenceUnit(unitName = "mypc_no_2lc")
EntityManagerFactory emfNo2LC;
/**
* Check if disabling 2LC works as expected
*/
public String disabled2LCCheck() {
EntityManager em = emfNo2LC.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
try {
// check if entities are NOT cached in 2LC
String[] names = stats.getSecondLevelCacheRegionNames();
assertEquals("There aren't any 2LC regions.", 0, names.length);
createEmployee(em, "Martin", "Prague 132", 1);
assertEquals("There aren't any puts in the 2LC.", 0, stats.getSecondLevelCachePutCount());
// check if queries are NOT cached in 2LC
Employee emp = getEmployeeQuery(em, 1);
assertNotNull("Employee returned", emp);
assertEquals("There aren't any query puts in the 2LC.", 0, stats.getQueryCachePutCount());
// cleanup
em.remove(emp);
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Checking entity 2LC in one EntityManager session
*/
public String sameSessionCheck(String CACHE_REGION_NAME) {
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
SecondLevelCacheStatistics emp2LCStats = stats.getSecondLevelCacheStatistics(CACHE_REGION_NAME + "Employee");
try {
// add new entities and check if they are put in 2LC
createEmployee(em, "Peter", "Ostrava", 2);
createEmployee(em, "Tom", "Brno", 3);
assertEquals("There are 2 puts in the 2LC" + generateEntityCacheStats(emp2LCStats), 2, emp2LCStats.getPutCount());
// loading all Employee entities should put in 2LC all Employee
List<?> empList = getAllEmployeesQuery(em);
assertEquals("There are 2 entities.", empList.size(), 2);
assertEquals("There are 2 entities in the 2LC" + generateEntityCacheStats(emp2LCStats), 2, emp2LCStats.getElementCountInMemory());
// clear session
em.clear();
// entity should be loaded from 2L cache, we'are expecting hit in 2L cache
Employee emp = getEmployee(em, 2);
assertNotNull("Employee returned", emp);
assertEquals("Expected 1 hit in cache" + generateEntityCacheStats(emp2LCStats), 1, emp2LCStats.getHitCount());
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Checking entity 2LC in a different EntityManager session
*/
public String secondSessionCheck(String CACHE_REGION_NAME) {
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
SecondLevelCacheStatistics emp2LCStats = stats.getSecondLevelCacheStatistics(CACHE_REGION_NAME + "Employee");
try {
// add new entity
createEmployee(em, "David", "Praha", 10);
assertEquals("There is 1 put in the 2LC" + generateEntityCacheStats(emp2LCStats), 1, emp2LCStats.getPutCount());
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
EntityManager em2 = emf.createEntityManager();
try {
// loading entity stored in previous session, we'are expecting hit in cache
Employee emp = getEmployee(em2, 10);
assertNotNull("Employee returned", emp);
assertEquals("Expected 1 hit in 2LC" + generateEntityCacheStats(emp2LCStats), 1, emp2LCStats.getHitCount());
} catch (AssertionError e) {
return e.getMessage();
} finally {
em2.close();
}
return "OK";
}
/**
* Insert 2 entities and put them into the 2LC and then evicts entity cache.
*/
public String addEntitiesAndEvictAll(String CACHE_REGION_NAME) {
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
SecondLevelCacheStatistics emp2LCStats = stats.getSecondLevelCacheStatistics(CACHE_REGION_NAME + "Employee");
try {
createEmployee(em, "Jan", "Ostrava", 20);
createEmployee(em, "Martin", "Brno", 30);
assertEquals("There are 2 puts in the 2LC" + generateEntityCacheStats(emp2LCStats), 2, emp2LCStats.getPutCount());
assertTrue("Expected entities stored in the cache" + generateEntityCacheStats(emp2LCStats), emp2LCStats.getElementCountInMemory() > 0);
// evict entity 2lc
emf.getCache().evictAll();
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Checks if entity 2LC is empty.
*/
public String evictedEntityCacheCheck(String CACHE_REGION_NAME) {
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
SecondLevelCacheStatistics emp2LCStats = stats.getSecondLevelCacheStatistics(CACHE_REGION_NAME + "Employee");
try {
assertEquals("Expected no entities stored in the cache" + emp2LCStats, 0, emp2LCStats.getElementCountInMemory());
// loading entity stored in previous session, we are expecting miss in 2lc
Employee emp = getEmployee(em, 20);
assertNotNull("Employee returned", emp);
assertEquals("Expected 1 miss in 2LC" + generateEntityCacheStats(emp2LCStats), 1, emp2LCStats.getMissCount());
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Performs 2 query calls, first call put query in the cache and second should hit the cache
*
* @param id Employee's id in the query
*/
public String queryCacheCheck(String id) {
// the nextTimestamp from infinispan is "return System.currentTimeMillis()"
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
return e.getMessage();
}
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
try {
String queryString = "from Employee e where e.id > " + id;
QueryStatistics queryStats = stats.getQueryStatistics(queryString);
Query query = em.createQuery(queryString);
query.setHint("org.hibernate.cacheable", true);
// query - this call should fill the cache
query.getResultList();
assertEquals("Expected 1 miss in cache" + generateQueryCacheStats(queryStats), 1, queryStats.getCacheMissCount());
assertEquals("Expected 1 put in cache" + generateQueryCacheStats(queryStats), 1, queryStats.getCachePutCount());
assertEquals("Expected no hits in cache" + generateQueryCacheStats(queryStats), 0, queryStats.getCacheHitCount());
// query - second call should hit cache
query.getResultList();
assertEquals("Expected 1 hit in cache" + generateQueryCacheStats(queryStats), 1, queryStats.getCacheHitCount());
} catch (AssertionError e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Evicts all query cache regions
*/
public void evictQueryCache() {
EntityManager em = emf.createEntityManager();
try {
// this should evict query cache
em.unwrap(Session.class).getSessionFactory().getCache().evictDefaultQueryRegion();
} catch (Exception e) {
e.printStackTrace();
} finally {
em.close();
}
}
/**
* Checking if query cache is empty
*
* @param id Employee's id in the query
*/
public String queryCacheCheckIfEmpty(String id) {
EntityManager em = emf.createEntityManager();
Statistics stats = em.unwrap(Session.class).getSessionFactory().getStatistics();
stats.clear();
try {
// the nextTimestamp from infinispan is "return System.currentTimeMillis() / 100;"
Thread.sleep(1000);
String queryString = "from Employee e where e.id > " + id;
QueryStatistics queryStats = stats.getQueryStatistics(queryString);
Query query = em.createQuery(queryString);
query.setHint("org.hibernate.cacheable", true);
// query - this call shouldn't hit the cache -> query cache is empty
query.getResultList();
assertEquals("Expected 1 miss in cache" + generateQueryCacheStats(queryStats), 1, queryStats.getCacheMissCount());
assertEquals("Expected 1 put in cache" + generateQueryCacheStats(queryStats), 1, queryStats.getCachePutCount());
assertEquals("Expected no hits in cache" + generateQueryCacheStats(queryStats), 0, queryStats.getCacheHitCount());
} catch (AssertionError e) {
return e.getMessage();
} catch (InterruptedException e) {
return e.getMessage();
} finally {
em.close();
}
return "OK";
}
/**
* Generate query cache statistics for put, hit and miss count as one String
*/
public String generateQueryCacheStats(QueryStatistics stats) {
String result = "(hitCount=" + stats.getCacheHitCount()
+ ", missCount=" + stats.getCacheMissCount()
+ ", putCount=" + stats.getCachePutCount() + ").";
return result;
}
/**
* Generate entity cache statistics for put, hit and miss count as one String
*/
public String generateEntityCacheStats(SecondLevelCacheStatistics stats) {
String result = "(hitCount=" + stats.getHitCount()
+ ", missCount=" + stats.getMissCount()
+ ", putCount=" + stats.getPutCount() + ").";
return result;
}
public String getCacheRegionName() {
return (String) emf.getProperties().get("hibernate.cache.region_prefix");
}
/**
* Create employee in provided EntityManager
*/
public void createEmployee(EntityManager em, String name, String address,
int id) {
Employee emp = new Employee();
emp.setId(id);
emp.setAddress(address);
emp.setName(name);
try {
em.persist(emp);
em.flush();
} catch (Exception e) {
throw new RuntimeException("transactional failure while persisting employee entity", e);
}
}
/**
* Create employee in provided EntityManager
*/
public void createEmployee(String name, String address,
int id) {
EntityManager em = emf.createEntityManager();
Employee emp = new Employee();
emp.setId(id);
emp.setAddress(address);
emp.setName(name);
try {
em.persist(emp);
} catch (Exception e) {
throw new RuntimeException("transactional failure while persisting employee entity", e);
} finally {
em.close();
}
}
/**
* Load employee from provided EntityManager
*/
public Employee getEmployee(EntityManager em, int id) {
Employee emp = em.find(Employee.class, id);
return emp;
}
/**
* Load employee using Query from provided EntityManager
*/
public Employee getEmployeeQuery(EntityManager em, int id) {
Query query;
query = em.createQuery("from Employee e where e.id=:id");
query.setParameter("id", id);
query.setHint("org.hibernate.cacheable", true);
return (Employee) query.getSingleResult();
}
/**
* Load all employees using Query from provided EntityManager
*/
@SuppressWarnings("unchecked")
public List<Employee> getAllEmployeesQuery(EntityManager em) {
Query query;
query = em.createQuery("from Employee");
query.setHint("org.hibernate.cacheable", true);
return query.getResultList();
}
}