package org.mobicents.slee.container.deployment.profile; import java.util.HashSet; import java.util.Set; import javassist.CtClass; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.NotFoundException; import javax.slee.InvalidStateException; import javax.slee.SLEEException; import javax.slee.management.DeploymentException; import javax.slee.management.ManagementException; import javax.slee.profile.ProfileImplementationException; 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.profile.AbstractProfileMBean; import org.mobicents.slee.container.profile.AbstractProfileMBeanImpl; public class ConcreteProfileMBeanGenerator { private static final Logger logger = Logger.getLogger(ConcreteProfileMBeanGenerator.class); private ProfileSpecificationComponent component = null; private String cmpProfileInterfaceName = null; private String profileManagementInterfaceName = null; private ClassPool pool = null; private CtClass cmpProfileInterface = null; private CtClass profileManagementInterface = null; private CtClass profileMBeanConcreteClass = null; private CtClass profileMBeanConcreteInterface = null; /** * holds all cmp acessor methods to copy to mbean interface and implement in mbean impl */ private Set<CtMethod> mBeanCmpAcessorMethods = new HashSet<CtMethod>(); /** * holds all management methods to copy to mbean interface and implement in mbean impl */ private Set<CtMethod> mBeanManagementMethods = new HashSet<CtMethod>(); public ConcreteProfileMBeanGenerator(ProfileSpecificationComponent component) { this.component = component; ProfileSpecificationDescriptorImpl descriptor = component.getDescriptor(); this.cmpProfileInterfaceName = descriptor.getProfileClasses().getProfileCMPInterface().getProfileCmpInterfaceName(); this.profileManagementInterfaceName = descriptor.getProfileManagementInterface() == null ? null : descriptor.getProfileManagementInterface().getProfileManagementInterfaceName(); this.pool = component.getClassPool(); } /** * Generates the Profile MBean interface * * @return the interface generated */ public void generateProfileMBeanInterface() throws Exception { if (SleeProfileClassCodeGenerator.checkCombination(component) == -1) { throw new DeploymentException("Profile Specification doesn't match any combination " + "from the JSLEE spec 1.0 section 10.5.2"); } String profileMBeanConcreteInterfaceName = cmpProfileInterfaceName + "MBean"; profileMBeanConcreteInterface = pool.makeInterface(profileMBeanConcreteInterfaceName); try { cmpProfileInterface = pool.get(cmpProfileInterfaceName); profileManagementInterface = profileManagementInterfaceName != null ? pool.get(profileManagementInterfaceName) : null; } catch (NotFoundException nfe) { throw new DeploymentException("Failed to locate CMP/Management Interface for " + component, nfe); } // set interface try { profileMBeanConcreteInterface.addInterface(pool.get(AbstractProfileMBean.class.getName())); } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } // gather exceptions that the mbean methods may throw CtClass[] managementMethodExceptions = new CtClass[3]; try { managementMethodExceptions[0] = pool.get(ManagementException.class.getName()); managementMethodExceptions[1] = pool.get(InvalidStateException.class.getName()); managementMethodExceptions[2] = pool.get(ProfileImplementationException.class.getName()); } catch (NotFoundException e) { throw new SLEEException(e.getMessage(),e); } CtClass[] cmpGetAcessorMethodExceptions = new CtClass[] {managementMethodExceptions[0]}; CtClass[] cmpSetAcessorMethodExceptions = new CtClass[] {managementMethodExceptions[0],managementMethodExceptions[1]}; // gather all Object class methods, we don't want those in the mbean Set<CtMethod> objectMethods = new HashSet<CtMethod>(); try { CtClass objectClass = pool.get(Object.class.getName()); for (CtMethod ctMethod : objectClass.getMethods()) { objectMethods.add(ctMethod); } } catch (NotFoundException e) { throw new SLEEException(e.getMessage(),e); } // gather methods to copy Set<CtMethod> cmpAcessorMethods = new HashSet<CtMethod>(); Set<CtMethod> managementMethods = new HashSet<CtMethod>(); if (profileManagementInterface != null) { // If the Profile Specification defines a Profile Management Interface, the profileMBean interface has the same methods // 1. gather all methods from management interface for (CtMethod ctMethod : profileManagementInterface.getMethods()) { if (!objectMethods.contains(ctMethod)) { managementMethods.add(ctMethod); } } // 2. gather all methods present also in cmp interface, removing those from the ones gather from management interface for (CtMethod ctMethod : cmpProfileInterface.getMethods()) { if (!objectMethods.contains(ctMethod)) { if (managementMethods.remove(ctMethod)) { cmpAcessorMethods.add(ctMethod); } } } } else { for (CtMethod ctMethod : cmpProfileInterface.getMethods()) { if (!objectMethods.contains(ctMethod)) { cmpAcessorMethods.add(ctMethod); } } } // copy cmp acessor & mngt methods for (CtMethod ctMethod : cmpAcessorMethods) { // copy method CtMethod methodCopy = new CtMethod(ctMethod, profileMBeanConcreteInterface, null); // set exceptions CtClass[] exceptions = null; if(ctMethod.getName().startsWith("set")) { exceptions = cmpSetAcessorMethodExceptions; } else if(ctMethod.getName().startsWith("get")) { exceptions = cmpGetAcessorMethodExceptions; } else { throw new DeploymentException("unexpected method in profile cmp interface "+ctMethod); } methodCopy.setExceptionTypes(exceptions); // add to class profileMBeanConcreteInterface.addMethod(methodCopy); // store in set to be used in mbean impl mBeanCmpAcessorMethods.add(methodCopy); } for (CtMethod ctMethod : managementMethods) { // copy method CtMethod methodCopy = new CtMethod(ctMethod, profileMBeanConcreteInterface, null); // set exceptions methodCopy.setExceptionTypes(managementMethodExceptions); // add to class profileMBeanConcreteInterface.addMethod(methodCopy); // store in set to be used in mbean impl mBeanManagementMethods.add(methodCopy); } // write class file try { profileMBeanConcreteInterface.writeFile(this.component.getDeploymentDir().getAbsolutePath()); if (logger.isDebugEnabled()) { logger.debug("Concrete Interface " + cmpProfileInterfaceName + "MBean" + " generated in the following path " + this.component.getDeploymentDir().getAbsolutePath()); } } catch (Throwable e) { throw new SLEEException(e.getMessage(), e); } finally { profileMBeanConcreteInterface.defrost(); } // and load it to the component try { this.component.setProfileMBeanConcreteInterfaceClass(Thread.currentThread().getContextClassLoader().loadClass(profileMBeanConcreteInterfaceName)); } catch (Throwable e) { throw new SLEEException(e.getMessage(), e); } } /** * This method generates concrete class of MBean impl */ public void generateProfileMBean() throws Exception { if (SleeProfileClassCodeGenerator.checkCombination(component) == -1) { throw new DeploymentException("Profile Specification doesn't match any combination " + "from the JSLEE spec 1.0 section 10.5.2"); } String profileMBeanConcreteClassName = profileMBeanConcreteInterface.getName() + "Impl"; profileMBeanConcreteClass = pool.makeClass(profileMBeanConcreteClassName); // set interface & super class try { profileMBeanConcreteClass.setInterfaces(new CtClass[] {profileMBeanConcreteInterface}); profileMBeanConcreteClass.setSuperclass(pool.get(AbstractProfileMBeanImpl.class.getName())); } catch (NotFoundException e) { throw new SLEEException(e.getMessage(),e); } // implement cmp acessor & management methods gather in the mbean interface building for (CtMethod method : mBeanCmpAcessorMethods) { // copy method & remove abstract modifier CtMethod newMethod = CtNewMethod.copy( method, profileMBeanConcreteClass, null ); // generate body String body = null; if (method.getName().startsWith("set")) { body = "{ " + " beforeSetCmpField();" + " try { " + " (("+component.getProfileCmpConcreteClass().getName()+")getProfileObject().getProfileConcrete())." + method.getName()+"($1);" + " } finally {" + " afterSetCmpField();" + " }" + "}"; } else { body = "{ " + " boolean activatedTransaction = beforeGetCmpField();" + " try { " + " return ($r) (("+component.getProfileCmpConcreteClass().getName()+")getProfileObject().getProfileConcrete())." + method.getName()+"();" + " } finally {" + " afterGetCmpField(activatedTransaction);" + " }" + "}"; } if(logger.isDebugEnabled()) { logger.debug("Implemented profile mbean method named "+method.getName()+", with body:\n"+body); } newMethod.setBody(body); profileMBeanConcreteClass.addMethod(newMethod); } for (CtMethod method : mBeanManagementMethods) { // copy method & remove abstract modifier CtMethod newMethod = CtNewMethod.copy( method, profileMBeanConcreteClass, null ); // generate body boolean voidReturnType = newMethod.getReturnType().equals(CtClass.voidType); String body = "{ boolean activatedTransaction = beforeManagementMethodInvocation(); try { "; if (!voidReturnType) { body += "return ($r) "; } body += "(("+component.getProfileCmpConcreteClass().getName()+")getProfileObject().getProfileConcrete())." + method.getName()+"($$); } catch(Throwable t) { throwableOnManagementMethodInvocation(t); } finally { afterManagementMethodInvocation(activatedTransaction); }"; if (!voidReturnType) { body += "throw new "+SLEEException.class.getName()+"(\"bad code generated\");"; } body += " }"; if(logger.isDebugEnabled()) { logger.debug("Implemented profile mbean method named "+method.getName()+", with body:\n"+body); } newMethod.setBody(body); profileMBeanConcreteClass.addMethod(newMethod); } try { profileMBeanConcreteClass.writeFile(this.component.getDeploymentDir().getAbsolutePath()); if (logger.isDebugEnabled()) { logger.debug("Concrete Class " + profileMBeanConcreteClassName + " generated in the following path " + this.component.getDeploymentDir().getAbsolutePath()); } } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } finally { profileMBeanConcreteClass.defrost(); } try { component.setProfileMBeanConcreteImplClass(Thread.currentThread().getContextClassLoader().loadClass(profileMBeanConcreteClassName)); } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } } }