/*
* 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.Set;
import javax.slee.ActivityContextInterface;
import javax.slee.CreateException;
import javax.slee.SLEEException;
import javax.slee.Sbb;
import javax.slee.ServiceID;
import javax.slee.TransactionRequiredLocalException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.SleeContainerUtils;
import org.mobicents.slee.container.SleeThreadLocals;
import org.mobicents.slee.container.component.sbb.SbbComponent;
import org.mobicents.slee.container.eventrouter.EventRoutingTransactionData;
import org.mobicents.slee.container.eventrouter.SbbInvocationState;
import org.mobicents.slee.container.jndi.JndiManagement;
import org.mobicents.slee.container.sbb.SbbObject;
import org.mobicents.slee.container.sbb.SbbObjectState;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.sbbentity.SbbEntityID;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
/**
* SbbEntity implementation object. This is the wrapper object for a concrete
* SBB instance that the container keeps in memory. This is also used to track
* things like child relation objects for a sbb instance that has been loaded
* into the slee.
*
*
* @author Francesco Moggia
* @author M. Ranganathan
* @author Ralf Siedow
* @author eduardomartins
*
*/
public class SbbObjectImpl implements SbbObject {
private final static SleeContainer sleeContainer = SleeContainer
.lookupFromJndi();
private SbbObjectState state;
private SbbInvocationState invocationState = SbbInvocationState.NOT_INVOKING;
private static Logger log = Logger.getLogger(SbbObjectImpl.class);
private final boolean doTraceLogs = log.isTraceEnabled();
/**
* the service id assigned to this object
*/
private final ServiceID serviceID;
private SbbEntity sbbEntity;
// My SBB concrete class
private SbbConcrete sbbConcrete;
/**
* the sbb component
*/
private final SbbComponent sbbComponent;
/**
* The Sbb context is the object through which the Sbb interacts with the
* Slee
*/
private SbbContextImpl sbbContext;
/**
* Creates a new instance of SbbObject.
*
* @param sbbComponent .
*
*
*/
public SbbObjectImpl(ServiceID serviceID, SbbComponent sbbComponent) {
this.serviceID = serviceID;
this.sbbComponent = sbbComponent;
this.createConcreteClass();
// set sbb context
this.sbbContext = new SbbContextImpl(this);
if (doTraceLogs) {
log.trace("setSbbContext()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSetSbbContext()) {
// before invoking setSbbContext we my need to save the service id in the
// thread, so the alarm facility can retrieve it
boolean invokingServiceSet = SleeThreadLocals
.getInvokingService() != null;
if (!invokingServiceSet) {
SleeThreadLocals.setInvokingService(serviceID);
}
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.setSbbContext(this.sbbContext);
} finally {
jndiManagement.popJndiContext();
if (!invokingServiceSet) {
SleeThreadLocals.setInvokingService(null);
}
}
}
}
public void setSbbEntity(SbbEntity sbbe) {
this.sbbEntity = sbbe;
this.sbbConcrete.setSbbEntity(sbbe);
}
public ServiceID getServiceID() {
return this.serviceID;
}
public SbbEntity getSbbEntity() throws TransactionRequiredLocalException {
return sbbEntity;
}
/**
* @return Returns the state.
*/
public SbbObjectState getState() {
return this.state;
}
public SbbInvocationState getInvocationState() {
return this.invocationState;
}
public void setSbbInvocationState(SbbInvocationState state) {
this.invocationState = state;
}
/**
* @param state
* The state to set.
*/
public void setState(SbbObjectState state) {
if (doTraceLogs)
log.trace("setState: current state = " + this.getState()
+ " new state = " + state);
this.state = state;
}
/**
* Getter for property sbbConcrete. The sbb concrete object is an instance
* of the concrete class that is instantiated by the deployer.
*
* @return Value of property sbbConcrete.
*
*/
public Sbb getSbbConcrete() {
return sbbConcrete;
}
/*
* (non-Javadoc)
*
* @see org.mobicents.slee.runtime.SbbEntity#getSbbComponent()
*/
public SbbComponent getSbbComponent() {
return this.sbbComponent;
}
@Override
public void unsetSbbContext() {
if (doTraceLogs) {
log.trace("unsetSbbContext()");
}
this.sbbContext = null;
if (sbbComponent.getAbstractSbbClassInfo().isInvokeUnsetSbbContext()) {
final ClassLoader oldClassLoader = SleeContainerUtils
.getCurrentThreadClassLoader();
SleeContainerUtils
.setCurrentThreadClassLoader(this.sbbComponent
.getClassLoader());
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
if (this.sbbConcrete != null)
this.sbbConcrete.unsetSbbContext();
} finally {
jndiManagement.popJndiContext();
SleeContainerUtils.setCurrentThreadClassLoader(oldClassLoader);
}
}
}
@Override
public void sbbCreate() throws CreateException {
if (doTraceLogs) {
log.trace("sbbCreate()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbCreate()) {
this.invocationState = SbbInvocationState.INVOKING_SBB_CREATE;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbCreate();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
}
}
@Override
public void sbbPostCreate() throws CreateException {
if (doTraceLogs) {
log.trace("sbbPostCreate()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbPostCreate()) {
if (!sbbEntity.isReentrant()) {
Set<SbbEntityID> invokedsbbEntities = sleeContainer
.getTransactionManager().getTransactionContext()
.getInvokedNonReentrantSbbEntities();
if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
throw new SLEEException(
" unable to invoke sbb, re-entrancy not allowed by sbb "
+ sbbComponent.getSbbID());
}
try {
this.invocationState = SbbInvocationState.INVOKING_SBB_POSTCREATE;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbPostCreate();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
} finally {
invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
}
} else {
this.invocationState = SbbInvocationState.INVOKING_SBB_POSTCREATE;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbPostCreate();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
}
}
}
@Override
public void sbbActivate() {
if (doTraceLogs) {
log.trace("sbbActivate()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbActivate()) {
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbActivate();
} finally {
jndiManagement.popJndiContext();
}
}
}
@Override
public void sbbPassivate() {
if (doTraceLogs) {
log.trace("sbbPassivate()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbPassivate()) {
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbPassivate();
} finally {
jndiManagement.popJndiContext();
}
}
}
@Override
public void sbbLoad() throws TransactionRequiredLocalException {
if (doTraceLogs) {
log.trace("sbbLoad()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbLoad()) {
SleeTransactionManager txManager = sleeContainer
.getTransactionManager();
txManager.mandateTransaction();
if (!sbbEntity.isReentrant()) {
Set<SbbEntityID> invokedsbbEntities = txManager
.getTransactionContext()
.getInvokedNonReentrantSbbEntities();
if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
throw new SLEEException(
" unable to invoke sbb, re-entrancy not allowed by sbb "
+ sbbComponent.getSbbID());
}
try {
this.invocationState = SbbInvocationState.INVOKING_SBB_LOAD;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
sbbConcrete.sbbLoad();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
} finally {
invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
}
} else {
this.invocationState = SbbInvocationState.INVOKING_SBB_LOAD;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
sbbConcrete.sbbLoad();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
}
}
}
@Override
public void sbbStore() {
if (doTraceLogs) {
log.trace("sbbStore()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbStore()) {
SleeTransactionManager txMgr = sleeContainer
.getTransactionManager();
txMgr.mandateTransaction();
if (this.sbbConcrete != null) {
final ClassLoader oldClassLoader = SleeContainerUtils
.getCurrentThreadClassLoader();
Set<SbbEntityID> invokedsbbEntities = null;
try {
SleeContainerUtils
.setCurrentThreadClassLoader(this.sbbComponent
.getClassLoader());
if (!sbbEntity.isReentrant()) {
invokedsbbEntities = txMgr.getTransactionContext()
.getInvokedNonReentrantSbbEntities();
if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
throw new SLEEException(
" unable to invoke sbb, re-entrancy not allowed by sbb "
+ sbbComponent.getSbbID());
}
}
this.invocationState = SbbInvocationState.INVOKING_SBB_STORE;
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbStore();
} finally {
jndiManagement.popJndiContext();
}
this.invocationState = SbbInvocationState.NOT_INVOKING;
} finally {
if (invokedsbbEntities != null) {
invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
}
SleeContainerUtils
.setCurrentThreadClassLoader(oldClassLoader);
}
}
}
}
@Override
public void sbbExceptionThrown(Exception exception) {
if (doTraceLogs) {
log.trace("sbbExceptionThrown( exception = " + exception + ")");
}
boolean invoke = sbbComponent.getAbstractSbbClassInfo()
.isInvokeSbbExceptionThrown();
Object eventObject = null;
ActivityContextInterface aci = null;
if (invoke) {
EventRoutingTransactionData ertd = sleeContainer
.getTransactionManager().getTransactionContext()
.getEventRoutingTransactionData();
if (ertd != null) {
eventObject = ertd.getEventBeingDelivered().getEvent();
aci = ertd.getAciReceivingEvent();
}
}
sbbContext.setRollbackOnly();
if (invoke) {
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbExceptionThrown(exception, eventObject, aci);
} finally {
jndiManagement.popJndiContext();
}
}
}
@Override
public void sbbRolledBack(Object event,
ActivityContextInterface activityContextInterface,
boolean removeRollback) {
if (doTraceLogs) {
log.trace("sbbExceptionThrown( event= " + event + ", aci="
+ activityContextInterface + ", removeRollback="
+ removeRollback + " )");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbRolledBack()) {
final ClassLoader oldClassLoader = SleeContainerUtils
.getCurrentThreadClassLoader();
Set<SbbEntityID> invokedsbbEntities = null;
try {
SleeContainerUtils
.setCurrentThreadClassLoader(this.sbbComponent
.getClassLoader());
// track and check reentrancy
if (!sbbEntity.isReentrant()) {
invokedsbbEntities = sleeContainer.getTransactionManager()
.getTransactionContext()
.getInvokedNonReentrantSbbEntities();
if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
throw new SLEEException(
" unable to invoke sbb, re-entrancy not allowed by sbb "
+ sbbComponent.getSbbID());
}
}
// invoke sbb
final RolledBackContextImpl sbbRolledBackContext = new RolledBackContextImpl(
event, activityContextInterface, removeRollback);
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbRolledBack(sbbRolledBackContext);
} finally {
jndiManagement.popJndiContext();
}
} finally {
if (invokedsbbEntities != null) {
invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
}
SleeContainerUtils.setCurrentThreadClassLoader(oldClassLoader);
}
}
}
@Override
public void sbbRemove() {
if (doTraceLogs) {
log.trace("sbbRemove()");
}
if (sbbComponent.getAbstractSbbClassInfo().isInvokeSbbRemove()) {
final ClassLoader oldClassLoader = SleeContainerUtils
.getCurrentThreadClassLoader();
Set<SbbEntityID> invokedsbbEntities = null;
try {
SleeContainerUtils
.setCurrentThreadClassLoader(this.sbbComponent
.getClassLoader());
// track and check reentrancy
if (!sbbEntity.isReentrant()) {
invokedsbbEntities = sleeContainer.getTransactionManager()
.getTransactionContext()
.getInvokedNonReentrantSbbEntities();
if (!invokedsbbEntities.add(sbbEntity.getSbbEntityId())) {
throw new SLEEException(
" unable to invoke sbb, re-entrancy not allowed by sbb "
+ sbbComponent.getSbbID());
}
}
// invoke sbb
final JndiManagement jndiManagement = sleeContainer.getJndiManagement();
jndiManagement.pushJndiContext(sbbComponent);
try {
this.sbbConcrete.sbbRemove();
} finally {
jndiManagement.popJndiContext();
}
} finally {
if (invokedsbbEntities != null) {
invokedsbbEntities.remove(sbbEntity.getSbbEntityId());
}
SleeContainerUtils.setCurrentThreadClassLoader(oldClassLoader);
}
}
}
private void createConcreteClass() {
try {
// logger.debug(sbbDescriptor.getConcreteSbbClass());
// Concrete class of the Sbb. the concrete sbb class is the
// class that implements the Sbb methods. This is obtained
// from the deployment descriptor and the abstract sbb class.
this.sbbConcrete = (SbbConcrete) sbbComponent.getConcreteSbbClass()
.newInstance();
} catch (Exception ex) {
log.error("unexpected exception creating concrete class!", ex);
throw new RuntimeException(
"Unexpected exception creating concrete class for "
+ this.sbbComponent.getSbbID(), ex);
}
}
}