package org.mobicents.slee.container.component.deployment;
import java.lang.reflect.Modifier;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import javax.slee.SLEEException;
import javax.slee.management.DeploymentException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.deployment.ClassPool;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.profile.MProfileAbstractClass;
/**
* Class decorating the profile abstract class.
* @author martins
*
*/
public class ProfileAbstractClassDecorator {
private static final Logger logger = Logger.getLogger(ProfileAbstractClassDecorator.class);
/**
* the abstract class
*/
private CtClass ctClass = null;
private final ProfileSpecificationComponent component;
/**
* Constructor
*/
public ProfileAbstractClassDecorator(ProfileSpecificationComponent component) {
this.component = component;
}
/**
* Decorate the abstract Class
*
* @return true is the class was decorated
*/
public boolean decorateAbstractClass() throws DeploymentException {
ClassPool pool = component.getClassPool();
MProfileAbstractClass abstractClass = component.getDescriptor().getProfileAbstractClass();
if (abstractClass == null) {
return false;
}
String abstractClassName = abstractClass.getProfileAbstractClassName();
try {
ctClass = pool.get(abstractClassName);
} catch (NotFoundException nfe) {
throw new DeploymentException("Could not find Abstract Class: "
+ abstractClassName, nfe);
}
decorateClassJNDIAddToEnvironmentCalls();
if (isAbstractClassDecorated) {
try {
String deployDir = component.getDeploymentDir().getAbsolutePath();
ctClass.writeFile(deployDir);
ctClass.detach();
// the file on disk is now in sync with the latest in-memory version
if (logger.isDebugEnabled()) {
logger.debug("Modified Abstract Class "
+ ctClass.getName()
+ " generated in the following path "
+ deployDir);
}
} catch (Throwable e) {
throw new SLEEException ( e.getMessage(), e);
} finally {
ctClass.defrost();
}
return true;
}
else {
return false;
}
}
/**
*
* @return
*/
private void decorateClassJNDIAddToEnvironmentCalls() {
for (CtMethod ctMethod : ctClass.getMethods()) {
if (!Modifier.isAbstract(ctMethod.getModifiers()) && !Modifier.isNative(ctMethod.getModifiers()) && !ctMethod.getDeclaringClass().getName().equals(Object.class.getName())) {
try {
decorateMethodJNDIAddToEnvironmentCalls(ctMethod);
} catch (CannotCompileException e) {
throw new SLEEException(e.getMessage(),e);
}
}
}
}
private void decorateMethodJNDIAddToEnvironmentCalls(CtMethod method)
throws CannotCompileException {
method.instrument(new ExprEditor() {
public void edit(MethodCall m) throws CannotCompileException {
// the call has to be on a JNDI Context object
boolean isJndiCtx = false;
try {
// see if the method call is on javax.naming.Context or a derived type
if (m.getClassName().equals(javax.naming.Context.class.getName())) {
isJndiCtx = true;
} else {
CtClass cl0 = component.getClassPool().get(m.getClassName());
CtClass[] cl0Interfaces = cl0.getInterfaces();
for (int i = 0; i < cl0Interfaces.length; i++) {
CtClass cl0If = cl0Interfaces[i];
if (cl0If.getName().equals(javax.naming.Context.class.getName())) {
isJndiCtx = true;
break;
}
}
}
} catch (NotFoundException e) {
// The class is not in the pool so ignore it
return;
//throw new CannotCompileException(e);
}
if (!isJndiCtx)
return;
if (m.getMethodName().endsWith("bind") || m.getMethodName().equals("createSubcontext") ) {
m.replace("{ throw new javax.naming.OperationNotSupportedException(); $_ = $proceed($$); }");
isAbstractClassDecorated = true;
}
else if (m.getMethodName().equals("addToEnvironment")) {
m.replace("{ throw new javax.naming.NamingException(); $_ = $proceed($$); }");
isAbstractClassDecorated = true;
}
}
});
}
boolean isAbstractClassDecorated = false;
}