/*************************************************** * * * Mobicents: The Open Source JSLEE Platform * * * * Distributable under LGPL license. * * See terms of license at gnu.org. * * * ***************************************************/ /* * ConcreteActivityContextInterfaceGenerator.java * * Created on Aug 17, 2004 * */ package org.mobicents.slee.container.deployment; import java.util.Iterator; import java.util.Map; import javassist.CannotCompileException; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.NotFoundException; import javax.slee.SLEEException; import javax.slee.management.DeploymentException; import org.apache.log4j.Logger; import org.mobicents.slee.container.component.SbbComponent; import org.mobicents.slee.container.component.deployment.ClassPool; import org.mobicents.slee.runtime.activity.ActivityContextInterfaceImpl; import org.mobicents.slee.runtime.activity.SbbActivityContextInterfaceImpl; /** * Class generating the concrete activity context interface class from the * activity context interface provided by a sbb developer * * @author DERUELLE Jean <a * href="mailto:jean.deruelle@gmail.com">jean.deruelle@gmail.com </a> * @author F.Moggia fixed activitycontext */ public class ConcreteActivityContextInterfaceGenerator { /** * Logger to logg information */ private static Logger logger = null; /** * Pool to generate or read classes with javassist */ private final ClassPool pool; /** * The path where classes will reside */ private final String deployDir; /** * the sbb activity context interface name */ private final String activityContextInterfaceName; /** * The interface from which to generate the concrete interface */ protected CtClass activityContextInterface = null; /** * The the concrete activity interface */ protected CtClass concreteActivityContextInterface = null; static { logger = Logger .getLogger(ConcreteActivityContextInterfaceGenerator.class); } /** * */ public ConcreteActivityContextInterfaceGenerator( String activityContextInterfaceName, String deployDir, ClassPool classPool) { this.pool = classPool; this.deployDir = deployDir; this.activityContextInterfaceName = activityContextInterfaceName; } /** * Generate the Activity Context Interface Class * * @param activityContextInterfaceName * the name of the Activity Context Interface * @return the concrete Activity Context Interface class implementing the * Activity Context Interface */ public Class generateActivityContextInterfaceConcreteClass() throws DeploymentException { String tmpClassName = ConcreteClassGeneratorUtils.CONCRETE_ACTIVITY_INTERFACE_CLASS_NAME_PREFIX + activityContextInterfaceName + ConcreteClassGeneratorUtils.CONCRETE_ACTIVITY_INTERFACE_CLASS_NAME_SUFFIX; concreteActivityContextInterface = pool.makeClass(tmpClassName); CtClass sbbActivityContextInterface = null; try { activityContextInterface = pool.get(activityContextInterfaceName); sbbActivityContextInterface = pool .get(SbbActivityContextInterfaceImpl.class.getName()); } catch (NotFoundException nfe) { throw new DeploymentException("Could not find aci " + activityContextInterfaceName, nfe); } // Generates the extends link ConcreteClassGeneratorUtils.createInheritanceLink( concreteActivityContextInterface, sbbActivityContextInterface); // Generates the implements link ConcreteClassGeneratorUtils.createInterfaceLinks( concreteActivityContextInterface, new CtClass[] { activityContextInterface }); // Creates the constructor with parameters try { CtClass[] parameters = new CtClass[] { pool.get(ActivityContextInterfaceImpl.class.getName()), pool.get(SbbComponent.class.getName()) }; createConstructorWithParameter(parameters); } catch (NotFoundException nfe) { logger .error("Could not find class. Constructor With Parameter not created"); throw new DeploymentException( "Could not find class. Constructor With Parameter not created", nfe); } // Generates the methods to implement from the interface Map interfaceMethods = ClassUtils .getInterfaceMethodsFromInterface(activityContextInterface); generateConcreteMethods(interfaceMethods); // generates the class String sbbDeploymentPathStr = deployDir; try { concreteActivityContextInterface.writeFile(sbbDeploymentPathStr); if (logger.isDebugEnabled()) { logger.debug("Concrete Class " + tmpClassName + " generated in the following path " + sbbDeploymentPathStr); } } catch (Exception e) { logger.error("problem generating concrete class", e); throw new DeploymentException( "problem generating concrete class! ", e); } // load the class Class clazz = null; try { clazz = Thread.currentThread().getContextClassLoader().loadClass( tmpClassName); } catch (Exception e1) { logger.error("problem loading generated class", e1); throw new DeploymentException( "problem loading the generated class! ", e1); } this.concreteActivityContextInterface.defrost(); return clazz; } private boolean isBaseInterfaceMethod(String methodName) { if ("getActivity".equals(methodName) || "attach".equals(methodName) || "detach".equals(methodName) || "isEnding".equals(methodName) || "isAttached".equals(methodName) || "equals".equals(methodName) || "hashCode".equals(methodName)) { return true; } else { return false; } } /** * Generates the concrete methods of the class It generates a specific * method implementation for the javax.slee.ActivityContextInterface methods * for the methods coming from the ActivityContextInterface developer the * call is routed to the base asbtract class * * @param interfaceMethods * the methods to implement coming from the * ActivityContextInterface developer */ private void generateConcreteMethods(Map interfaceMethods) { if (interfaceMethods == null) return; Iterator it = interfaceMethods.values().iterator(); while (it.hasNext()) { CtMethod interfaceMethod = (CtMethod) it.next(); if (interfaceMethod != null && isBaseInterfaceMethod(interfaceMethod.getName())) continue; // @todo: need to check args also try { // copy method from abstract to concrete class CtMethod concreteMethod = CtNewMethod.copy(interfaceMethod, concreteActivityContextInterface, null); // create the method body String fieldName = interfaceMethod.getName().substring(3); fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1); String concreteMethodBody = null; if (interfaceMethod.getName().startsWith("get")) { concreteMethodBody = "{ return ($r)getFieldValue(\"" + fieldName + "\","+concreteMethod.getReturnType().getName()+".class); }"; } else if (interfaceMethod.getName().startsWith("set")) { concreteMethodBody = "{ setFieldValue(\"" + fieldName + "\",$1); }"; } else { throw new SLEEException("unexpected method name <" + interfaceMethod.getName() + "> to implement in sbb aci interface"); } if (logger.isDebugEnabled()) { logger.debug("Generated method " + interfaceMethod.getName() + " , body = " + concreteMethodBody); } concreteMethod.setBody(concreteMethodBody); concreteActivityContextInterface.addMethod(concreteMethod); } catch (Exception cce) { throw new SLEEException("Cannot compile method " + interfaceMethod.getName(), cce); } } } /** * Creates a constructor with parameters <BR> * For every parameter a field of the same class is created in the concrete * class And each field is gonna be initialized with the corresponding * parameter * * @param parameters * the parameters of the constructor to add */ protected void createConstructorWithParameter(CtClass[] parameters) { CtConstructor constructorWithParameter = new CtConstructor(parameters, concreteActivityContextInterface); String constructorBody = "{ super($1,$2); }"; try { concreteActivityContextInterface .addConstructor(constructorWithParameter); constructorWithParameter.setBody(constructorBody); if (logger.isDebugEnabled()) { logger.debug("ConstructorWithParameter created"); } } catch (CannotCompileException e) { logger.error(e); } } }