Hi all,
Hibernate and JBoss EAP 6.1 are surprisingly driving me crazy.
Here is my use case:
Hibernate is the Persistence Provider for my JPA Entity Manager.
Everything works fine into my business method both called from local and remote interfaces via ejb client, thanks to a XATransaction running for each request/asynchronous ejb method/message driven bean call.
But when my code tries to get all the entities from a database table and adapt them from entity beans to a dto randomly the hibernate session is null and hibernate throws a LazyInitializationException.
The most strange behaviour is that once the JavassistLazyInitializer is correctly initialized and the session is correctly set into the AbstractLazyInitializer the code runs fine until I undeploy the enterprise application (restart the server, enable / disable the application).
If the code throws LazyInitializationException at the first invocation time, then the Exception will be thrown during all the application uptime.
I will report below the code representing one of the five singletons running the Entity EJB to DTO transformation, but I can assure to all of you that the described behaviour appears randomly to one or more singleton executions each time I try to redeploy the enterprise application!
One last important (maybe) thing: dao objects and cache service objects are located into two different jar sub-deployments of a single ear deployment unit.
Here is the code affected by the random LazyInitializationException, thank all of you in advance:
- persistence.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="ClabSystemPU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/ClabSystemDS</jta-data-source>
... MORE EJBs...
<class>com.contactlab.persistence.model.system.SrvSysLocalizedMessage</class>
... MORE EJBs...
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.bytecode.use_reflection_optimizer" value="true" />
<property name="hibernate.current_session_context_class" value="jta" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="hibernate.transaction.auto_close_session" value="true" />
<property name="hibernate.connection.aggressive_release" value="false" />
<property name="hibernate.connection.release_mode" value="after_transaction" />
<property name="hibernate.connection.autocommit" value="true" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.default_batch_fetch_size" value="5000" />
<property name="hibernate.default_entity_mode" value="pojo" />
<property name="hibernate.generate_statistics" value="true" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="true" />
<property name="hibernate.archive.autodetection" value="class" />
<!-- CACHE -->
<property name="hibernate.cache.use_query_cache" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
</properties>
</persistence-unit>
</persistence>
- Entity EJB
Code:
package com.contactlab.persistence.model.system;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class SrvSysLocalizedMessageId implements java.io.Serializable {
static final long serialVersionUID = -4625327722733138433L;
private int messageId;
private int localeId;
public SrvSysLocalizedMessageId() {
}
public SrvSysLocalizedMessageId(int messageId, int localeId) {
this.messageId = messageId;
this.localeId = localeId;
}
@Column(name = "`message_id`", nullable = false)
public int getMessageId() {
return this.messageId;
}
public void setMessageId(int messageId) {
this.messageId = messageId;
}
@Column(name = "`locale_id`", nullable = false)
public int getLocaleId() {
return this.localeId;
}
public void setLocaleId(int localeId) {
this.localeId = localeId;
}
}
Code:
package com.contactlab.persistence.model.system;
import java.util.Date;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.search.annotations.Indexed;
@Entity
@Indexed
@Table(name = "srv_sys_localized_message", catalog = "system")
public class SrvSysLocalizedMessage implements java.io.Serializable {
static final long serialVersionUID = 40527294840589823L;
private SrvSysLocalizedMessageId id;
private SrvSysMessage srvSysMessage;
private DecSysLocale decSysLocale;
private String message;
private Date dateAdd;
private Date lastModified;
public SrvSysLocalizedMessage() {
}
public SrvSysLocalizedMessage(SrvSysLocalizedMessageId id,
SrvSysMessage srvSysMessage, DecSysLocale decSysLocale,
String message, Date dateAdd, Date lastModified) {
this.id = id;
this.srvSysMessage = srvSysMessage;
this.decSysLocale = decSysLocale;
this.message = message;
this.dateAdd = dateAdd;
this.lastModified = lastModified;
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "messageId", column = @Column(name = "`message_id`", nullable = false)),
@AttributeOverride(name = "localeId", column = @Column(name = "`locale_id`", nullable = false)) })
public SrvSysLocalizedMessageId getId() {
return this.id;
}
public void setId(SrvSysLocalizedMessageId id) {
this.id = id;
}
@Transient
public String getDocumentId() {
return srvSysMessage.getDocumentId() + decSysLocale.getCode();
}
@ManyToOne(fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SELECT)
@JoinColumn(name = "`message_id`", nullable = false, insertable = false, updatable = false)
public SrvSysMessage getSrvSysMessage() {
return this.srvSysMessage;
}
public void setSrvSysMessage(SrvSysMessage srvSysMessage) {
this.srvSysMessage = srvSysMessage;
}
@ManyToOne(fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SELECT)
@JoinColumn(name = "`locale_id`", nullable = false, insertable = false, updatable = false)
public DecSysLocale getDecSysLocale() {
return this.decSysLocale;
}
public void setDecSysLocale(DecSysLocale decSysLocale) {
this.decSysLocale = decSysLocale;
}
@Column(name = "`message`", nullable = false)
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "`date_add`", nullable = false, length = 19)
public Date getDateAdd() {
return this.dateAdd;
}
public void setDateAdd(Date dateAdd) {
this.dateAdd = dateAdd;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "`last_modified`", nullable = false, length = 19)
public Date getLastModified() {
return this.lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
}
- DAO interfaces
Code:
package com.contactlab.persistence.commons.genericdao;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
public interface GenericRepository<T, ID extends Serializable> {
int countAll();
int countByExample(final T exampleInstance);
void delete(final T entity);
List<T> findAll();
List<T> findByCriteria(final Criterion... criterion);
List<T> findByCriteria(final int firstResult, final int maxResults,
final Criterion... criterion);
List<T> findByCriteria(final int firstResult, final int maxResults,
final Order order, final Criterion... criterion);
List<Object> findByCriteria(final int firstResult, final int maxResults,
final Order order, final ProjectionList list,
final Criterion... criterion);
List<Object> findByCriteria(final int firstResult, final int maxResults,
final ProjectionList list, final Criterion... criterion);
List<T> findByCriteria(final Order order, final Criterion... criterion);
List<Object> findByCriteria(final Order order, final ProjectionList list,
final Criterion... criterion);
List<Object> findByCriteria(final ProjectionList list,
final Criterion... criterion);
List<T> findByExample(final T exampleInstance);
T findById(final ID id);
T findById(final ID id, boolean lock);
List<T> findByNamedQuery(final String queryName, Object... params);
List<T> findByNamedQueryAndNamedParams(final String queryName,
final Map<String, ? extends Object> params);
Class<T> getEntityClass();
T merge(final T entity);
ID save(final T entity);
void update(final T entity);
}
Code:
package com.contactlab.persistence.dao.system;
import com.contactlab.persistence.commons.genericdao.GenericRepository;
import com.contactlab.persistence.model.system.SrvSysLocalizedMessage;
import com.contactlab.persistence.model.system.SrvSysLocalizedMessageId;
public interface SrvSysLocalizedMessageDAO extends GenericRepository<SrvSysLocalizedMessage, SrvSysLocalizedMessageId> {}
Code:
package com.contactlab.persistence.dao.system;
public interface SrvSysLocalizedMessageDAOLocal extends SrvSysLocalizedMessageDAO {}
- DAO abstract common class
Code:
package com.contactlab.persistence.commons.genericdao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import javax.persistence.spi.PersistenceProvider;
public abstract class AbstractGenericRepositoryImpl<T, ID extends Serializable, PP>
implements GenericRepository<T, ID> {
protected final Class<T> persistentClass;
protected PP persistenceProvider;
@SuppressWarnings("unchecked")
public AbstractGenericRepositoryImpl() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public AbstractGenericRepositoryImpl(final Class<T> persistentClass) {
super();
this.persistentClass = persistentClass;
}
public PP getPersistenceProvider() {
return persistenceProvider;
}
}
Code:
package com.contactlab.persistence.dao.system.util;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.hibernate.Criteria;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.contactlab.persistence.commons.genericdao.AbstractGenericRepositoryImpl;
public abstract class GenericHibernateRepository<T, ID extends Serializable>
extends AbstractGenericRepositoryImpl<T, ID, Session> {
private static final Logger LOG = LoggerFactory
.getLogger(GenericHibernateRepository.class);
@Override
public int countAll() {
LOG.trace("countAll() - start");
int returnint = countByCriteria();
LOG.trace("countAll() - end - return value={}", returnint);
return returnint;
}
public int countByCriteria(Criterion... criterion) {
LOG.trace("countByCriteria(Object criterion={}) - start", criterion);
Session session = null;
session = getPersistenceProvider();
Criteria crit = session.createCriteria(getEntityClass());
crit.setProjection(Projections.rowCount());
for (final Object c : criterion) {
crit.add((Criterion) c);
}
final List<T> result = crit.list();
int returnint = ((Number) result.get(0)).intValue();
LOG.trace(
"countByCriteria(Object criterion={}) - end - return value={}",
criterion, returnint);
return returnint;
}
@Override
public int countByExample(final T exampleInstance) {
LOG.trace("countByExample(T exampleInstance={}) - start",
exampleInstance);
Session session = null;
Criteria crit = null;
session = getPersistenceProvider();
crit = session.createCriteria(getEntityClass());
crit.setProjection(Projections.rowCount());
crit.add(Example.create(exampleInstance));
final List<T> result = crit.list();
int returnint = (Integer) result.get(0);
LOG.trace(
"countByExample(T exampleInstance={}) - end - return value={}",
exampleInstance, returnint);
return returnint;
}
@Override
public void delete(T entity) {
LOG.trace("delete(T entity={}) - start", entity);
Session session = getPersistenceProvider();
session.delete(entity);
LOG.trace("delete(T entity={}) - end", entity);
}
@Override
public List<T> findAll() {
LOG.trace("findAll() - start");
List<T> returnList = findByCriteria();
LOG.trace("findAll() - end - return value={}", returnList);
return returnList;
}
public List<T> findByCriteria(final Criterion... criterion) {
LOG.trace("findByCriteria(Object criterion={}) - start", criterion);
List<T> returnList = (List<T>) findByCriteria(null, null, criterion);
LOG.trace(
"findByCriteria(Object criterion={}) - end - return value={}",
criterion, returnList);
return returnList;
}
@Override
public List<T> findByCriteria(final int firstResult, final int maxResults,
final Criterion... criterion) {
return (List<T>) findByCriteria(firstResult, maxResults, null, null,
criterion);
}
@Override
public List<T> findByCriteria(final int firstResult, final int maxResults,
final Order order, final Criterion... criterion) {
return (List<T>) findByCriteria(firstResult, maxResults, order, null,
criterion);
}
@Override
public List<Object> findByCriteria(int firstResult, int maxResults,
Order order, ProjectionList list, Criterion... criterion) {
Session session = null;
session = getPersistenceProvider();
Criteria crit = session.createCriteria(getEntityClass());
if (criterion != null)
for (final Object c : criterion) {
crit.add((Criterion) c);
}
if (list != null)
crit.setProjection(list);
if (order != null)
crit.addOrder((Order) order);
if (firstResult > 0) {
crit.setFirstResult(firstResult);
}
if (maxResults > 0) {
crit.setMaxResults(maxResults);
}
final List<Object> result = crit.list();
return result;
}
@Override
public List<Object> findByCriteria(int firstResult, int maxResults,
ProjectionList list, Criterion... criterion) {
return findByCriteria(firstResult, maxResults, null, list, criterion);
}
@Override
public List<T> findByCriteria(final Order order,
final Criterion... criterion) {
List<T> returnList = (List<T>) findByCriteria(order, null, criterion);
return returnList;
}
@Override
public List<Object> findByCriteria(Order order, ProjectionList list,
Criterion... criterion) {
return findByCriteria(-1, -1, order, list, criterion);
}
@Override
public List<Object> findByCriteria(ProjectionList list,
Criterion... criterion) {
return findByCriteria(-1, -1, list, criterion);
}
@SuppressWarnings("unchecked")
@Override
public List<T> findByExample(final T exampleInstance) {
LOG.trace("findByExample(T exampleInstance={}) - start",
exampleInstance);
Session session = null;
Criteria crit = null;
session = getPersistenceProvider();
crit = session.createCriteria(getEntityClass());
crit.add(Example.create(exampleInstance));
final List<T> result = crit.list();
LOG.trace(
"findByExample(T exampleInstance={}) - end - return value={}",
exampleInstance, result);
return result;
}
@Override
public T findById(ID id) {
LOG.trace("findById(ID id={}) - start", id);
T returnT = findById(id, false);
LOG.trace("findById(ID id={}) - end - return value={}", id, returnT);
return returnT;
}
@SuppressWarnings("unchecked")
@Override
public T findById(final ID id, boolean lock) {
LOG.trace("findById(ID id={}, boolean lock={}) - start", id, lock);
Session session = null;
session = getPersistenceProvider();
T entity;
if (lock)
entity = (T) session.get(getEntityClass(), id, LockOptions.UPGRADE);
else
entity = (T) session.get(getEntityClass(), id);
LOG.trace(
"findById(ID id={}, boolean lock={}) - end - return value={}",
id, lock, entity);
return entity;
}
@SuppressWarnings("unchecked")
@Override
public List<T> findByNamedQuery(final String name, Object... params) {
LOG.trace("findByNamedQuery(String name={}, Object params={}) - start",
name, params);
Session session = null;
session = getPersistenceProvider();
Query query = session.createQuery(name);
for (int i = 0; i < params.length; i++) {
query.setParameter(i + 1, params[i]);
}
final List<T> result = (List<T>) query.list();
LOG.trace(
"findByNamedQuery(String name={}, Object params={}) - end - return value={}",
name, params, result);
return result;
}
@SuppressWarnings("unchecked")
@Override
public List<T> findByNamedQueryAndNamedParams(final String name,
final Map<String, ? extends Object> params) {
LOG.trace(
"findByNamedQueryAndNamedParams(String name={}, Map<String,? extends Object> params={}) - start",
name, params);
Session session = null;
session = getPersistenceProvider();
Query query = session.createQuery(name);
for (final Map.Entry<String, ? extends Object> param : params
.entrySet()) {
query.setParameter(param.getKey(), param.getValue());
}
final List<T> result = (List<T>) query.list();
LOG.trace(
"findByNamedQueryAndNamedParams(String name={}, Map<String,? extends Object> params={}) - end - return value={}",
name, params, result);
return result;
}
@Override
public Class<T> getEntityClass() {
return persistentClass;
}
public T merge(T entity) {
LOG.trace("merge(T entity={}) - start", entity);
Session session = getPersistenceProvider();
@SuppressWarnings("unchecked")
final T savedEntity = (T) session.merge(entity);
LOG.trace("merge(T entity={}) - end - return value={}", entity,
savedEntity);
session.flush();
return savedEntity;
}
@Override
public ID save(T entity) {
LOG.trace("save(T entity={}) - start", entity);
Session session = getPersistenceProvider();
@SuppressWarnings("unchecked")
final ID savedEntity = (ID) session.save(entity);
session.evict(entity);
LOG.trace("save(T entity={}) - end - return value={}", entity,
savedEntity);
session.flush();
return savedEntity;
}
@Override
public void update(T entity) {
LOG.trace("update(T entity={}) - start", entity);
Session session = getPersistenceProvider();
session.update(entity);
session.flush();
LOG.trace("update(T entity={}) - end", entity);
}
}
- DAO concrete class
Code:
package com.contactlab.persistence.dao.system.impl;
import com.contactlab.persistence.dao.system.SrvSysMessageDAO;
import com.contactlab.persistence.dao.system.SrvSysMessageDAOLocal;
import com.contactlab.persistence.dao.system.util.AbstractClabSystemDAOBean;
import com.contactlab.persistence.model.system.SrvSysMessage;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
@Stateless
@Local(SrvSysMessageDAOLocal.class)
@Remote(SrvSysMessageDAO.class)
public class SrvSysMessageDAOBean extends
AbstractClabSystemDAOBean<SrvSysMessage, Integer> implements
SrvSysMessageDAO, SrvSysMessageDAOLocal {}
- CACHE SERVICE interfaces
Code:
package com.contactlab.persistence.cache;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import org.infinispan.Cache;
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public interface CacheService<K, V> {
boolean isIndexed();
boolean isPeriodic();
boolean isOnDemand();
V get(K key);
Collection<V> getAll();
boolean contains(K key);
List<V> searchByAttribute(Map<String, Object> searchConstraints);
// @Asynchronous
void loadData();
}
Code:
package com.contactlab.persistence.cache;
public interface CacheServiceLocal<K, V> extends CacheService<K, V> {}
Code:
package com.contactlab.persistence.cache;
import com.contactlab.commons.utils.enterprise.components.dto.LocalizedApplicationMessage;
public interface LocalizedMessagesCacheService extends
CacheService<String, LocalizedApplicationMessage> {
void addLocalizedApplicationMessage(String applicationCode,
String messageCode, String locale, String messageType,
String message);
LocalizedApplicationMessage removeLocalizedApplicationMessage(
String applicationCode, String messageCode, String locale);
LocalizedApplicationMessage modifyLocalizedApplicationMessage(
String applicationCode, String messageCode, String locale,
String message);
void updateMessageType(String applicationCode, String messageCode,
String messageType);
}
Code:
package com.contactlab.persistence.cache;
import com.contactlab.commons.utils.enterprise.components.dto.LocalizedApplicationMessage;
public interface LocalizedMessagesCacheServiceLocal extends
CacheServiceLocal<String, LocalizedApplicationMessage>,
LocalizedMessagesCacheService {}
- CACHE SERVICE abstract common class
Code:
package com.contactlab.persistence.cache.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.ScheduleExpression;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.transaction.UserTransaction;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.util.Version;
import org.hibernate.search.query.dsl.BooleanJunction;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.util.impl.PassThroughAnalyzer;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.query.CacheQuery;
import org.infinispan.query.Search;
import org.infinispan.query.SearchManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.contactlab.persistence.cache.CacheService;
import com.contactlab.persistence.cache.CacheServiceLocal;
import com.contactlab.persistence.cache.enums.PLCacheTimerType;
@TransactionManagement(TransactionManagementType.BEAN)
abstract class AbstractCacheServiceBean<K, V> implements CacheService<K, V>,
CacheServiceLocal<K, V> {
private static final Logger LOG = LoggerFactory
.getLogger(AbstractCacheServiceBean.class);
@Resource
protected TimerService timerService;
protected Timer timer;
protected ScheduleExpression scheduleExpression;
protected TimerConfig timerConfig;
protected final AtomicBoolean stopped;
private final AtomicBoolean loading;
private final AtomicLong loadingStart;
private final AtomicLong stopElapsedTime;
@Resource
private UserTransaction utx;
protected EmbeddedCacheManager cacheManager;
protected Cache<K, V> cache;
protected QueryParser luceneQueryParser;
protected SearchManager searchManager;
protected QueryBuilder queryBuilder;
public AbstractCacheServiceBean() {
stopped = new AtomicBoolean(false);
loading = new AtomicBoolean(false);
loadingStart = new AtomicLong();
stopElapsedTime = new AtomicLong();
}
@Override
public boolean isIndexed() {
return true;
}
@Override
public boolean isPeriodic() {
return true;
}
@Override
public boolean isOnDemand() {
return false;
}
protected void doInit() {
initCacheIndexer();
initCacheLoaderTimer();
}
protected void initCacheIndexer() {
if (isIndexed()) {
luceneQueryParser = new QueryParser(Version.LUCENE_36,
getDefaultField(), new PassThroughAnalyzer(
Version.LUCENE_36));
/*
* HIBERNATE
*/
searchManager = Search.getSearchManager(cache);
// you could make the queries via Lucene APIs, or use some helpers:
queryBuilder = searchManager.buildQueryBuilderForClass(
getEntityClass()).get();
}
}
protected void initCacheLoaderTimer() {
if (isPeriodic()) {
// TIMER
// try {
// if (cache.getCacheConfiguration().clustering().cacheMode() ==
// CacheMode.LOCAL
// || cacheManager.isCoordinator())
// loadData();
// } catch (Exception e) {
// LOG.error("", e);
// }
scheduleExpression = new ScheduleExpression().hour("*").minute("*")
.second("*/30");
timerConfig = new TimerConfig(getPLCacheTimerType(), false);
timer = timerService.createCalendarTimer(scheduleExpression,
timerConfig);
LOG.info("Set timer configuration: {} - next fire at {}",
timer.getInfo(), timer.getNextTimeout());
timerConfig = null;
}
}
protected void handleTimeout(Timer timer) {
if (hasToFireTimeout(timer.getInfo())) {
LOG.info("Timeout fired for timer {}", timer.getInfo());
loadData();
}
}
protected abstract PLCacheTimerType getPLCacheTimerType();
@PreDestroy
protected void destroy() {
if (isPeriodic()) {
timer.cancel();
}
}
protected abstract void setCache(Cache<K, V> cache);
protected abstract void setCacheManager(EmbeddedCacheManager cacheManager);
protected String getDefaultField() {
return "";
}
@Override
public V get(K key) {
V returnV = null;
if (!cache.containsKey(key) && isOnDemand()) {
returnV = getFromSource(key);
if (returnV != null) {
LOG.trace("Cache MISS for key {} ({}); key added", key, returnV
.getClass().getSimpleName());
} else {
LOG.trace("Cache MISS for key {}; key not found in source", key);
}
} else {
returnV = cache.get(key);
LOG.trace("Cache HIT for key {} ({}) ", key, returnV.getClass()
.getSimpleName());
}
return returnV;
}
protected V getFromSource(K key) {
return null;
}
@Override
public Collection<V> getAll() {
List<V> l = new LinkedList<>();
for (Entry<K, V> entry : cache.entrySet())
l.add(entry.getValue());
return l;
}
@Override
public boolean contains(K key) {
return get(key) != null;
}
protected abstract Class<V> getEntityClass();
protected List<Object> doSearch(Map<String, Object> searchConstraints) {
if (!isPeriodic()) {
throw new UnsupportedOperationException(
"Cannot search on not periodically renewed cache");
}
if (searchConstraints == null || searchConstraints.isEmpty())
return new ArrayList<Object>(cache.values());
// you could make the queries via Lucene APIs, or use some helpers:
QueryBuilder queryBuilder = searchManager.buildQueryBuilderForClass(
getEntityClass()).get();
// the queryBuilder has a nice fluent API which guides you through all
// options.
// this has some knowledge about your object, for example which
// Analyzers
// need to be applied, but the output is a failry standard Lucene Query.
org.apache.lucene.search.Query luceneQuery = null;
BooleanJunction<BooleanJunction> boolj = queryBuilder.bool();
for (Entry<String, Object> searchConstraint : searchConstraints
.entrySet()) {
boolj.must(queryBuilder.keyword()
.onField(searchConstraint.getKey())
.matching(searchConstraint.getValue()).createQuery());
}
luceneQuery = boolj.createQuery();
// the query API itself accepts any Lucene Query, and on top of that
// you can restrict the result to selected class types:
CacheQuery query = searchManager
.getQuery(luceneQuery, getEntityClass());
// and there are your results!
List<Object> returnList = query.list();
return returnList;
}
protected void checkDataConsistency(K key) {
if (!cache.containsKey(key))
throw new IllegalArgumentException("Provided key " + key.toString()
+ " does not exist in cache");
}
@Override
public void loadData() {
StringBuilder sb = null;
if (!stopped.get() && loading.compareAndSet(false, true)) {
sb = new StringBuilder();
int removed = 0;
int added = 0;
int present = 0;
Set<K> keysToRemove = null;
Map<K, V> data = null;
loading.set(true);
loadingStart.set(System.currentTimeMillis());
LOG.info("Beginning transaction for method loadData.");
try {
present = cache.size();
// utx.begin();
sb.append(getPLCacheTimerType())
.append(" cache data load action results:")
.append("\n\tEntities in cache BEFORE LOAD ACTION: ")
.append(present);
/*
* REMOVES FROM CACHE THE KEYS THAT DO NOT EXIST ANYMORE
*/
data = collectData();
sb.append("\n\tPotential entities into cache ")
.append(" FOUND: ").append(data.size());
keysToRemove = new HashSet<>();
for (K key : cache.keySet())
if (!data.containsKey(key)) {
keysToRemove.add(key);
removed++;
LOG.debug("Removed ENTITY identified by key\"{}\".",
key);
}
sb.append("\n\tEntities to remove ").append(removed);
removed = 0;
for (K key : keysToRemove) {
cache.remove(key);
removed++;
}
present -= removed;
sb.append("\n\tREMOVED ").append(removed)
.append(" entities from cache");
keysToRemove = null;
/*
* INSERT OR UPDATE INTO CACHE
*/
cache.putAll(data);
added = cache.size() - present;
sb.append("\n\tADDED ").append(added)
.append(" entities to cache");
sb.append("\n\tUPDATED ").append(present)
.append(" entities into cache");
data = null;
// utx.commit();
LOG.info(
"Committied transaction for method load cache data in {} millis.\n{}",
(System.currentTimeMillis() - loadingStart.get()),
sb.toString());
sb = null;
} catch (Exception e) {
LOG.error(
"An exception occurred during transaction phase for method load cache data",
e);
loadData();
} finally {
loading.set(false);
}
}
}
protected boolean hasToFireTimeout(Serializable info) {
return isPeriodic()
&& (info != null)
&& (info instanceof PLCacheTimerType)
&& ((PLCacheTimerType) info) == getPLCacheTimerType()
&& (cache.getCacheConfiguration().clustering().cacheMode() == CacheMode.LOCAL || cacheManager
.isCoordinator());
}
protected abstract Map<K, V> collectData();
public boolean stopDaemon() {
LOG.info("Stopping cache data loader daemon...");
stopElapsedTime.set(System.currentTimeMillis());
stopped.set(true);
return stopped.get();
}
}
- CACHE SERVICE concrete singleton class
Code:
@Local(LocalizedMessagesCacheServiceLocal.class)
@Remote(LocalizedMessagesCacheService.class)
@Singleton
@Startup
public class LocalizedMessagesCacheServiceBean extends
AbstractCacheServiceBean<String, LocalizedApplicationMessage> implements
LocalizedMessagesCacheService, LocalizedMessagesCacheServiceLocal {
@Inject
private Logger LOG;
@Inject
private SrvSysLocalizedMessageDAOLocal srvSysLocalizedMessageDAO;
@Inject
private MessagesCacheServiceLocal messagesCacheService;
@Inject
private AvailableLocalesCacheServiceLocal availableLocalesCacheService;
@Inject
@LocalizedApplicationMessageAdapterBinding
private LocalizedApplicationMessageAdapter adapter;
@Override
protected Class<LocalizedApplicationMessage> getEntityClass() {
return LocalizedApplicationMessage.class;
}
@PostConstruct
private void init() {
doInit();
}
@Timeout @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void timeout(Timer timer) {
handleTimeout(timer);
}
@Override
public List<LocalizedApplicationMessage> searchByAttribute(
Map<String, Object> searchConstraints) {
List<LocalizedApplicationMessage> results = new ArrayList<LocalizedApplicationMessage>();
try {
for (Object result : doSearch(searchConstraints))
results.add((LocalizedApplicationMessage) result);
} catch (Exception e) {
throw new PersistenceLayerException(e);
}
return results;
}
@Override
@Resource(name = "java:jboss/infinispan/clab")
protected void setCacheManager(EmbeddedCacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
@Resource(name = "java:jboss/infinispan/clab/system/localizedApplicationMessagesRepository")
protected void setCache(Cache<String, LocalizedApplicationMessage> cache) {
this.cache = cache;
}
@Override
public void addLocalizedApplicationMessage(String applicationCode,
String messageCode, String locale, String messageType,
String message) {
LocalizedApplicationMessage localizedMessage = new LocalizedApplicationMessage();
localizedMessage.setApplicationCode(applicationCode);
localizedMessage.setMessageCode(messageCode);
localizedMessage.setMessageType(messageType);
localizedMessage.setMessage(message);
localizedMessage.setEnabled(true);
cache.put(localizedMessage.getPk(), localizedMessage);
Date now = new Date();
int messageId = messagesCacheService.get(applicationCode + messageCode)
.getId();
int localeId = availableLocalesCacheService.get(locale).getId();
SrvSysLocalizedMessageId id = new SrvSysLocalizedMessageId(messageId,
localeId);
SrvSysLocalizedMessage srvSysLocalizedMessage = new SrvSysLocalizedMessage();
srvSysLocalizedMessage.setId(id);
srvSysLocalizedMessage.setMessage(message);
srvSysLocalizedMessage.setDateAdd(now);
srvSysLocalizedMessage.setLastModified(now);
srvSysLocalizedMessageDAO.save(srvSysLocalizedMessage);
}
@Override
public LocalizedApplicationMessage removeLocalizedApplicationMessage(
String applicationCode, String messageCode, String locale) {
int messageId = messagesCacheService.get(applicationCode + messageCode)
.getId();
int localeId = availableLocalesCacheService.get(locale).getId();
LocalizedApplicationMessage removed = cache.remove(applicationCode
+ messageCode + locale);
SrvSysLocalizedMessage srvSysLocalizedMessage = new SrvSysLocalizedMessage();
SrvSysLocalizedMessageId id = new SrvSysLocalizedMessageId(messageId,
localeId);
srvSysLocalizedMessage.setId(id);
srvSysLocalizedMessageDAO.delete(srvSysLocalizedMessage);
return removed;
}
@Override
public LocalizedApplicationMessage modifyLocalizedApplicationMessage(
String applicationCode, String messageCode, String locale,
String message) {
int messageId = messagesCacheService.get(applicationCode + messageCode)
.getId();
int localeId = availableLocalesCacheService.get(locale).getId();
String key = applicationCode + messageCode + locale;
LocalizedApplicationMessage localizedApplicationMessage = cache
.get(key);
localizedApplicationMessage.setMessage(message);
cache.put(key, localizedApplicationMessage);
SrvSysLocalizedMessageId id = new SrvSysLocalizedMessageId(messageId,
localeId);
SrvSysLocalizedMessage srvSysLocalizedMessage = srvSysLocalizedMessageDAO
.findById(id);
srvSysLocalizedMessage.setMessage(message);
srvSysLocalizedMessage.setLastModified(new Date());
srvSysLocalizedMessageDAO.merge(srvSysLocalizedMessage);
return localizedApplicationMessage;
}
@Override
public void updateMessageType(String applicationCode, String messageCode,
String messageType) {
Map<String, Object> searchConstraints = new HashMap<String, Object>();
if (applicationCode != null)
searchConstraints.put("applicationCode", applicationCode);
if (messageCode != null)
searchConstraints.put("messageCode", messageCode);
Collection<LocalizedApplicationMessage> messages = searchByAttribute(searchConstraints);
for (LocalizedApplicationMessage message : messages) {
message.setMessageType(messageType);
cache.put(message.getApplicationMessageId(), message);
}
}
@Override
protected PLCacheTimerType getPLCacheTimerType() {
return PLCacheTimerType.LOCALIZED_MESSAGES;
}
@Override
protected Map<String, LocalizedApplicationMessage> collectData() {
List<SrvSysLocalizedMessage> list = null;
Map<String, LocalizedApplicationMessage> data = null;
list = srvSysLocalizedMessageDAO.findAll();
data = new HashMap<>(list.size());
LocalizedApplicationMessage dto = null;
for (SrvSysLocalizedMessage item : list) {
dto = adapter.from(item);
data.put(dto.getPk(), dto);
dto = null;
}
return data;
}
}
- Adapter and DTO object
Code:
package com.contactlab.persistence.cache.adapters.impl;
import com.contactlab.commons.utils.enterprise.components.dto.LocalizedApplicationMessage;
import com.contactlab.persistence.cache.adapters.LocalizedApplicationMessageAdapter;
import com.contactlab.persistence.cache.adapters.LocalizedApplicationMessageAdapterBinding;
import com.contactlab.persistence.model.system.SrvSysLocalizedMessage;
@LocalizedApplicationMessageAdapterBinding
public class LocalizedApplicationMessageAdapterImpl implements
LocalizedApplicationMessageAdapter {
/**
* @see com.contactlab.commons.utils.interfaces.adapter.Adapter#from(java.lang.Object)
*/
@Override
public LocalizedApplicationMessage from(SrvSysLocalizedMessage source) {
LocalizedApplicationMessage dto = new LocalizedApplicationMessage();
dto.setApplicationCode(source.getSrvSysMessage().getDecSysApplication()
.getCode());
dto.setMessageCode(source.getSrvSysMessage().getZerofilledCode());
dto.setMessageType(source.getSrvSysMessage().getDecSysMessageType()
.getCode());
dto.setDefaultMessage(source.getSrvSysMessage().getDefaultMessage());
dto.setMessage(source.getMessage());
dto.setLocale(source.getDecSysLocale().getCode());
dto.setEnabled(source.getSrvSysMessage().isEnabled());
return dto;
}
@Override
public SrvSysLocalizedMessage to(LocalizedApplicationMessage source) {
return null;
}
}
Code:
package com.contactlab.commons.utils.enterprise.components.dto;
import java.io.Serializable;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
@Indexed
public class LocalizedApplicationMessage implements Serializable {
private static final long serialVersionUID = -1948602352016940294L;
@Field
private String applicationCode;
@Field
private String messageCode;
@Field
private String messageType;
@Field
private String locale;
private String defaultMessage;
private String message;
private boolean enabled;
@DocumentId
public String getPk() {
return applicationCode + messageCode + locale;
}
public String getApplicationMessageId() {
return applicationCode + messageCode + locale;
}
public String getApplicationCode() {
return applicationCode;
}
public void setApplicationCode(String applicationCode) {
this.applicationCode = applicationCode;
}
public String getMessageCode() {
return messageCode;
}
public void setMessageCode(String messageCode) {
this.messageCode = messageCode;
}
public String getMessageType() {
return messageType;
}
public void setMessageType(String messageType) {
this.messageType = messageType;
}
public String getDefaultMessage() {
return defaultMessage;
}
public void setDefaultMessage(String defaultMessage) {
this.defaultMessage = defaultMessage;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((applicationCode == null) ? 0 : applicationCode.hashCode());
result = prime * result + ((locale == null) ? 0 : locale.hashCode());
result = prime * result
+ ((messageCode == null) ? 0 : messageCode.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocalizedApplicationMessage other = (LocalizedApplicationMessage) obj;
if (applicationCode == null) {
if (other.applicationCode != null)
return false;
} else if (!applicationCode.equals(other.applicationCode))
return false;
if (locale == null) {
if (other.locale != null)
return false;
} else if (!locale.equals(other.locale))
return false;
if (messageCode == null) {
if (other.messageCode != null)
return false;
} else if (!messageCode.equals(other.messageCode))
return false;
return true;
}
}
I HAVE TO PROVIDE THE FULL STACK TRACE REPLYING TO THIS POST, TOO MANY CHARACTERS :-D