package org.mobicents.slee.container.deployment.profile;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javax.slee.SLEEException;
import javax.slee.profile.ReadOnlyProfileException;
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.ProfileSpecificationDescriptorImpl;
import org.mobicents.slee.container.deployment.ClassUtils;
import org.mobicents.slee.container.profile.AbstractProfileCmpSlee10Wrapper;
import org.mobicents.slee.container.profile.ProfileObject;
/**
*
* The Profile CMP Slee 1.0 Wrapper is an object that implements the Profile CMP
* Interface, wrapping the SLEE 1.1 real profile concrete object in a SLEE 1.0
* compatible interface. This class generates such objects.
*
* @author martins
*
*/
public class ProfileCmpSlee10WrapperClassGenerator {
private static final Logger logger = Logger.getLogger(ProfileCmpSlee10WrapperClassGenerator.class);
/**
* the component to process
*/
private final ProfileSpecificationComponent component;
/**
*
* @param component
*/
public ProfileCmpSlee10WrapperClassGenerator(ProfileSpecificationComponent component) {
this.component = component;
}
/**
*
* @throws Exception
*/
public void generateClass() throws Exception {
ProfileSpecificationDescriptorImpl descriptor = component.getDescriptor();
ClassPool pool = component.getClassPool();
String profileCmpInterfaceName = descriptor.getProfileCMPInterface().getProfileCmpInterfaceName();
String wrapperClassName = profileCmpInterfaceName + "Slee10Wrapper" ;
CtClass profileCmpInterface = null;
CtClass wrapperClass = null;
try {
profileCmpInterface = pool.get(profileCmpInterfaceName);
wrapperClass = pool.makeClass(wrapperClassName);
wrapperClass.setSuperclass(pool.get(AbstractProfileCmpSlee10Wrapper.class.getName()));
wrapperClass.addInterface(profileCmpInterface);
} catch (Exception e) {
throw new SLEEException(e.getMessage(),e);
}
// implement only methods from profile cmp and management interface that are also on user defined local object interface
Map<String, CtMethod> methodsToImplement = ClassUtils.getInterfaceMethodsFromInterface(profileCmpInterface);
// generate constructor
try {
CtClass[] constructorParameters = new CtClass[] { pool.get(ProfileObject.class.getName()) };
String constructorBody = "{ super($$); }";
CtConstructor constructor = CtNewConstructor.make(constructorParameters, new CtClass[]{}, constructorBody , wrapperClass);
wrapperClass.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(wrapperClass, ctMethod,"(("+profileCmpConcreteClassName+")profileObject.getProfileConcrete())");
}
// generate class file
try {
wrapperClass.writeFile(component.getDeploymentDir().getAbsolutePath());
if (logger.isDebugEnabled()) {
logger.debug("Profile CMP SLEE 1.0 Wrapper Class " + wrapperClassName + " generated in the following path " + component.getDeploymentDir().getAbsolutePath());
}
}
catch (Exception e) {
throw new SLEEException(e.getMessage(), e);
}
finally {
wrapperClass.defrost();
}
// load it and store it in the component
try {
component.setProfileCmpSlee10WrapperClass(component.getClassLoader().loadClass(wrapperClassName));
}
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=
"{ "
+ " try {"
+ returnStatement + interceptorAccess +'.'+ method.getName()+"($$);"
+ " } catch ("+ReadOnlyProfileException.class.getName()+" e) {"
+ " throw new "+UnsupportedOperationException.class.getName()+"(e.getMessage(),e);"
+ " }"
+ "}";
if(logger.isDebugEnabled())
{
logger.debug("Instrumented method, name:"+method.getName()+", with body:\n"+body);
}
newMethod.setBody(body);
// add to concrete class
concreteClass.addMethod(newMethod);
}
}