/* * ConcreteUsageParameterClassGenerator.java * * Created on Jan 9, 2005 * * Created by: M. Ranganathan * * The Mobicents Open SLEE project * * A SLEE for the people! * * The source code contained in this file is in in the public domain. * It can be used in any project or product without prior permission, * license or royalty payments. There is NO WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, * THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * AND DATA ACCURACY. We do not warrant or make any representations * regarding the use of the software or the results thereof, including * but not limited to the correctness, accuracy, reliability or * usefulness of the software. */ package org.mobicents.slee.container.deployment; import java.beans.Introspector; import java.util.HashSet; import java.util.Iterator; import javassist.CannotCompileException; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import javassist.CtNewMethod; import javassist.Modifier; import javax.slee.usage.SampleStatistics; import org.apache.log4j.Logger; import org.mobicents.slee.container.component.deployment.ClassPool; import org.mobicents.slee.container.management.jmx.InstalledUsageParameterSet; import org.mobicents.slee.container.management.jmx.UsageMBeanImpl; /** * @author M.Ranganathan * @author martins * */ public class ConcreteUsageParameterClassGenerator { private static Logger logger = Logger.getLogger(ConcreteUsageParameterClassGenerator.class); private static final String NAME_FIELD = "name"; public static final String SET_NAME = "setName"; public static final String GET_NAME = "getName"; private static final String USAGE_PARAMETER_MBEAN_FIELD = "usageMBean"; public static final String SET_USAGE_PARAMETER_MBEAN = "setUsageMBean"; public static final String GET_USAGE_PARAMETER_MBEAN = "getUsageMBean"; private final ClassPool classPool; private final String usageParameterInterfaceName; private final String deploymentDir; private final HashSet<String> generatedFields = new HashSet<String>(); public ConcreteUsageParameterClassGenerator(String usageParameterInterfaceName, String deploymentDir, ClassPool classPool) { this.usageParameterInterfaceName = usageParameterInterfaceName; this.deploymentDir = deploymentDir; this.classPool = classPool; } public Class<?> generateConcreteUsageParameterClass() throws Exception { CtClass usageParamInterface = classPool.get(usageParameterInterfaceName); String concreteClassName = usageParameterInterfaceName + "Impl"; CtClass implClassInterface = classPool.get(InstalledUsageParameterSet.class.getName()); CtMethod[] methods = usageParamInterface.getMethods(); CtClass ctClass = classPool.makeClass(concreteClassName); try { //Generates the implements link ConcreteClassGeneratorUtils.createInterfaceLinks(ctClass, new CtClass[] { usageParamInterface, implClassInterface }); // generate the "usage mbean" field, getter and setter CtField ctField = new CtField(classPool.get(UsageMBeanImpl.class .getName()), USAGE_PARAMETER_MBEAN_FIELD, ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); generateUsageMBeanSetter(ctClass); generateUsageMBeanGetter(ctClass); // generate the "name" field, getter and setter ctField = new CtField(classPool.get(String.class.getName()), NAME_FIELD, ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); generateNameSetter(ctClass); generateNameGetter(ctClass); // generate concrete methods for each usage param for (int i = 0; i < methods.length; i++) { generateConcreteMethod(ctClass, methods[i]); } // generate reset method generateResetMethod(ctClass); // generate constructor createDefaultConstructor(ctClass); // write file ctClass.writeFile(deploymentDir); if (logger.isDebugEnabled()) logger.debug("UsageParameterGenerator Writing file " + concreteClassName); Class<?> retval = Thread.currentThread().getContextClassLoader() .loadClass(concreteClassName); return retval; } finally { ctClass.defrost(); } } private void generateUsageMBeanSetter(CtClass concreteClass) throws Exception { String body = "public void " + SET_USAGE_PARAMETER_MBEAN + " ( " + UsageMBeanImpl.class.getName() + " usageMbean ) { this." + USAGE_PARAMETER_MBEAN_FIELD + "= usageMbean; }"; CtMethod ctMethod = CtNewMethod.make(body, concreteClass); concreteClass.addMethod(ctMethod); } private void generateUsageMBeanGetter(CtClass concreteClass) throws Exception { String body = "public " + UsageMBeanImpl.class.getName() + " " + GET_USAGE_PARAMETER_MBEAN + "() {"; body += "return " + USAGE_PARAMETER_MBEAN_FIELD + "; }"; CtMethod ctMethod = CtNewMethod.make(body, concreteClass); concreteClass.addMethod(ctMethod); } private void generateNameGetter(CtClass concreteClass) throws Exception { String body = "public " + String.class.getName() + " getName() { return " + NAME_FIELD + "; } "; CtMethod ctMethod = CtNewMethod.make(body, concreteClass); concreteClass.addMethod(ctMethod); } private void generateNameSetter(CtClass concreteClass) throws Exception { String body = "public void " + SET_NAME + "( " + java.lang.String.class.getName() + " n) { " + NAME_FIELD + " = n ; } "; CtMethod ctMethod = CtNewMethod.make(body, concreteClass); concreteClass.addMethod(ctMethod); } private void createDefaultConstructor(CtClass concreteClass) { CtConstructor defaultConstructor = new CtConstructor(null, concreteClass); String constructorBody = "{ this.reset(); }"; try { defaultConstructor.setBody(constructorBody); concreteClass.addConstructor(defaultConstructor); logger.debug("DefaultConstructor created"); } catch (CannotCompileException e) { //Auto-generated catch block e.printStackTrace(); } } /** * Reset the usage parameters. */ private void generateResetMethod(CtClass ctClass) throws Exception { String body = "public synchronized void reset() {"; for (Iterator<String> it = this.generatedFields.iterator(); it.hasNext();) { String generatedField = (String) it.next(); if ( generatedField.endsWith("Max")) { body += generatedField + " = Long.MIN_VALUE ; "; } else if ( generatedField.endsWith("Min")) { body += generatedField + " = Long.MAX_VALUE ; "; } else body += generatedField + " = 0; "; } body += "}"; if ( logger.isDebugEnabled()) { logger.debug("generateResetMethod(): body = " + body); } CtMethod newMethod = CtNewMethod.make(body, ctClass); ctClass.addMethod(newMethod); } /** * @param method * @return */ private void generateConcreteMethod(CtClass ctClass, CtMethod method) throws Exception { /* * The SLEE derives the usage parameter type associated with this usage * parameter name from the method name of the declared method.The SBB * Developer declares an increment method to declare the presence of and * to permit updates to a counter-type usage parameter. The method name * of the increment method is derived by adding an �increment� prefix to * the usage parameter name. ( See chapter 11.2.1 ). */ String methodName = method.getName(); String paramName = null; if (methodName.startsWith("increment")) { paramName = Introspector.decapitalize(methodName.substring("increment".length())); CtField ctField = new CtField(CtClass.longType, paramName + "Value", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Value"); ctField = new CtField(CtClass.longType, paramName + "Sum", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Sum"); ctField = new CtField(CtClass.longType, paramName + "Count", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Count"); } else if (methodName.startsWith("sample")) { /* * Sample-type usage parameters. The SBB can add sample values to a * sample -type usage parameter. The Adminstrator can get the * minimum, maximum, mean, and number of the sample values added to * a sample -type usage parameter and reset the state of the usage * parameter through the SLEE�s management interface. */ paramName = Introspector.decapitalize(methodName.substring("sample".length())); CtField ctField = new CtField(CtClass.longType, paramName + "Value", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Value"); ctField = new CtField(CtClass.doubleType, paramName + "Mean", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Mean"); ctField = new CtField(CtClass.longType, paramName + "Min", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Min"); ctField = new CtField(CtClass.longType, paramName + "Max", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Max"); ctField = new CtField(CtClass.longType, paramName + "Count", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Count"); ctField = new CtField(CtClass.doubleType, paramName + "Sum", ctClass); ctField.setModifiers(Modifier.PRIVATE); ctClass.addField(ctField); this.generatedFields.add(paramName + "Sum"); } else return; // TODO -- should I throw exception here ? if ( logger.isDebugEnabled() ) logger.debug("generateConcreteMethod(): USAGEPARAM variable is " + paramName); if (logger.isDebugEnabled()) logger.debug("Generating usage method = " + methodName); String body = ""; String getterBody = ""; String getter11Body = ""; if (methodName.startsWith("increment")) { body += "public synchronized void " + methodName + "( long longValue ) { "; // code for notification propagation here. body += "this." + paramName + "Count += longValue;"; body += "this." + paramName + "Sum += longValue;"; body += "this." + paramName + "Value = longValue;"; // sendUsageNotification (long value, long seqno, String // usageParameterSetName, String usageParameterName, boolean // isCounter) body += "this." + USAGE_PARAMETER_MBEAN_FIELD + ".sendUsageNotification(" + "this." + paramName + "Sum, " + "this." + paramName + "Count, " + "this." + NAME_FIELD + "," + "\"" + paramName + "\"" + "," + Boolean.TRUE.toString() + ");"; body += "}"; getterBody += "public synchronized long get" + methodName.substring("increment".length()) + "( boolean reset) { "; getterBody += "long tempCount = this." + paramName + "Count;"; getterBody += "if (reset == true) {this." + paramName + "Count=0;"; getterBody += "this." + paramName + "Sum = 0;"; getterBody += "this." + paramName + "Value = 0;}"; //getterBody += "this." + paramName + "Min = Long.MAX_VALUE ;"; //getterBody += "this." + paramName + "Max = Long.MIN_VALUE ;}"; getterBody += "return tempCount;"; getterBody += "}"; getter11Body += "public long get" + methodName.substring("increment".length()) + "() { return get" + methodName.substring("increment".length())+ "(false); }"; } else if (methodName.startsWith("sample")) { /* * Sample-type usage parameters. The SBB can add sample values to a * sample -type usage parameter. The Adminstrator can get the * minimum, maximum, mean, and number of the sample values added to * a sample -type usage parameter and reset the state of the usage * parameter through the SLEE�s management interface. */ body += "public synchronized void " + methodName + "( long longValue ) { "; body += "this." + paramName + "Sum += longValue;"; body += "this." + paramName + "Mean = this." + paramName + "Sum / (this." + paramName + "Count+1);"; body += " if ( this." + paramName + "Max < longValue ) this." + paramName + "Max = longValue;"; body += " if ( this." + paramName + "Min > longValue ) this." + paramName + "Min = longValue;"; body += "this." + paramName + "Count++;"; // sendUsageNotification (long value, long seqno, String // usageParameterSetName, String usageParameterName, boolean // isCounter) body += "this." + USAGE_PARAMETER_MBEAN_FIELD + ".sendUsageNotification( longValue, " + "this." + paramName + "Count, " + "this." + NAME_FIELD + "," + "\"" + paramName + "\"" + "," + Boolean.FALSE.toString() + ");"; body += "}"; getterBody += "public synchronized " + SampleStatistics.class.getName() + " get" + methodName.substring("sample".length()) + "( boolean reset) { "; getterBody += SampleStatistics.class.getName() + " tempValue" + "= new " + SampleStatistics.class.getName() + "(this." + paramName + "Count, " + "this." + paramName + "Min, " + "this." + paramName + "Max, " + "this." + paramName + "Mean);"; getterBody += "if (reset == true) {this." + paramName + "Count=0;"; getterBody += "this." + paramName + "Sum = 0;"; getterBody += "this." + paramName + "Mean = 0;"; getterBody += "this." + paramName + "Value = 0;"; getterBody += "this." + paramName + "Min = Long.MAX_VALUE ;"; getterBody += "this." + paramName + "Max = Long.MIN_VALUE ;}"; getterBody += "return tempValue;"; getterBody += "}"; getter11Body += "public " + SampleStatistics.class.getName() + " get" + methodName.substring("sample".length()) + "() { return get" + methodName.substring("sample".length())+ "(false); }"; } else { return; } if (logger.isDebugEnabled()) { logger.debug("Adding SLEE 1.0 usage param getter with source "+getterBody); } CtMethod getterMethod = CtNewMethod.make(getterBody, ctClass); ctClass.addMethod(getterMethod); if (logger.isDebugEnabled()) { logger.debug("Adding SLEE 1.1 usage param getter with source "+getter11Body); } CtMethod getter11Method = CtNewMethod.make(getter11Body, ctClass); ctClass.addMethod(getter11Method); if (logger.isDebugEnabled()) { logger.debug("Adding usage param setter with source "+body); } CtMethod setterMethod = CtNewMethod.make(body, ctClass); ctClass.addMethod(setterMethod); } }