package org.mobicents.slee.container.deployment.profile;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javax.slee.SLEEException;
import javax.slee.TransactionRolledbackLocalException;
import javax.slee.management.DeploymentException;
import javax.slee.profile.ProfileLocalObject;
import javax.transaction.SystemException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.SleeContainer;
import org.mobicents.slee.container.component.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.deployment.ClassPool;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ProfileSpecificationDescriptorImpl;
import org.mobicents.slee.container.deployment.ClassUtils;
import org.mobicents.slee.container.deployment.ConcreteClassGeneratorUtils;
import org.mobicents.slee.container.profile.ProfileLocalObjectImpl;
import org.mobicents.slee.container.profile.ProfileObject;
import org.mobicents.slee.container.profile.ProfileObjectState;
import org.mobicents.slee.container.security.Utility;
public class ConcreteProfileLocalObjectGenerator {
private static final Logger logger = Logger.getLogger(ConcreteProfileLocalObjectGenerator.class);
/**
* the component to process
*/
private final ProfileSpecificationComponent component;
/**
*
* @param component
*/
public ConcreteProfileLocalObjectGenerator(ProfileSpecificationComponent component) {
this.component = component;
}
/**
*
* @throws Exception
*/
public void generateProfileLocalConcreteClass() throws Exception {
ProfileSpecificationDescriptorImpl descriptor = component.getDescriptor();
ClassPool pool = component.getClassPool();
CtClass profileLocalObjectInterface = null;
CtClass profileLocalObjectImplClass = null;
try {
// This is the class we will extend
profileLocalObjectImplClass = pool.get(ProfileLocalObjectImpl.class.getName());
// the slee defined interface
profileLocalObjectInterface = pool.get(ProfileLocalObject.class.getName());
}
catch (NotFoundException nfe) {
throw new SLEEException("Failed to locate required class for " + component, nfe);
}
boolean profileLocalObjectInterfaceProvided = descriptor.getProfileLocalInterface() != null;
String profileLocalInterfaceName = null;
String profileLocalConcreteClassName = null;
if (profileLocalObjectInterfaceProvided) {
profileLocalInterfaceName = descriptor.getProfileLocalInterface().getProfileLocalInterfaceName();
profileLocalConcreteClassName = profileLocalInterfaceName + "Impl";
}
else {
profileLocalInterfaceName = descriptor.getProfileCMPInterface().getProfileCmpInterfaceName();
profileLocalConcreteClassName = profileLocalInterfaceName + "_PLO_Impl";
}
CtClass profileLocalConcreteClass = null;
try {
profileLocalConcreteClass = pool.makeClass(profileLocalConcreteClassName);
} catch (Exception e) {
throw new DeploymentException("Failed to create Profile Local Interface implementation class.",e);
}
CtClass profileLocalInterface = null;
try {
profileLocalInterface = pool.get(profileLocalInterfaceName);
}
catch (NotFoundException nfe) {
throw new DeploymentException("Failed to locate user provided local object interface class for " + component, nfe);
}
// implement only methods from profile cmp and management interface that are also on user defined local object interface
Map<String, CtMethod> methodsToImplement = ClassUtils.getInterfaceMethodsFromInterface(profileLocalInterface,ClassUtils.getInterfaceMethodsFromInterface(profileLocalObjectInterface));
// Create interface and inheritance links
CtClass[] presentInterfaces = profileLocalObjectImplClass.getInterfaces();
CtClass[] targetInterfaces = new CtClass[presentInterfaces.length + 1];
for (int index = 0; index < presentInterfaces.length; index++) {
targetInterfaces[index] = presentInterfaces[index];
}
targetInterfaces[targetInterfaces.length - 1] = profileLocalInterface;
ConcreteClassGeneratorUtils.createInterfaceLinks(profileLocalConcreteClass, targetInterfaces);
ConcreteClassGeneratorUtils.createInheritanceLink(profileLocalConcreteClass, profileLocalObjectImplClass);
// generate constructor
try {
CtClass[] constructorParameters = new CtClass[] { pool.get(ProfileObject.class.getName()) };
String constructorBody = "{ super($$); }";
CtConstructor constructor = CtNewConstructor.make(constructorParameters, new CtClass[]{}, constructorBody , profileLocalConcreteClass);
profileLocalConcreteClass.addConstructor(constructor);
} catch (CannotCompileException e) {
throw new SLEEException(e.getMessage(),e);
}
// implement methods delegating to an object casted to the profile cmp concrete class generated by SLEE
String profileCmpConcreteClassName = component.getProfileCmpConcreteClass().getName();
for (CtMethod ctMethod : methodsToImplement.values()) {
implementMethod(profileLocalConcreteClass, ctMethod,"(("+profileCmpConcreteClassName+")profileObject.getProfileConcrete())");
}
// generate class file
try {
profileLocalConcreteClass.writeFile(component.getDeploymentDir().getAbsolutePath());
if (logger.isDebugEnabled()) {
logger.debug("Concrete Class " + profileLocalConcreteClassName + " generated in the following path " + component.getDeploymentDir().getAbsolutePath());
}
}
catch (Exception e) {
throw new SLEEException(e.getMessage(), e);
}
finally {
// let go, so that it's not holding subsequent deployments of the same profile component.
// This would not have been necessary is the ClassPool is not one shared instance in the SLEE,
// but there is instead a hierarchy mimicing the classloader hierarchy. This also makes
// our deployer essentially single threaded.
profileLocalConcreteClass.defrost();
}
// load it and store it in the component
try {
component.setProfileLocalObjectConcreteClass(component.getClassLoader().loadClass(profileLocalConcreteClassName));
}
catch (ClassNotFoundException e) {
throw new SLEEException(e.getMessage(),e);
}
}
private void implementMethod(CtClass concreteClass, CtMethod method, String interceptorAccess) throws Exception {
// copy method to concrete class
CtMethod newMethod = CtNewMethod.copy( method, concreteClass, null );
// generate body
String returnStatement = method.getReturnType().equals(CtClass.voidType) ? "" : "return ($r)";
String body=
"{ "
+ "super.sleeContainer.getTransactionManager().mandateTransaction();"
+" checkTransaction();"
+ "try {"
+ "if(System.getSecurityManager()!=null && profileObject.getProfileTable().getProfileSpecificationComponent().getDescriptor().isIsolateSecurityPermission()){"
+ ""
+ returnStatement+" " +Utility.class.getName()+".makeSafeProxyCall("+interceptorAccess+",\""+method.getName()+"\",$sig,$args);"
+"}else"
+"{"
+ returnStatement + interceptorAccess +'.'+ method.getName()+"($$);"
+"}"
+ "} catch ("+RuntimeException.class.getName()+" e) {"
+ " try {"
+ " profileObject.invalidateObject(); super.sleeContainer.getTransactionManager().setRollbackOnly();"
+ " } catch ("+SystemException.class.getName()+" e1) {"
+ " throw new "+SLEEException.class.getName()+"(e1.getMessage(),e1);"
+" }"
+""
+ " throw new "+TransactionRolledbackLocalException.class.getName()+"(e.getMessage(),e);"
+ "} catch ("+PrivilegedActionException.class.getName()+" e) {"
+ " try {"
+ " profileObject.invalidateObject(); super.sleeContainer.getTransactionManager().setRollbackOnly();"
+ " } catch ("+SystemException.class.getName()+" e1) {"
+ " throw new "+SLEEException.class.getName()+"(e1.getMessage(),e1);"
+ " }"
+ " throw new "+TransactionRolledbackLocalException.class.getName()+"(e.getCause().getMessage(),e.getCause());"
+ "}"
+"}";
if(logger.isDebugEnabled())
{
logger.debug("Instrumented method, name:"+method.getName()+", with body:\n"+body);
}
newMethod.setBody(body);
// add to concrete class
concreteClass.addMethod(newMethod);
}
}