/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, 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.wildfly.clustering.ejb.infinispan.bean;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.wildfly.clustering.ee.infinispan.CacheProperties;
import org.wildfly.clustering.ee.infinispan.CacheEntryMutator;
import org.wildfly.clustering.ee.Mutator;
import org.wildfly.clustering.ejb.Bean;
import org.wildfly.clustering.ejb.PassivationListener;
import org.wildfly.clustering.ejb.RemoveListener;
import org.wildfly.clustering.ejb.Time;
import org.wildfly.clustering.ejb.infinispan.BeanEntry;
import org.wildfly.clustering.ejb.infinispan.BeanFactory;
import org.wildfly.clustering.ejb.infinispan.BeanGroup;
import org.wildfly.clustering.ejb.infinispan.BeanGroupEntry;
import org.wildfly.clustering.ejb.infinispan.BeanGroupFactory;
import org.wildfly.clustering.ejb.infinispan.BeanKey;
import org.wildfly.clustering.ejb.infinispan.logging.InfinispanEjbLogger;
/**
* Encapsulates the cache mapping strategy for a bean.
*
* @author Paul Ferraro
*
* @param <G> the group identifier type
* @param <I> the bean identifier type
* @param <T> the bean type
*/
public class InfinispanBeanFactory<I, T> implements BeanFactory<I, T> {
private final String beanName;
private final BeanGroupFactory<I, T> groupFactory;
private final Cache<BeanKey<I>, BeanEntry<I>> cache;
private final Cache<BeanKey<I>, BeanEntry<I>> findCache;
private final Time timeout;
private final PassivationListener<T> listener;
public InfinispanBeanFactory(String beanName, BeanGroupFactory<I, T> groupFactory, Cache<BeanKey<I>, BeanEntry<I>> cache, CacheProperties properties, Time timeout, PassivationListener<T> listener) {
this.beanName = beanName;
this.groupFactory = groupFactory;
this.cache = cache;
this.findCache = properties.isLockOnRead() ? this.cache.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK) : this.cache;
this.timeout = timeout;
this.listener = listener;
}
@Override
public BeanKey<I> createKey(I id) {
return new InfinispanBeanKey<>(id);
}
@Override
public Bean<I, T> createBean(I id, BeanEntry<I> entry) {
I groupId = entry.getGroupId();
BeanGroupEntry<I, T> groupEntry = this.groupFactory.findValue(groupId);
if (groupEntry == null) {
InfinispanEjbLogger.ROOT_LOGGER.invalidBeanGroup(id, groupId);
this.cache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).remove(this.createKey(id));
return null;
}
BeanGroup<I, T> group = this.groupFactory.createGroup(groupId, groupEntry);
Mutator mutator = (entry.getLastAccessedTime() == null) ? Mutator.PASSIVE : new CacheEntryMutator<>(this.cache, this.createKey(id), entry);
return new InfinispanBean<>(id, entry, group, mutator, this, this.timeout, this.listener);
}
@Override
public BeanEntry<I> findValue(I id) {
return this.findCache.get(this.createKey(id));
}
@Override
public BeanEntry<I> tryValue(I id) {
return this.findCache.getAdvancedCache().withFlags(Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, Flag.FAIL_SILENTLY).get(this.createKey(id));
}
@Override
public BeanEntry<I> createValue(I id, I groupId) {
return this.cache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).computeIfAbsent(this.createKey(id), key -> new InfinispanBeanEntry<>(this.beanName, groupId));
}
@Override
public void remove(I id, RemoveListener<T> listener) {
BeanEntry<I> entry = this.cache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).remove(this.createKey(id));
if (entry != null) {
I groupId = entry.getGroupId();
BeanGroupEntry<I, T> groupEntry = this.groupFactory.findValue(groupId);
if (groupEntry != null) {
try (BeanGroup<I, T> group = this.groupFactory.createGroup(groupId, groupEntry)) {
T bean = group.removeBean(id);
if (listener != null) {
listener.removed(bean);
}
}
}
}
}
}