package org.mobicents.slee.container.management;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.Name;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingException;
import javax.slee.facilities.AlarmFacility;
import javax.slee.facilities.Level;
import javax.slee.management.DeploymentException;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.jboss.naming.NonSerializableFactory;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ComponentRepositoryImpl;
import org.mobicents.slee.container.component.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.SbbComponent;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MEnvEntry;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.references.MEjbRef;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MResourceAdaptorEntityBinding;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MResourceAdaptorTypeBinding;
import org.mobicents.slee.container.deployment.SbbClassCodeGenerator;
import org.mobicents.slee.container.service.ServiceActivityContextInterfaceFactoryImpl;
import org.mobicents.slee.container.service.ServiceActivityFactoryImpl;
import org.mobicents.slee.resource.ResourceAdaptorEntity;
import org.mobicents.slee.runtime.facilities.SbbAlarmFacilityImpl;
import org.mobicents.slee.runtime.facilities.TimerFacilityImpl;
import org.mobicents.slee.runtime.transaction.SleeTransactionManager;
/**
* Manages sbbs in container
*
* @author martins
*
*/
@SuppressWarnings("deprecation")
public class SbbManagement {
private static final Logger logger = Logger.getLogger(SbbManagement.class);
private final SleeContainer sleeContainer;
public SbbManagement(SleeContainer sleeContainer) {
this.sleeContainer = sleeContainer;
}
/**
* Deploys an SBB. This generates the code to convert abstract to concrete
* class and registers the component in the component table and creates an
* object pool for the sbb id.
*
* @param mobicentsSbbDescriptor
* the descriptor of the sbb to install
* @throws Exception
*/
public void installSbb(SbbComponent sbbComponent)
throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Installing " + sbbComponent);
}
final SleeTransactionManager sleeTransactionManager = sleeContainer
.getTransactionManager();
sleeTransactionManager.mandateTransaction();
// change classloader
ClassLoader oldClassLoader = Thread.currentThread()
.getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(
sbbComponent.getClassLoader());
// Set up the comp/env naming context for the Sbb.
setupSbbEnvironment(sbbComponent);
// generate class code for the sbb
new SbbClassCodeGenerator().process(sbbComponent);
//FIXME: this will erase stack trace.
//} catch (Exception ex) {
// throw ex;
} finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
// Set 1.0 Trace to off
sleeContainer.getTraceMBean().getTraceFacility().setTraceLevelOnTransaction(
sbbComponent.getSbbID(), Level.OFF);
sleeContainer.getAlarmMBean().registerComponent(
sbbComponent.getSbbID());
}
private void setupSbbEnvironment(SbbComponent sbbComponent) throws Exception {
Context ctx = (Context) new InitialContext().lookup("java:comp");
if (logger.isDebugEnabled()) {
logger.debug("Setting up SBB env. Initial context is " + ctx);
}
Context envCtx = null;
try {
envCtx = ctx.createSubcontext("env");
} catch (NameAlreadyBoundException ex) {
envCtx = (Context) ctx.lookup("env");
}
Context sleeCtx = null;
try {
sleeCtx = envCtx.createSubcontext("slee");
} catch (NameAlreadyBoundException ex) {
sleeCtx = (Context) envCtx.lookup("slee");
}
// Do all the context binding stuff just once during init and
// just do the linking here.
Context newCtx;
String containerName = "java:slee/container/Container";
try {
newCtx = sleeCtx.createSubcontext("container");
} catch (NameAlreadyBoundException ex) {
} finally {
newCtx = (Context) sleeCtx.lookup("container");
}
try {
newCtx.bind("Container", new LinkRef(containerName));
} catch (NameAlreadyBoundException ex) {
}
String nullAciFactory = "java:slee/nullactivity/nullactivitycontextinterfacefactory";
String nullActivityFactory = "java:slee/nullactivity/nullactivityfactory";
try {
newCtx = sleeCtx.createSubcontext("nullactivity");
} catch (NameAlreadyBoundException ex) {
} finally {
newCtx = (Context) sleeCtx.lookup("nullactivity");
}
try {
newCtx.bind("activitycontextinterfacefactory", new LinkRef(
nullAciFactory));
} catch (NameAlreadyBoundException ex) {
}
try {
newCtx.bind("factory", new LinkRef(nullActivityFactory));
} catch (NameAlreadyBoundException ex) {
}
String serviceActivityContextInterfaceFactory = "java:slee/serviceactivity/"
+ ServiceActivityContextInterfaceFactoryImpl.JNDI_NAME;
String serviceActivityFactory = "java:slee/serviceactivity/"
+ ServiceActivityFactoryImpl.JNDI_NAME;
try {
newCtx = sleeCtx.createSubcontext("serviceactivity");
} catch (NameAlreadyBoundException ex) {
} finally {
newCtx = (Context) sleeCtx.lookup("serviceactivity");
}
try {
newCtx.bind(ServiceActivityContextInterfaceFactoryImpl.JNDI_NAME,
new LinkRef(serviceActivityContextInterfaceFactory));
} catch (NameAlreadyBoundException ex) {
}
try {
newCtx.bind(ServiceActivityFactoryImpl.JNDI_NAME, new LinkRef(
serviceActivityFactory));
} catch (NameAlreadyBoundException ex) {
}
String timer = "java:slee/facilities/" + TimerFacilityImpl.JNDI_NAME;
String aciNaming = "java:slee/facilities/activitycontextnaming";
try {
newCtx = sleeCtx.createSubcontext("facilities");
} catch (NameAlreadyBoundException ex) {
} finally {
newCtx = (Context) sleeCtx.lookup("facilities");
}
try {
newCtx.bind("timer", new LinkRef(timer));
} catch (NameAlreadyBoundException ex) {
}
try {
newCtx.bind("activitycontextnaming", new LinkRef(aciNaming));
} catch (NameAlreadyBoundException ex) {
}
String trace = "java:slee/facilities/trace";
try {
newCtx.bind("trace", new LinkRef(trace));
} catch (NameAlreadyBoundException ex) {
}
String alarm = "java:slee/facilities/alarm";
try {
//This has to be checked, to be sure sbb have it under correct jndi binding
AlarmFacility sbbAlarmFacility = new SbbAlarmFacilityImpl(sbbComponent.getSbbID(),sleeContainer.getAlarmMBean());
newCtx.bind("alarm", sbbAlarmFacility);
} catch (NameAlreadyBoundException ex) {
}
String profile = "java:slee/facilities/profile";
try {
newCtx.bind("profile", new LinkRef(profile));
} catch (NameAlreadyBoundException ex) {
}
String profilteTableAciFactory = "java:slee/facilities/profiletableactivitycontextinterfacefactory";
try {
newCtx.bind("profiletableactivitycontextinterfacefactory",
new LinkRef(profilteTableAciFactory));
} catch (NameAlreadyBoundException ex) {
}
// For each resource that the Sbb references, bind the implementing
// object name to its comp/env
if (logger.isDebugEnabled()) {
logger.debug("Number of Resource Bindings:"
+ sbbComponent.getDescriptor().getResourceAdaptorTypeBindings());
}
ComponentRepositoryImpl componentRepository = sleeContainer.getComponentRepositoryImpl();
for (MResourceAdaptorTypeBinding raTypeBinding : sbbComponent.getDescriptor().getResourceAdaptorTypeBindings()) {
ResourceAdaptorTypeComponent raTypeComponent = componentRepository.getComponentByID(raTypeBinding.getResourceAdaptorTypeRef());
for (MResourceAdaptorEntityBinding raEntityBinding : raTypeBinding.getResourceAdaptorEntityBinding()) {
String raObjectName = raEntityBinding.getResourceAdaptorObjectName();
String linkName = raEntityBinding.getResourceAdaptorEntityLink();
/*
* The Deployment descriptor specifies Zero or more
* resource-adaptor-entity-binding elements. Each
* resource-adaptor-entity-binding element binds an object that
* implements the resource adaptor interface of the resource
* adaptor type into the JNDI comp onent environment of the SBB
* (see Section 6.13.3). Each resource- adaptorentity- binding
* element contains the following sub-elements: A description
* element. This is an optional informational element. A
* resource-adaptor-object?name element. This element specifies
* the location within the JNDI component environment to which
* the object that implements the resource adaptor interface
* will be bound. A resource-adaptor-entity-link element. This
* is an optional element. It identifies the resource adaptor
* entity that provides the object that should be bound into the
* JNDI component environment of the SBB. The identified
* resource adaptor entity must be an instance of a resource
* adaptor whose resource adaptor type is specified by the
* resourceadaptor- type-ref sub-element of the enclosing
* resource-adaptortype- binding element.
*/
ResourceManagement resourceManagement = sleeContainer.getResourceManagement();
ResourceAdaptorEntity raEntity = resourceManagement
.getResourceAdaptorEntity(resourceManagement
.getResourceAdaptorEntityName(linkName));
if (raEntity == null)
throw new Exception(
"Could not find Resource adaptor Entity for Link Name: ["
+ linkName + "] of RA Type ["
+ raTypeComponent + "]");
NameParser parser = ctx.getNameParser("");
Name local = parser.parse(raObjectName);
int tokenCount = local.size();
Context subContext = envCtx;
for (int i = 0; i < tokenCount - 1; i++) {
String nextTok = local.get(i);
try {
subContext.lookup(nextTok);
} catch (NameNotFoundException nfe) {
subContext.createSubcontext(nextTok);
} finally {
subContext = (Context) subContext.lookup(nextTok);
}
}
String lastTok = local.get(tokenCount - 1);
// Bind the resource adaptor instance to where the Sbb expects
// to find it.
if (logger.isDebugEnabled()) {
logger
.debug("setupSbbEnvironment: Binding a JNDI reference to sbb interface of "+raTypeBinding.getResourceAdaptorTypeRef());
}
try {
Object raSbbInterface = raEntity.getResourceAdaptorInterface(raTypeBinding.getResourceAdaptorTypeRef());
if (raSbbInterface != null) {
NonSerializableFactory.rebind(subContext, lastTok,raSbbInterface);
//subContext.bind(lastTok, raEntity.getResourceAdaptorInterface(raTypeBinding.getResourceAdaptorTypeRef()));
}
else {
throw new DeploymentException("Unable to retrieve the RA interface for RA entity "+raEntity.getName()+" and RAType " +raTypeBinding.getResourceAdaptorTypeRef());
}
} catch (NameAlreadyBoundException e) {
logger.warn(
"setupSbbEnvironment: Unable to bind a JNDI reference to sbb interface of "+raTypeBinding.getResourceAdaptorTypeRef(), e);
}
}
String localFactoryName = raTypeBinding.getActivityContextInterfaceFactoryName();
if (localFactoryName != null) {
NameParser parser = ctx.getNameParser("");
Name local = parser.parse(localFactoryName);
int nameSize = local.size();
Context tempCtx = envCtx;
for (int a = 0; a < nameSize - 1; a++) {
String temp = local.get(a);
try {
tempCtx.lookup(temp);
} catch (NameNotFoundException ne) {
tempCtx.createSubcontext(temp);
} finally {
tempCtx = (Context) tempCtx.lookup(temp);
}
}
if (logger.isDebugEnabled()) {
logger
.debug(
"setupSbbEnvironment: Binding a JNDI reference to aci factory interface of "+raTypeBinding.getResourceAdaptorTypeRef());
}
String factoryRefName = local.get(nameSize - 1);
try {
tempCtx
.bind(factoryRefName,raTypeComponent.getActivityContextInterfaceFactory());
} catch (NameAlreadyBoundException e) {
logger.warn(
"setupSbbEnvironment: Unable to bind a JNDI reference to aci factory interface of "+raTypeBinding.getResourceAdaptorTypeRef(), e);
}
}
}
/*
* Bind the ejb-refs
*/
try {
envCtx.createSubcontext("ejb");
} catch (NameAlreadyBoundException ex) {
envCtx.lookup("ejb");
}
if (logger.isDebugEnabled()) {
logger.debug("Created ejb local context");
}
for (MEjbRef ejbRef : sbbComponent.getDescriptor().getEjbRefs()) {
String jndiName = ejbRef.getEjbRefName();
if (logger.isDebugEnabled()) {
logger.debug("Binding ejb: " + ejbRef.getEjbRefName()
+ " with link to " + jndiName);
}
try {
envCtx.bind(ejbRef.getEjbRefName(), new LinkRef(jndiName));
} catch (NameAlreadyBoundException ex) {
}
/*
* Validate the ejb reference has the correct type and classes as
* specified in deployment descriptor
*/
/*
* TODO I think I know the problem here. It seems the ejb is loaded
* AFTER the sbb is loaded, hence the validation fails here since it
* cannot locate the ejb. We need to force the ejb to be loaded
* before the sbb
*/
/*
* Commented out for now
*
*
* Object obj = new InitialContext().lookup("java:comp/env/" +
* ejbRef.getEjbRefName());
*
* Object homeObject = null; try { Class homeClass =
* Thread.currentThread().getContextClassLoader().loadClass(home);
*
* homeObject = PortableRemoteObject.narrow(obj, homeClass);
*
* if (!homeClass.isInstance(homeObject)) { throw new
* DeploymentException("Looked up ejb home is not an instanceof " +
* home); } } catch (ClassNotFoundException e) { throw new
* DeploymentException("Failed to load class " + home); } catch
* (ClassCastException e) { throw new DeploymentException("Failed to
* lookup ejb reference using jndi name " + jndiName); }
*
* Object ejb = null; try { Method m =
* homeObject.getClass().getMethod("create", null); Object ejbObject =
* m.invoke(home, null);
*
* Class ejbClass =
* Thread.currentThread().getContextClassLoader().loadClass(remote);
* if (!ejbClass.isInstance(ejbObject)) { throw new
* DeploymentException("Looked up ejb object is not an instanceof " +
* remote); } } catch (ClassNotFoundException e) { throw new
* DeploymentException("Failed to load class " + remote); }
*
*/
/*
* A note on the <ejb-link> link. The semantics of ejb-link when
* used to reference a remote ejb are not defined in the SLEE spec.
* In J2EE it is defined to mean a reference to an ejb deployed in
* the same J2EE application whose <ejb-name> is the same as the
* link (optionally the ejb-jar) file is also specifed. In SLEE
* there is no J2EE application and ejbs cannot be deployed in the
* SLEE container, therefore we do nothing with <ejb-link> since I
* am not sure what should be done with it anyway! - Tim
*/
}
/* Set the environment entries */
for (MEnvEntry mEnvEntry : sbbComponent.getDescriptor().getEnvEntries()) {
Class type = null;
if (logger.isDebugEnabled()) {
logger.debug("Got an environment entry:" + mEnvEntry);
}
try {
type = Thread.currentThread().getContextClassLoader()
.loadClass(mEnvEntry.getEnvEntryType());
} catch (Exception e) {
throw new DeploymentException(mEnvEntry.getEnvEntryType()
+ " is not a valid type for an environment entry");
}
Object entry = null;
String s = mEnvEntry.getEnvEntryValue();
try {
if (type == String.class) {
entry = new String(s);
} else if (type == Character.class) {
if (s.length() != 1) {
throw new DeploymentException(
s
+ " is not a valid value for an environment entry of type Character");
}
entry = new Character(s.charAt(0));
} else if (type == Integer.class) {
entry = new Integer(s);
} else if (type == Boolean.class) {
entry = new Boolean(s);
} else if (type == Double.class) {
entry = new Double(s);
} else if (type == Byte.class) {
entry = new Byte(s);
} else if (type == Short.class) {
entry = new Short(s);
} else if (type == Long.class) {
entry = new Long(s);
} else if (type == Float.class) {
entry = new Float(s);
}
} catch (NumberFormatException e) {
throw new DeploymentException("Environment entry value " + s
+ " is not a valid value for type " + type);
}
if (logger.isDebugEnabled()) {
logger.debug("Binding environment entry with name:"
+ mEnvEntry.getEnvEntryName() + " type " + entry.getClass()
+ " with value:" + entry + ". Current classloader = "
+ Thread.currentThread().getContextClassLoader());
}
try {
envCtx.bind(mEnvEntry.getEnvEntryName(), entry);
} catch (NameAlreadyBoundException ex) {
logger.error("Name already bound ! ", ex);
}
}
}
public void uninstallSbb(SbbComponent sbbComponent)
throws SystemException, Exception, NamingException {
final SleeTransactionManager sleeTransactionManager = sleeContainer
.getTransactionManager();
sleeTransactionManager.mandateTransaction();
if (logger.isDebugEnabled())
logger.debug("Uninstalling "+sbbComponent);
// remove sbb from trace and alarm facilities
sleeContainer.getTraceMBean().getTraceFacility().unSetTraceLevel(
sbbComponent.getSbbID());
sleeContainer.getAlarmMBean().unRegisterComponent(
sbbComponent.getSbbID());
if (logger.isDebugEnabled()) {
logger.debug("Removed SBB " + sbbComponent.getSbbID()
+ " from trace and alarm facilities");
}
}
}