com.terracotta.entity.ClusteredEntityManager Maven / Gradle / Ivy
/*
* All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
*/
package com.terracotta.entity;
import org.terracotta.toolkit.Toolkit;
import org.terracotta.toolkit.collections.ToolkitMap;
import org.terracotta.toolkit.concurrent.locks.ToolkitLock;
import org.terracotta.toolkit.concurrent.locks.ToolkitReadWriteLock;
import com.terracotta.entity.internal.InternalRootEntity;
import com.terracotta.entity.internal.LockingEntity;
import com.terracotta.entity.internal.ToolkitAwareEntity;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
/**
* ClusteredEntityManager
*/
public class ClusteredEntityManager {
private static final long TRY_LOCK_TIMEOUT_SECONDS = 2;
private final Toolkit toolkit;
private final EntityLockHandler entityLockHandler;
private volatile transient ConcurrentMap> entityMapsMap = new ConcurrentHashMap>();
public ClusteredEntityManager(Toolkit toolkit) {
this(toolkit, new EntityLockHandler(toolkit));
}
ClusteredEntityManager(Toolkit toolkit, EntityLockHandler entityLockHandler) {
this.toolkit = toolkit;
this.entityLockHandler = entityLockHandler;
}
public T getRootEntity(String name, Class entityClass) {
T entity = getRootEntityInternal(name, entityClass);
if (entity != null && ClusteredEntityState.DESTROY_IN_PROGRESS.equals(entity.getState())) {
destroyRootEntitySilently(name, entityClass, entity);
return null;
}
return entity;
}
public Map getRootEntities(Class entityClass) {
HashMap resultMap = new HashMap();
for (Map.Entry entry : getEntityMap(entityClass).entrySet()) {
T entity = entry.getValue();
if (!ClusteredEntityState.DESTROY_IN_PROGRESS.equals(entity.getState())) {
resultMap.put(entry.getKey(), processEntity(entity));
} else {
destroyRootEntitySilently(entry.getKey(), entityClass, entity);
}
}
return Collections.unmodifiableMap(resultMap);
}
/**
* Method for adding a {@link com.terracotta.entity.RootEntity} to this ClusteredEntityManager.
*
* If a {@link com.terracotta.entity.RootEntity} of the same clusteredEntityClass with the same name is already known
* to this ClusteredEntityManager, that entity will be returned and the clusteredEntity passed in will not added.
*
* @param name the name of the entity
* @param clusteredEntityClass the type of the entity
* @param clusteredEntity the clustered entity
*
* @return the current known mapping if any, {@code null} otherwise
*/
public T addRootEntityIfAbsent(String name, Class clusteredEntityClass, T clusteredEntity) {
ToolkitMap map = getEntityMap(clusteredEntityClass);
T oldValue = map.putIfAbsent(name, clusteredEntity);
if (oldValue != null) {
return processEntity(oldValue);
} else {
processEntity(clusteredEntity);
return null;
}
}
/**
* Method for destroying a root entity
*
* This method will follow these steps:
*
* - Put entity in exclusive maintenance mode
* If this fails, throws {@link java.lang.IllegalStateException}
* - Verify the entity passed in matches the current known entity
* If this fails, throws {@link java.lang.IllegalArgumentException}
* - Mark the entity with {@link com.terracotta.entity.ClusteredEntityState#DESTROY_IN_PROGRESS} and save it
* If this fails, throws {@link java.lang.UnsupportedOperationException}
* - Perform the destroy operation
*
*
* @param name name of the entity to destroy
* @param rootEntityClass public interface under which this entity is managed
* @param controlEntity the entity to destroy
* @param The managed entity type
* @return {@code true} if entity was effectively destroyed, {@code false} if entity does not exist
*/
public boolean destroyRootEntity(String name, Class rootEntityClass, T controlEntity) {
InternalRootEntity currentRootEntity = asInternalRootEntity(getRootEntityInternal(name, rootEntityClass));
if (currentRootEntity != null) {
ToolkitLock entityWriteLock = currentRootEntity.getEntityLock().writeLock();
try {
if (entityWriteLock.tryLock(TRY_LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
try {
if (!currentRootEntity.equals(controlEntity)) {
throw new IllegalArgumentException(String.format("The specified entity named %s does not match " +
"the mapping known to this entity manager", name));
}
currentRootEntity.markDestroying();
try {
getEntityMap(rootEntityClass).put(name, (T) currentRootEntity);
} catch (Exception e) {
// Failed to save entity in destroy state - abort
currentRootEntity.alive();
throw new UnsupportedOperationException(String.format("Unable to mark entity %s of type %s with destroy in progress", name, rootEntityClass), e);
}
currentRootEntity.destroy();
getEntityMap(rootEntityClass).remove(name);
return true;
} finally {
entityWriteLock.unlock();
}
} else {
throw new IllegalStateException(String.format("Unable to lock entity %s of type %s for destruction", name, rootEntityClass));
}
} catch (InterruptedException e) {
throw new IllegalStateException(String.format("Unable to lock entity %s of type %s for destruction", name, rootEntityClass), e);
}
}
return false;
}
private InternalRootEntity asInternalRootEntity(T currentRootEntity) {
return (InternalRootEntity) currentRootEntity;
}
public ToolkitReadWriteLock getEntityLock(String lockName) {
return toolkit.getReadWriteLock(lockName);
}
public void dispose() {
entityLockHandler.dispose();
}
private T getRootEntityInternal(String name, Class rootEntityClass) {
return processEntity(getEntityMap(rootEntityClass).get(name));
}
private void destroyRootEntitySilently(String name, Class entityClass, T entity) {
try {
destroyRootEntity(name, entityClass, entity);
} catch (Exception e) {
// Ignore - trying to destroy left overs
}
}
private T processEntity(T entity) {
if (entity instanceof ToolkitAwareEntity) {
((ToolkitAwareEntity)entity).setToolkit(toolkit);
}
if (entity instanceof LockingEntity) {
((LockingEntity)entity).setEntityLockHandler(entityLockHandler);
}
return entity;
}
private ToolkitMap getEntityMap(Class entityClass) {
ToolkitMap entityMap = (ToolkitMap) entityMapsMap.get(entityClass);
if (entityMap == null) {
entityMap = toolkit.getMap(getMapName(entityClass), String.class, entityClass);
ToolkitMap installedMap = (ToolkitMap) entityMapsMap.putIfAbsent(entityClass, entityMap);
if (installedMap != null) {
entityMap = installedMap;
}
}
return entityMap;
}
String getMapName(Class entityClass) {
return entityClass.getName();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy