/*
* 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.activity;
import javax.slee.SLEEException;
import javax.slee.SbbLocalObject;
import javax.slee.TransactionRequiredLocalException;
import javax.slee.TransactionRolledbackLocalException;
import javax.slee.facilities.TimerID;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.activity.ActivityContext;
import org.mobicents.slee.container.activity.ActivityContextInterface;
import org.mobicents.slee.container.activity.ActivityEventQueueManager;
import org.mobicents.slee.container.event.EventContext;
import org.mobicents.slee.container.eventrouter.EventRoutingTask;
import org.mobicents.slee.container.sbbentity.SbbEntity;
import org.mobicents.slee.container.transaction.SleeTransaction;
import org.mobicents.slee.container.transaction.SleeTransactionManager;
import org.mobicents.slee.container.transaction.TransactionContext;
import org.mobicents.slee.container.transaction.TransactionalAction;
/**
*
* Activity context interface - default implementation. The Sbb deployer has to
* imbed an instance of this as a proxy object in each sbb ACI.
*
* This is the SLEE wrapper data structure for Activity Contexts. The Sbb gets
* to access this rather than the activity. The reason this exists is because
* the activity context can be at a different location than the activity context
* interface (does not need to be co-located in the same jvm. )
*
* @author M. Ranganathan
* @author Ralf Siedow
* @author martins
*
*/
public class ActivityContextInterfaceImpl implements ActivityContextInterface {
private static Logger logger = Logger
.getLogger(ActivityContextInterfaceImpl.class);
private static final SleeContainer sleeContainer = SleeContainer
.lookupFromJndi();
private boolean doTraceLogs = logger.isTraceEnabled();
private final ActivityContext activityContext;
/**
* This is allocated by the Slee to wrap an incoming event (activity).
*
* @param activityContextHandle
*/
public ActivityContextInterfaceImpl(ActivityContext activityContext) {
this.activityContext = activityContext;
}
/*
* (non-Javadoc)
*
* @see javax.slee.ActivityContextInterface#getActivity()
*/
public Object getActivity() throws TransactionRequiredLocalException,
SLEEException {
sleeContainer.getTransactionManager().mandateTransaction();
return activityContext.getActivityContextHandle().getActivityObject();
}
/*
* (non-Javadoc)
*
* @see javax.slee.ActivityContextInterface#attach(javax.slee.SbbLocalObject)
*/
public void attach(SbbLocalObject sbbLocalObject)
throws NullPointerException, TransactionRequiredLocalException,
TransactionRolledbackLocalException, SLEEException {
if (doTraceLogs) {
logger.trace("attach( ac = "+activityContext+" , sbbLocalObject = " + sbbLocalObject + " )");
}
if (sbbLocalObject == null)
throw new NullPointerException("null SbbLocalObject !");
sleeContainer.getTransactionManager().mandateTransaction();
org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;
SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();
boolean attached = getActivityContext().attachSbbEntity(sbbEntity.getSbbEntityId());
boolean setRollbackAndThrowException = false;
if (attached) {
try {
if (sbbEntity.isRemoved()) {
setRollbackAndThrowException = true;
} else {
// attach entity from ac
sbbEntity.afterACAttach(getActivityContext().getActivityContextHandle());
}
} catch (Exception e) {
setRollbackAndThrowException = true;
}
}
if (setRollbackAndThrowException) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException e) {
logger
.warn(
"failed to set rollback flag while asserting valid sbb entity",
e);
}
throw new TransactionRolledbackLocalException(
"Failed to attach invalid sbb entity. SbbID " + sbbEntity.getSbbEntityId());
}
if (attached) {
// JSLEE 1.0 Spec, Section 8.5.8 excerpt:
// The SLEE delivers the event to an SBB entity that stays attached once. The SLEE may deliver the
// event to the same SBB entity more than once if it has been detached and then re -attached.
final EventRoutingTask routingTask = activityContext.getLocalActivityContext().getCurrentEventRoutingTask();
EventContext eventContextImpl = routingTask != null ? routingTask.getEventContext() : null;
if (eventContextImpl != null && eventContextImpl.getSbbEntitiesThatHandledEvent().remove(sbbEntity.getSbbEntityId())) {
if (doTraceLogs) {
logger.trace("Removed the SBB Entity ["
+ sbbEntity.getSbbEntityId()
+ "] from the delivered set of activity context ["
+ getActivityContext().getActivityContextHandle()
+ "]. Seems to be a reattachment after detachment in the same event delivery transaction. See JSLEE 1.0 Spec, Section 8.5.8.");
}
}
}
}
/*
* (non-Javadoc)
*
* @see javax.slee.ActivityContextInterface#detach(javax.slee.SbbLocalObject)
*/
public void detach(SbbLocalObject sbbLocalObject)
throws NullPointerException, TransactionRequiredLocalException,
TransactionRolledbackLocalException, SLEEException {
if (doTraceLogs) {
logger.trace("detach( ac = "+activityContext+" , sbbLocalObject = " + sbbLocalObject + " )");
}
if (sbbLocalObject == null)
throw new NullPointerException("null SbbLocalObject !");
sleeContainer.getTransactionManager().mandateTransaction();
org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;
SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();
// detach ac from entity
final ActivityContext ac = getActivityContext();
ac.detachSbbEntity(sbbEntity.getSbbEntityId());
boolean setRollbackAndThrowException = false;
try {
if (sbbEntity.isRemoved()) {
setRollbackAndThrowException = true;
} else {
// detach entity from ac
sbbEntity.afterACDetach(getActivityContext().getActivityContextHandle());
}
} catch (Exception e) {
setRollbackAndThrowException = true;
}
if (setRollbackAndThrowException) {
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (SystemException e) {
logger
.warn(
"failed to set rollback flag while asserting valid sbb entity",
e);
}
throw new TransactionRolledbackLocalException(
"Failed to detach invalid sbb entity. SbbID " + sbbEntity.getSbbEntityId());
}
}
/*
* (non-Javadoc)
*
* @see javax.slee.ActivityContextInterface#isEnding()
*/
public boolean isEnding() throws TransactionRequiredLocalException,
SLEEException {
sleeContainer.getTransactionManager().mandateTransaction();
return getActivityContext().isEnding();
}
public ActivityContext getActivityContext() {
return activityContext;
}
@Override
public int hashCode() {
return activityContext.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == this.getClass()) {
return ((ActivityContextInterfaceImpl) obj).activityContext
.equals(this.activityContext);
} else {
return false;
}
}
/*
* (non-Javadoc)
* @see javax.slee.ActivityContextInterface#isAttached(javax.slee.SbbLocalObject)
*/
public boolean isAttached(SbbLocalObject sbbLocalObject) throws NullPointerException,
TransactionRequiredLocalException,
TransactionRolledbackLocalException, SLEEException {
if (sbbLocalObject == null) {
throw new NullPointerException("null sbbLocalObject");
}
sleeContainer.getTransactionManager().mandateTransaction();
if (sbbLocalObject instanceof org.mobicents.slee.container.sbb.SbbLocalObject) {
org.mobicents.slee.container.sbb.SbbLocalObject sbbLocalObjectImpl = (org.mobicents.slee.container.sbb.SbbLocalObject) sbbLocalObject;
SbbEntity sbbEntity = sbbLocalObjectImpl.getSbbEntity();
if (sbbEntity != null && !sbbEntity.isRemoved()) {
return sbbEntity.isAttached(activityContext.getActivityContextHandle());
}
}
try {
sleeContainer.getTransactionManager().setRollbackOnly();
} catch (Exception e) {
throw new SLEEException(e.getMessage(),e);
}
throw new TransactionRolledbackLocalException("the sbbLocalObject argument must represent a valid SBB entity");
}
private static final String[] EMPTY_STRING_ARRAY = {};
private static final TimerID[] EMPTY_TIMERID_ARRAY = {};
// SLEE 1.1 Extensions
@Override
public String[] getNamesBound() {
return activityContext.getNamingBindings().toArray(EMPTY_STRING_ARRAY);
}
@Override
public TimerID[] getTimers() {
return activityContext.getAttachedTimers().toArray(EMPTY_TIMERID_ARRAY);
}
@Override
public void suspend() throws TransactionRequiredLocalException,
SLEEException {
final SleeTransactionManager txManager = sleeContainer
.getTransactionManager();
txManager.mandateTransaction();
try {
final SleeTransaction tx = txManager.getTransaction();
final ActivityEventQueueManager aeqm = activityContext
.getLocalActivityContext().getEventQueueManager();
aeqm.createBarrier(tx);
final TransactionalAction action = new TransactionalAction() {
public void execute() {
aeqm.removeBarrier(tx);
}
};
final TransactionContext tc = tx.getTransactionContext();
tc.getAfterCommitActions().add(action);
tc.getAfterRollbackActions().add(action);
} catch (Throwable e) {
throw new SLEEException(e.getMessage(), e);
}
}
}