package org.mobicents.slee.container.service;
import java.util.Set;
import javax.slee.SLEEException;
import javax.slee.SbbID;
import javax.slee.ServiceID;
import javax.slee.management.ServiceState;
import javax.slee.resource.EventFlags;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ServiceComponent;
import org.mobicents.slee.container.management.ResourceManagement;
import org.mobicents.slee.runtime.activity.ActivityContext;
import org.mobicents.slee.runtime.activity.ActivityContextHandle;
import org.mobicents.slee.runtime.activity.ActivityContextHandlerFactory;
import org.mobicents.slee.runtime.sbbentity.SbbEntity;
import org.mobicents.slee.runtime.sbbentity.SbbEntityFactory;
import org.mobicents.slee.runtime.transaction.TransactionalAction;
/**
* Service implementation. This is the run-time representation of the service
* Represents an instance of a Slee Service. Note that in the SLEE, the Service
* is a management artifact.
*
* @author eduardomartins
* @author Francesco Moggia
* @author M. Ranganathan
*
*/
public class Service {
private static final Logger logger = Logger.getLogger(Service.class);
private static final SleeContainer sleeContainer = SleeContainer.lookupFromJndi();
// --- service
private final ServiceComponent serviceComponent;
private final ServiceCacheData cacheData;
/**
* The Public constructor. This is used to create a runtime representation
* of the service.
*
* @param serviceComponent --
* the svc descriptor corresponding to this Service.
*
* @throws RuntimeException
*/
protected Service(ServiceComponent serviceComponent) throws RuntimeException {
if (serviceComponent == null)
throw new NullPointerException("null descriptor or container");
if (logger.isDebugEnabled()) {
logger.debug("Service.Service(): creating service "
+ serviceComponent);
}
this.serviceComponent = serviceComponent;
this.cacheData = new ServiceCacheData(serviceComponent.getServiceID(),sleeContainer.getCluster().getMobicentsCache());
cacheData.create();
}
/**
* get the default priority.
*/
public byte getDefaultPriority() {
return serviceComponent.getDefaultPriority();
}
/**
* Retrieves the service component
* @return
*/
public ServiceComponent getServiceComponent() {
return serviceComponent;
}
/**
* get the component key for the service component from which this service
* was created.
*/
public ServiceID getServiceID() {
return serviceComponent.getServiceID();
}
/**
* Retrieves the {@link SbbID} of the root sbb for this service
* @return
*/
public SbbID getRootSbbID() {
return this.serviceComponent.getRootSbbComponent().getSbbID();
}
/**
* Set the service state.
*
* @param serviceState
*/
public void setState(final ServiceState serviceState) {
if (logger.isDebugEnabled()) {
try {
ServiceState oldServiceState = cacheData.getState();
logger
.debug("ServiceComponent.setState(): State service ID = "
+ getServiceID()
+ " current State = "
+ oldServiceState
+ " new State = "
+ serviceState
+ " TX ID: "
+ sleeContainer.getTransactionManager()
.getTransaction());
} catch (SystemException e) {
logger.error("error in debugging setState(): ", e);
}
}
cacheData.setState(serviceState);
// notifying the resource adaptors about service state change if the tx commits
final ResourceManagement resourceManagement = sleeContainer
.getResourceManagement();
TransactionalAction action = new TransactionalAction() {
public void execute() {
ServiceID serviceID = getServiceID();
for (String raEntityName : resourceManagement
.getResourceAdaptorEntities()) {
if (serviceState == ServiceState.ACTIVE) {
resourceManagement.getResourceAdaptorEntity(raEntityName).serviceActive(serviceID);
}
else if (serviceState == ServiceState.STOPPING) {
resourceManagement.getResourceAdaptorEntity(raEntityName).serviceStopping(serviceID);
}
else if (serviceState == ServiceState.INACTIVE) {
resourceManagement.getResourceAdaptorEntity(raEntityName).serviceInactive(serviceID);
}
}
}
};
try {
sleeContainer.getTransactionManager().addAfterCommitAction(action);
} catch (SystemException e) {
throw new SLEEException(e.getMessage(),e);
}
}
/**
* Returns the service state.
*
* @return
*/
public ServiceState getState() {
if (cacheData.exists() && !cacheData.isRemoved()) {
// we need to trap service state retrieval since it may be done for
// a service that is not in cache
ServiceState serviceState = cacheData.getState();
if (serviceState != null) {
return serviceState;
}
}
return ServiceState.INACTIVE;
}
/**
* Get the SBB entity values for the service. Note operation is rather
* expensive as reading all the SBB entities from the cache. Avoid using
* it whenever possible
*
*
*/
public Set<String> getChildObj() {
return cacheData.getChildSbbEntities();
}
/**
* Check if this service maps the specified convergence name.
*
* @param convergenceName
* @return
*/
public boolean containsConvergenceName(String convergenceName) {
return cacheData.hasChild(convergenceName);
}
/**
* Add a child for a given convergence name. This actually creates an Sbb
* Entity for the given convergence name and returns it.
*
* @param convergenceName
*/
public SbbEntity addChild(String convergenceName) {
if (logger.isDebugEnabled()) {
logger.debug(getServiceID().toString() + " adding convergence name "+convergenceName);
}
// create root sbb entity
SbbEntity sbbEntity = SbbEntityFactory.createRootSbbEntity(getRootSbbID(),
this.getServiceID(), convergenceName);
if (sbbEntity.isCreated()) {
// set default priority
sbbEntity.setPriority(getDefaultPriority());
// store in service's cache data
cacheData.addChild(convergenceName, sbbEntity.getSbbEntityId());
}
return sbbEntity;
}
public String getRootSbbEntityId(String convergenceName) {
return cacheData.getChild(convergenceName);
}
public void removeConvergenceName(String convergenceName) {
if (logger.isDebugEnabled()) {
logger.debug(getServiceID().toString() + " removing convergence name "+convergenceName);
}
cacheData.removeChild(convergenceName);
}
/**
* @return the service activity for this service.
*/
public ServiceActivityImpl getServiceActivity() {
return new ServiceActivityImpl(this);
}
/**
* Activate the Service and send out ServiceStartedEvent on the Service
* Activity associated with the Service.
*
* The following steps describe the life cycle of a Service: � A Service
* enters the Inactive state when the Service is installed successfully into
* the SLEE. � A Service enters the Active state from the Inactive state
* when the Service is activated. At this point, the SLEE may start a
* Service Activity for the Service, and fire a Service Started Event on
* this Activity, as described in Section 8.7. The operational state of a
* Service is persistent, i.e. the SLEE remembers the last state the Service
* is in. If the SLEE is shut down and then restarted, the SLEE restores
* these Services to their previous operational state.
*
*/
public void startActivity() {
// create ac for the activity
ActivityContextHandle ach = ActivityContextHandlerFactory.createServiceActivityContextHandle(new ServiceActivityHandle(serviceComponent.getServiceID()));
ActivityContext ac = sleeContainer.getActivityContextFactory().createActivityContext(ach);
if (logger.isDebugEnabled()) {
logger
.debug("starting service activity for "
+ serviceComponent);
}
// fire slee 1.0 and 1.1 service started events
ServiceStartedEventImpl event = new ServiceStartedEventImpl(getServiceID());
ac.fireEvent(ServiceStartedEventImpl.SLEE_10_EVENT_TYPE_ID,event,null,null,EventFlags.NO_FLAGS);
ac.fireEvent(ServiceStartedEventImpl.SLEE_11_EVENT_TYPE_ID,event,null,event.getService(),EventFlags.NO_FLAGS);
}
/**
* This sets the service state to STOPPING and sends out activity end events
* on the ServiceActivity. The state transitions to INACTIVE happens in the
* EventRouter after the EndActivity for the service activty is Consumed.
* The root sbb entity trees are forcefully removed when the service
* activity is consumed.
*
* A Service enters the Stopping state from the Active state when the
* Service is deactivated. At this point, the SLEE ends the Activity
* associated with the Service, if it exists (see Section 8.7.2), and fires
* an Activity End Event on this Activity. SBB entities belonging to the
* Service that require clean-up when the Service is deactivated should
* listen to this event and terminate their processing quickly but
* gracefully when this event is received. Optionally, after some SLEE
* implementation determined time, the SLEE may also forcefully remove the
* outstanding SBB entity trees of the Service. � The SLEE moves a Service
* to the Inactive state from the Stopping state spontaneously when all
* outstanding SBB entity trees of the Service complete their processing.
* The operational state of a Service is persistent, i.e. the SLEE remembers
* the last state the Service is in. If the SLEE is shut down and then
* restarted, the SLEE restores these Services to their previous operational
* state.
*
*
*/
public void endActivity() {
ActivityContextHandle ach = ActivityContextHandlerFactory.createServiceActivityContextHandle(new ServiceActivityHandle(serviceComponent.getServiceID()));
if (logger.isDebugEnabled()) {
logger.debug("ending service activity "+ach);
}
ActivityContext ac = sleeContainer.getActivityContextFactory().getActivityContext(ach);
if (ac != null) {
ac.endActivity();
}
else {
logger.error("unable to find and end ac "+ach);
}
}
/**
* Removes the service data
*/
public void removeFromCache() {
cacheData.remove();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service.printNode() { serviceID = " + getServiceID() + "\n");
if (logger.isDebugEnabled()) {
// very expensive operation. Use w/ care
sb.append("childObj = " + cacheData.getChildSbbEntities() + "/n");
} else {
sb.append("childObj = <not fully loaded from cache>\n");
}
sb
.append(
"defaultPriority = " + this.getDefaultPriority()
+ "\n")
.append("serviceActivity = " + this.getServiceActivity() + "\n")
.append("serviceState = " + this.getState() + "\n").append("}");
return sb.toString();
}
}