/* * Copyright 2004,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.bsf.util; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.util.Hashtable; import java.util.Stack; import java.util.Vector; import org.apache.bsf.util.cf.CodeFormatter; /** * A <code>CodeBuffer</code> object is used as a code repository for generated Java code. * It provides buffers which correspond to the various sections of a Java class. * * @author Matthew J. Duftler */ public class CodeBuffer { private StringWriter fieldDeclSW = new StringWriter(), methodDeclSW = new StringWriter(), initializerSW = new StringWriter(), constructorSW = new StringWriter(), serviceMethodSW = new StringWriter(); private PrintWriter fieldDeclPW = new PrintWriter(fieldDeclSW), methodDeclPW = new PrintWriter(methodDeclSW), initializerPW = new PrintWriter(initializerSW), constructorPW = new PrintWriter(constructorSW), serviceMethodPW = new PrintWriter(serviceMethodSW); private Stack symbolTableStack = new Stack(); private Hashtable symbolTable = new Hashtable(), usedSymbolIndices = new Hashtable(); private ObjInfo finalStatementInfo; private CodeBuffer parent; { symbolTableStack.push(symbolTable); } // New stuff... private Vector imports = new Vector(), constructorArguments = new Vector(), constructorExceptions = new Vector(), serviceMethodExceptions = new Vector(), implementsVector = new Vector(); private String packageName = null, className = "Test", serviceMethodName = "exec", extendsName = null; private Class serviceMethodReturnType = void.class; public CodeBuffer() { } public CodeBuffer(CodeBuffer parent) { this.parent = parent; } public void addConstructorArgument(ObjInfo arg) { constructorArguments.addElement(arg); } public void addConstructorException(String exceptionName) { if (!constructorExceptions.contains(exceptionName)) { constructorExceptions.addElement(exceptionName); } } public void addConstructorStatement(String statement) { constructorPW.println(statement); } public void addFieldDeclaration(String statement) { fieldDeclPW.println(statement); } public void addImplements(String importName) { if (!implementsVector.contains(importName)) { implementsVector.addElement(importName); } } public void addImport(String importName) { if (!imports.contains(importName)) { imports.addElement(importName); } } public void addInitializerStatement(String statement) { initializerPW.println(statement); } public void addMethodDeclaration(String statement) { methodDeclPW.println(statement); } public void addServiceMethodException(String exceptionName) { if (!serviceMethodExceptions.contains(exceptionName)) { serviceMethodExceptions.addElement(exceptionName); } } public void addServiceMethodStatement(String statement) { serviceMethodPW.println(statement); } // Used internally by merge(...). private void appendIfNecessary(PrintWriter pw, StringBuffer buf) { if (buf.length() > 0) { pw.print(buf.toString()); } } public String buildNewSymbol(String prefix) { Integer nextNum = getSymbolIndex(prefix); if (nextNum == null) { nextNum = new Integer(0); } int iNextNum = nextNum.intValue(); String symbol = prefix + "_" + iNextNum; while (getSymbol(symbol) != null) { iNextNum++; symbol = prefix + "_" + iNextNum; } putSymbolIndex(prefix, new Integer(iNextNum + 1)); return symbol; } public void clearSymbolTable() { symbolTable = new Hashtable(); symbolTableStack = new Stack(); symbolTableStack.push(symbolTable); usedSymbolIndices = new Hashtable(); } public String getClassName() { return className; } public Vector getConstructorArguments() { return constructorArguments; } public StringBuffer getConstructorBuffer() { constructorPW.flush(); return constructorSW.getBuffer(); } public Vector getConstructorExceptions() { return constructorExceptions; } public String getExtends() { return extendsName; } public StringBuffer getFieldBuffer() { fieldDeclPW.flush(); return fieldDeclSW.getBuffer(); } public ObjInfo getFinalServiceMethodStatement() { return finalStatementInfo; } public Vector getImplements() { return implementsVector; } public Vector getImports() { return imports; } public StringBuffer getInitializerBuffer() { initializerPW.flush(); return initializerSW.getBuffer(); } public StringBuffer getMethodBuffer() { methodDeclPW.flush(); return methodDeclSW.getBuffer(); } public String getPackageName() { return packageName; } public StringBuffer getServiceMethodBuffer() { serviceMethodPW.flush(); return serviceMethodSW.getBuffer(); } public Vector getServiceMethodExceptions() { return serviceMethodExceptions; } public String getServiceMethodName() { return serviceMethodName; } public Class getServiceMethodReturnType() { if (finalStatementInfo != null) { return finalStatementInfo.objClass; } else if (serviceMethodReturnType != null) { return serviceMethodReturnType; } else { return void.class; } } public ObjInfo getSymbol(String symbol) { ObjInfo ret = (ObjInfo)symbolTable.get(symbol); if (ret == null && parent != null) ret = parent.getSymbol(symbol); return ret; } Integer getSymbolIndex(String prefix) { if (parent != null) { return parent.getSymbolIndex(prefix); } else { return (Integer)usedSymbolIndices.get(prefix); } } public Hashtable getSymbolTable() { return symbolTable; } public void merge(CodeBuffer otherCB) { Vector otherImports = otherCB.getImports(); for (int i = 0; i < otherImports.size(); i++) { addImport((String)otherImports.elementAt(i)); } appendIfNecessary(fieldDeclPW, otherCB.getFieldBuffer()); appendIfNecessary(methodDeclPW, otherCB.getMethodBuffer()); appendIfNecessary(initializerPW, otherCB.getInitializerBuffer()); appendIfNecessary(constructorPW, otherCB.getConstructorBuffer()); appendIfNecessary(serviceMethodPW, otherCB.getServiceMethodBuffer()); ObjInfo oldRet = getFinalServiceMethodStatement(); if (oldRet != null && oldRet.isExecutable()) { addServiceMethodStatement(oldRet.objName + ";"); } setFinalServiceMethodStatement(otherCB.getFinalServiceMethodStatement()); } public void popSymbolTable() { symbolTableStack.pop(); symbolTable = (Hashtable)symbolTableStack.peek(); } public void print(PrintWriter out, boolean formatOutput) { if (formatOutput) { new CodeFormatter().formatCode(new StringReader(toString()), out); } else { out.print(toString()); } out.flush(); } public void pushSymbolTable() { symbolTable = (Hashtable)symbolTableStack.push(new ScriptSymbolTable(symbolTable)); } public void putSymbol(String symbol, ObjInfo obj) { symbolTable.put(symbol, obj); } void putSymbolIndex(String prefix, Integer index) { if (parent != null) { parent.putSymbolIndex(prefix, index); } else { usedSymbolIndices.put(prefix, index); } } public void setClassName(String className) { this.className = className; } public void setExtends(String extendsName) { this.extendsName = extendsName; } public void setFinalServiceMethodStatement(ObjInfo finalStatementInfo) { this.finalStatementInfo = finalStatementInfo; } public void setPackageName(String packageName) { this.packageName = packageName; } public void setServiceMethodName(String serviceMethodName) { this.serviceMethodName = serviceMethodName; } public void setServiceMethodReturnType(Class serviceMethodReturnType) { this.serviceMethodReturnType = serviceMethodReturnType; } public void setSymbolTable(Hashtable symbolTable) { this.symbolTable = symbolTable; } public boolean symbolTableIsStacked() { return (symbolTable instanceof ScriptSymbolTable); } public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); ObjInfo ret = finalStatementInfo; if (packageName != null && !packageName.equals("")) { pw.println("package " + packageName + ";"); pw.println(); } if (imports.size() > 0) { for (int i = 0; i < imports.size(); i++) { pw.println("import " + imports.elementAt(i) + ";"); } pw.println(); } pw.println("public class " + className + (extendsName != null && !extendsName.equals("") ? " extends " + extendsName : "") + (implementsVector.size() > 0 ? " implements " + StringUtils.getCommaListFromVector(implementsVector) : "") ); pw.println("{"); pw.print(getFieldBuffer().toString()); StringBuffer buf = getInitializerBuffer(); if (buf.length() > 0) { pw.println(); pw.println("{"); pw.print(buf.toString()); pw.println("}"); } buf = getConstructorBuffer(); if (buf.length() > 0) { pw.println(); pw.println("public " + className + "(" + (constructorArguments.size() > 0 ? StringUtils.getCommaListFromVector(constructorArguments) : "" ) + ")" + (constructorExceptions.size() > 0 ? " throws " + StringUtils.getCommaListFromVector(constructorExceptions) : "" ) ); pw.println("{"); pw.print(buf.toString()); pw.println("}"); } buf = getServiceMethodBuffer(); if (buf.length() > 0 || ret != null) { pw.println(); pw.println("public " + StringUtils.getClassName(getServiceMethodReturnType()) + " " + serviceMethodName + "()" + (serviceMethodExceptions.size() > 0 ? " throws " + StringUtils.getCommaListFromVector(serviceMethodExceptions) : "" ) ); pw.println("{"); pw.print(buf.toString()); if (ret != null) { if (ret.isValueReturning()) { pw.println(); pw.println("return " + ret.objName + ";"); } else if (ret.isExecutable()) { pw.println(ret.objName + ";"); } } pw.println("}"); } pw.print(getMethodBuffer().toString()); pw.println("}"); pw.flush(); return sw.toString(); } }