/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt 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.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.sbb.SbbComponent;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionalAction;
/**
*
* Manages sbb object pools in the SLEE container.
*
* @author martins
*
*/
public class SbbObjectPoolManagementImpl implements SbbObjectPoolManagementImplMBean {
private final static Logger logger = Logger
.getLogger(SbbObjectPoolManagementImpl.class);
private final ConcurrentHashMap<ObjectPoolMapKey, SbbObjectPoolImpl> pools;
private final SleeContainer sleeContainer;
private GenericObjectPool.Config config;
public SbbObjectPoolManagementImpl(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 = 1;
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, SbbObjectPoolImpl>();
}
/**
* 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 SbbObjectPoolImpl 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.isTraceEnabled()) {
logger.trace("Creating Pool for " + serviceID +" and "+ sbbComponent);
}
createObjectPool(serviceID,sbbComponent);
if (sleeTransactionManager != null && sleeTransactionManager.getTransactionContext() != 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);
}
}
};
sleeTransactionManager.getTransactionContext().getAfterRollbackActions().add(action);
}
}
/**
*
* @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 SbbObjectPoolImpl oldObjectPool = pools.put(new ObjectPoolMapKey(serviceID,sbbComponent.getSbbID()),
new SbbObjectPoolImpl(sbbComponent,serviceID,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.isTraceEnabled()) {
logger.trace("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);
}
};
sleeTransactionManager.getTransactionContext().getAfterRollbackActions().add(action);
}
}
/**
* 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 SbbObjectPoolImpl 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.getComponentRepository().getComponentByID(key.sbbID);
createObjectPool(key.serviceID,sbbComponent);
}
}
@Override
public String toString() {
return "SbbObject Pool Management: " + "\n+-- Pools: " + pools.keySet();
}
private static 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();
}
}
}