package org.mobicents.slee.runtime.sbb;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPoolFactory;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.SbbComponent;
import org.mobicents.slee.runtime.transaction.SleeTransactionManager;
import org.mobicents.slee.runtime.transaction.TransactionalAction;
/**
*
* Manages sbb object pools in the SLEE container.
*
* @author martins
*
*/
public class SbbObjectPoolManagement implements SbbObjectPoolManagementMBean {
private final static Logger logger = Logger
.getLogger(SbbObjectPoolManagement.class);
private final ConcurrentHashMap<ObjectPoolMapKey, SbbObjectPool> pools;
private final SleeContainer sleeContainer;
private GenericObjectPool.Config config;
public SbbObjectPoolManagement(SleeContainer sleeContainer) {
this.sleeContainer = sleeContainer;
// create pool config mbean with default pool configuration
config = new GenericObjectPool.Config();
config.maxActive = -1;
config.maxIdle = 50;
config.maxWait = -1;
config.minEvictableIdleTimeMillis = 60000;
config.minIdle = 0;
config.numTestsPerEvictionRun = -1;
config.testOnBorrow = true;
config.testOnReturn = true;
config.testWhileIdle = false;
config.timeBetweenEvictionRunsMillis = 300000;
config.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_FAIL;
// create pools map
pools = new ConcurrentHashMap<ObjectPoolMapKey, SbbObjectPool>();
}
/**
* Retrieves the current pool configuration
*
* @return
*/
public GenericObjectPool.Config getPoolConfig() {
return config;
}
/**
* Defines the current pool configuration
*/
public void setPoolConfig(GenericObjectPool.Config config) {
this.config = config;
}
/**
* Retrieves the object pool for the specified sbb and service.
* @param serviceID
* @param sbbID
* @return
*/
public SbbObjectPool getObjectPool(ServiceID serviceID, SbbID sbbID) {
return pools.get(new ObjectPoolMapKey(serviceID,sbbID));
}
/**
* Creates an object pool for the specified service and sbb. If a
* transaction manager is used then, and if the tx rollbacks, the pool will
* be removed.
*
* @param
* @param sleeTransactionManager
*/
public void createObjectPool(final ServiceID serviceID, final SbbComponent sbbComponent,
final SleeTransactionManager sleeTransactionManager) {
if (logger.isDebugEnabled()) {
logger.debug("Creating Pool for " + serviceID +" and "+ sbbComponent);
}
createObjectPool(serviceID,sbbComponent);
if (sleeTransactionManager != null) {
// add a rollback action to remove sbb object pool
TransactionalAction action = new TransactionalAction() {
public void execute() {
if (logger.isDebugEnabled()) {
logger
.debug("Due to tx rollback, removing pool for " + serviceID +" and "+ sbbComponent);
}
try {
removeObjectPool(serviceID,sbbComponent.getSbbID());
} catch (Throwable e) {
logger.error("Failed to remove " + serviceID +" and "+ sbbComponent + " object pool", e);
}
}
};
try {
sleeTransactionManager.addAfterRollbackAction(action);
} catch (Throwable e) {
logger.error(e.getMessage(),e);
}
}
}
/**
*
* @param serviceID
* @param sbbID
*/
private void createObjectPool(final ServiceID serviceID, final SbbComponent sbbComponent) {
// create the pool for the given SbbID
GenericObjectPoolFactory poolFactory = new GenericObjectPoolFactory(
new SbbObjectPoolFactory(serviceID,sbbComponent), config);
final ObjectPool objectPool = poolFactory.createPool();
final SbbObjectPool oldObjectPool = pools.put(new ObjectPoolMapKey(serviceID,sbbComponent.getSbbID()),
new SbbObjectPool(objectPool));
if (oldObjectPool != null) {
// there was an old pool, close it
try {
oldObjectPool.close();
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to close old pool for " + serviceID + "and " + sbbComponent);
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Created Pool for " + serviceID + "and " + sbbComponent);
}
}
/**
* Removes the object pool for the sbb with the specified component and the specified service. If a
* transaction manager is used then, and if the tx rollbacks, the pool will
* be restored.
*
* @param sbbDescriptor
* @param sleeTransactionManager
* @throws Exception
*/
public void removeObjectPool(final ServiceID serviceID, final SbbComponent sbbComponent,
final SleeTransactionManager sleeTransactionManager) {
if (logger.isDebugEnabled()) {
logger.debug("Removing Pool for " + serviceID + "and " + sbbComponent);
}
removeObjectPool(serviceID,sbbComponent.getSbbID());
if (sleeTransactionManager != null) {
// restore object pool if tx rollbacks
TransactionalAction action = new TransactionalAction() {
public void execute() {
if (logger.isDebugEnabled()) {
logger
.debug("Due to tx rollback, restoring pool for " + serviceID + "and " + sbbComponent);
}
createObjectPool(serviceID,sbbComponent);
}
};
try {
sleeTransactionManager.addAfterRollbackAction(action);
} catch (Throwable e) {
logger.error(e.getMessage(),e);
}
}
}
/**
* Removes the pool for the specified ids
*
* @param serviceID
* @param sbbID
* @throws Exception
*/
private void removeObjectPool(final ServiceID serviceID, final SbbID sbbID) {
ObjectPoolMapKey key = new ObjectPoolMapKey(serviceID,sbbID);
final SbbObjectPool objectPool = pools.remove(key);
if (objectPool != null) {
try {
objectPool.close();
} catch (Exception e) {
logger.error("failed to close pool",e);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Removed Pool for " + key);
}
}
// ---- MBEAN METHODS
public void register() {
MBeanServer mBeanServer = sleeContainer.getMBeanServer();
try {
mBeanServer.registerMBean(this, new ObjectName(MBEAN_NAME));
} catch (Exception e) {
logger.error("Failed to register", e);
}
}
public void unregister() {
try {
sleeContainer.getMBeanServer().unregisterMBean(
new ObjectName(MBEAN_NAME));
} catch (Exception e) {
logger.error("Failed to unregister", e);
}
}
public int getMaxActive() {
return config.maxActive;
}
public void setMaxActive(int maxActive) {
config.maxActive = maxActive;
}
public int getMaxIdle() {
return config.maxIdle;
}
public void setMaxIdle(int maxIdle) {
config.maxIdle = maxIdle;
}
public int getMinIdle() {
return config.minIdle;
}
public void setMinIdle(int minIdle) {
config.minIdle = minIdle;
}
public long getMaxWait() {
return config.maxWait;
}
public void setMaxWait(long maxWait) {
config.maxWait = maxWait;
}
public long getMinEvictableIdleTimeMillis() {
return config.minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
config.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public int getNumTestsPerEvictionRun() {
return config.numTestsPerEvictionRun;
}
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
config.numTestsPerEvictionRun = numTestsPerEvictionRun;
}
public boolean getTestOnBorrow() {
return config.testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
config.testOnBorrow = testOnBorrow;
}
public boolean getTestOnReturn() {
return config.testOnReturn;
}
public void setTestOnReturn(boolean testOnReturn) {
config.testOnReturn = testOnReturn;
}
public boolean getTestWhileIdle() {
return config.testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
config.testWhileIdle = testWhileIdle;
}
public long getTimeBetweenEvictionRunsMillis() {
return config.timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(
long timeBetweenEvictionRunsMillis) {
config.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public byte getWhenExhaustedAction() {
return config.whenExhaustedAction;
}
public void setWhenExhaustedAction(byte whenExhaustedAction) {
config.whenExhaustedAction = whenExhaustedAction;
}
public void reconfig() {
for (ObjectPoolMapKey key : pools.keySet()) {
final SbbComponent sbbComponent = sleeContainer.getComponentRepositoryImpl().getComponentByID(key.sbbID);
createObjectPool(key.serviceID,sbbComponent);
}
}
@Override
public String toString() {
return "SbbObject Pool Management: " + "\n+-- Pools: " + pools.keySet();
}
private class ObjectPoolMapKey {
private final ServiceID serviceID;
private final SbbID sbbID;
public ObjectPoolMapKey(ServiceID serviceID, SbbID sbbID) {
this.serviceID = serviceID;
this.sbbID = sbbID;
}
@Override
public int hashCode() {
return serviceID.hashCode()*31+sbbID.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == this.getClass()) {
ObjectPoolMapKey other = (ObjectPoolMapKey) obj;
return this.serviceID.equals(other.serviceID) && this.sbbID.equals(other.sbbID);
}
else {
return false;
}
}
@Override
public String toString() {
return serviceID.toString() + " & "+sbbID.toString();
}
}
}