
org.omnifaces.services.pooled.PooledContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of omniservices Show documentation
Show all versions of omniservices Show documentation
Utility library that provides EJB3-like features for CDI beans
The newest version!
/*
* Copyright 2021 OmniFaces
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.omnifaces.services.pooled;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.IntStream;
import jakarta.enterprise.context.spi.AlterableContext;
import jakarta.enterprise.context.spi.Contextual;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.Bean;
/**
* The {@link AlterableContext} implementation for {@link Pooled} beans.
*/
public class PooledContext implements AlterableContext {
private final ThreadLocal poolScope = ThreadLocal.withInitial(PooledScope::new);
private final Map, InstancePool>> instancePools = new ConcurrentHashMap<>();
private final Map, Object> dummyInstances = new ConcurrentHashMap<>();
@Override
public Class extends Annotation> getScope() {
return Pooled.class;
}
@SuppressWarnings("unchecked")
@Override
public T get(Contextual contextual, CreationalContext creationalContext) {
if (contextual instanceof Bean) {
PoolKey poolKey = poolScope.get().getPoolKey(contextual);
if (poolKey == null) {
return (T) dummyInstances.computeIfAbsent(contextual, ctx -> contextual.create(creationalContext));
}
return ((InstancePool) instancePools.get(poolKey.contextual())).getInstance(poolKey, creationalContext);
}
// TODO add clear error message and pick better exception
throw new IllegalArgumentException();
}
@SuppressWarnings("unchecked")
@Override
public T get(Contextual contextual) {
if (contextual instanceof Bean) {
PoolKey poolKey = poolScope.get().getPoolKey(contextual);
if (poolKey == null) {
return (T) dummyInstances.get(contextual);
}
return ((InstancePool) instancePools.get(poolKey.contextual())).getInstance(poolKey);
}
return null;
}
@Override
public boolean isActive() {
return true;
}
@SuppressWarnings("unchecked")
PoolKey allocateBean(Contextual contextual) {
PoolKey poolKey = ((InstancePool) instancePools.get(contextual)).allocateInstance();
poolScope.get().setPoolKey(poolKey);
return poolKey;
}
@SuppressWarnings("unchecked")
void releaseBean(PoolKey poolKey) {
poolScope.get().removePoolKey(poolKey);
((InstancePool) instancePools.get(poolKey.contextual())).releaseInstance(poolKey);
}
boolean hasAllocatedInstanceOf(Bean> bean) {
return poolScope.get().getPoolKey(bean) != null;
}
public void createInstancePool(Contextual contextual, Pooled poolSettings) {
instancePools.put(contextual, new InstancePool<>(contextual, poolSettings));
}
boolean mustDestroyBeanWhenCaught(Contextual contextual, Throwable throwable) {
return instancePools.get(contextual).mustDestroyBeanWhenCaught(throwable);
}
@Override
public void destroy(Contextual> contextual) {
PoolKey> poolKey = poolScope.get().getPoolKey(contextual);
if (poolKey != null) {
destroyInstance(poolKey);
}
}
private void destroyInstance(PoolKey poolKey) {
@SuppressWarnings("unchecked")
InstancePool instancePool = (InstancePool) instancePools.get(poolKey.contextual());
instancePool.destroyInstance(poolKey);
}
private static class InstancePool {
private final Contextual contextual;
private final Pooled poolSettings;
private final Map, Instance> instances = new ConcurrentHashMap<>();
private final BlockingDeque> freeInstanceKeys = new LinkedBlockingDeque<>();
InstancePool(Contextual contextual, Pooled poolSettings) {
this.contextual = contextual;
this.poolSettings = poolSettings;
IntStream.range(0, poolSettings.maxNumberOfInstances())
.mapToObj(i -> new PoolKey<>(contextual, i))
.forEach(freeInstanceKeys::add);
}
T getInstance(PoolKey poolKey) {
if (!poolKey.contextual().equals(contextual)) {
throw new IllegalArgumentException();
}
Instance instance = instances.get(poolKey);
if (instance != null) {
return instance.getInstance();
}
return null;
}
T getInstance(PoolKey poolKey, CreationalContext context) {
if (!poolKey.contextual().equals(contextual)) {
throw new IllegalArgumentException();
}
return instances.computeIfAbsent(poolKey, key -> new Instance<>(contextual, context)).getInstance();
}
PoolKey allocateInstance() {
try {
PoolKey poolKey = freeInstanceKeys.poll(poolSettings.instanceLockTimeout(), poolSettings.instanceLockTimeoutUnit());
if (poolKey == null) {
// Unable to allocate an instance within the configured timeout
throw new PoolLockTimeoutException();
}
return poolKey;
} catch (InterruptedException e) {
throw new UncheckedInterruptedException(e);
}
}
void releaseInstance(PoolKey key) {
if (!contextual.equals(key.contextual())) {
throw new IllegalArgumentException();
}
freeInstanceKeys.addFirst(key);
}
void destroyInstance(PoolKey key) {
Instance instance = instances.remove(key);
instance.destroy(contextual);
}
boolean mustDestroyBeanWhenCaught(Throwable throwable) {
for (Class throwableType: poolSettings.dontDestroyOn()) {
if (throwableType.isInstance(throwable)) {
return false;
}
}
if (poolSettings.dontDestroyOn().length > 0 && poolSettings.destroyOn().length == 0) {
return true;
}
for (Class throwableType: poolSettings.destroyOn()) {
if (throwableType.isInstance(throwable)) {
return true;
}
}
return false;
}
}
private static class Instance {
private final T instance;
private final CreationalContext creationalContext;
Instance(Contextual contextual, CreationalContext creationalContext) {
this.instance = contextual.create(creationalContext);
this.creationalContext = creationalContext;
}
T getInstance() {
return instance;
}
CreationalContext getCreationalContext() {
return creationalContext;
}
void destroy(Contextual contextual) {
contextual.destroy(instance, creationalContext);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy