Coverage Report - org.webslinger.bsf.janino.AbstractJaninoCompiler
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractJaninoCompiler
86%
150/175
100%
24/24
0
AbstractJaninoCompiler$1
20%
1/5
0%
0/2
0
AbstractJaninoCompiler$Init
N/A
N/A
0
AbstractJaninoCompiler$JaninoCompilerContext
83%
5/6
100%
1/1
0
 
 1  
 package org.webslinger.bsf.janino;
 2  
 
 3  
 import java.io.IOException;
 4  
 import java.io.StringReader;
 5  
 import java.io.StringWriter;
 6  
 import java.util.ArrayList;
 7  
 import java.util.HashMap;
 8  
 import java.util.Iterator;
 9  
 import java.util.List;
 10  
 
 11  
 import org.apache.bsf.BSFDeclaredBean;
 12  
 import org.apache.bsf.BSFException;
 13  
 import org.apache.bsf.util.BSFFunctions;
 14  
 
 15  
 import org.codehaus.janino.ByteArrayClassLoader;
 16  
 import org.codehaus.janino.ClassLoaderIClassLoader;
 17  
 import org.codehaus.janino.CompileException;
 18  
 import org.codehaus.janino.DebuggingInformation;
 19  
 import org.codehaus.janino.Java;
 20  
 import org.codehaus.janino.Location;
 21  
 import org.codehaus.janino.Mod;
 22  
 import org.codehaus.janino.Parser;
 23  
 import org.codehaus.janino.Scanner;
 24  
 import org.codehaus.janino.UnitCompiler;
 25  
 import org.codehaus.janino.UnparseVisitor;
 26  
 import org.codehaus.janino.util.ClassFile;
 27  
 import org.codehaus.janino.util.enumerator.EnumeratorSet;
 28  
 
 29  
 import org.webslinger.bsf.ApplyKey;
 30  
 import org.webslinger.bsf.Compiler;
 31  
 import org.webslinger.bsf.EvalKey;
 32  
 import org.webslinger.bsf.ExecKey;
 33  
 import org.webslinger.bsf.LanguageEngine;
 34  
 import org.webslinger.bsf.Key;
 35  
 import org.webslinger.util.GeneratedResult;
 36  
 
 37  780
 public abstract class AbstractJaninoCompiler<V extends Object, C extends Class<V>> extends Compiler<V, C> {
 38  
     protected interface Init {
 39  
         void init(LanguageEngine engine, Object[] beans);
 40  
     }
 41  
 
 42  
     protected String removeStart(String text, StringBuilder imports, StringBuilder staticDefs) throws IOException, Scanner.LocatedException {
 43  70
         Scanner textScanner = new Scanner(null, new StringReader(text));
 44  70
         textScanner.setSwallow(false);
 45  70
         StringWriter importWriter = new StringWriter();
 46  70
         StringWriter staticWriter = new StringWriter();
 47  70
         StringWriter writer = importWriter;
 48  70
         Parser textParser = new Parser(textScanner);
 49  
         do {
 50  1190
             Scanner.Token token = textScanner.peek();
 51  1190
             if (token.isComment()) {
 52  0
                 textScanner.read();
 53  1190
             } else if (token.isWhitespace()) {
 54  560
                 textScanner.read();
 55  630
             } else if (writer == importWriter && token.isKeyword("import")) {
 56  538
                 textScanner.setSwallow(true);
 57  538
                 textParser.parseImportDeclaration();
 58  538
                 textScanner.setSwallow(false);
 59  92
             } else if (token.isKeyword("static")) {
 60  22
                 writer = staticWriter;
 61  22
                 textScanner.read();
 62  22
                 token = textScanner.peek();
 63  22
                 textScanner.setSwallow(true);
 64  22
                 short mod = (short) (Mod.STATIC | textParser.parseModifiersOpt());
 65  22
                 if (textParser.peekOperator("{")) {
 66  0
                     textScanner.read();
 67  0
                     textParser.parseBlock();
 68  22
                 } else if (textParser.peekKeyword("class")) {
 69  12
                     textScanner.read();
 70  12
                     textParser.parseClassDeclarationRest(
 71  
                         null,
 72  
                         mod,
 73  
                         Parser.ClassDeclarationContext.TYPE_DECLARATION
 74  
                     );
 75  10
                 } else if (textParser.peekKeyword("interface")) {
 76  0
                     textScanner.read();
 77  0
                     textParser.parseInterfaceDeclarationRest(
 78  
                         null,
 79  
                         mod,
 80  
                         Parser.InterfaceDeclarationContext.NAMED_TYPE_DECLARATION
 81  
                     );
 82  10
                 } else if (textParser.peekKeyword("void")) {
 83  0
                     textScanner.read();
 84  0
                     Location location = textParser.location();
 85  0
                     String name = textParser.readIdentifier();
 86  0
                     textParser.parseMethodDeclarationRest(
 87  
                         null,
 88  
                         mod,
 89  
                         new Java.BasicType(location, Java.BasicType.VOID),
 90  
                         name
 91  
                     );
 92  0
                 } else {
 93  10
                     Java.Type type = textParser.parseType();
 94  10
                     Location location = textParser.location();
 95  10
                     String name = textParser.readIdentifier();
 96  10
                     if (textParser.peekOperator("(")) {
 97  5
                         textParser.parseMethodDeclarationRest(
 98  
                             null,
 99  
                             mod,
 100  
                             type,
 101  
                             name
 102  
                         );
 103  
                     } else {
 104  5
                         new Java.FieldDeclaration(
 105  
                             location,
 106  
                             null,
 107  
                             mod,
 108  
                             type,
 109  
                             textParser.parseFieldDeclarationRest(name)
 110  
                         );
 111  5
                         textParser.readOperator(";");
 112  
                     }
 113  
                 }
 114  22
                 textScanner.setSwallow(false);
 115  
             } else {
 116  
                 break;
 117  
             }
 118  1120
             writer.write(token.toString());
 119  8960
             while (token.getNextToken() != null) {
 120  8960
                 token = token.getNextToken();
 121  8960
                 if (token.getNextToken() == null) break;
 122  7840
                 writer.write(token.toString());
 123  
             }
 124  1120
         } while (true);
 125  70
         imports.append(importWriter.getBuffer());
 126  70
         staticDefs.append(staticWriter.getBuffer());
 127  70
         textScanner.setSwallow(false);
 128  70
         StringBuilder newText = new StringBuilder();
 129  48612
         while (!textScanner.peek().isEOF()) {
 130  48542
             Scanner.Token token = textScanner.read();
 131  
             //System.err.println("token=" + token);
 132  48542
             String tokenText = token.toString();
 133  48542
             newText.append(tokenText);
 134  48542
         }
 135  70
         return newText.toString();
 136  
     }
 137  
 
 138  46
     protected final HashMap<Class, Class> implementsMap = new HashMap<Class, Class>();
 139  
 
 140  
     public class JaninoCompilerContext extends CompilerContext {
 141  
         protected String imports;
 142  
         protected String staticDefs;
 143  
         protected Object[] beanObjects;
 144  260
         protected JaninoCompilerContext(Key<C> key) throws BSFException {
 145  260
             super(key);
 146  260
             beanObjects = new Object[beans.length];
 147  260
             for (int i = 0; i < beans.length; i++) {
 148  0
                 beanObjects[i] = beans[i].bean;
 149  
             }
 150  260
         }
 151  
     }
 152  
 
 153  
     public AbstractJaninoCompiler(LanguageEngine engine) {
 154  46
         super(engine);
 155  46
     }
 156  
 
 157  
     protected String filter(CompilerContext context, String text) throws BSFException {
 158  260
         return filter((JaninoCompilerContext) context, text);
 159  
     }
 160  
 
 161  
     protected String filter(JaninoCompilerContext context, String text) throws BSFException {
 162  260
         StringBuilder imports = new StringBuilder();
 163  260
         StringBuilder staticDefs = new StringBuilder();
 164  
         try {
 165  260
             return removeStart(text, imports, staticDefs);
 166  0
         } catch (IOException e) {
 167  0
             throw (BSFException) new BSFException(BSFException.REASON_IO_ERROR, e.getMessage(), e).initCause(e);
 168  0
         } catch (Scanner.LocatedException e) {
 169  0
             throw (BSFException) new BSFException(BSFException.REASON_IO_ERROR, e.getMessage(), e).initCause(e);
 170  
         } finally {
 171  260
             context.imports = imports.toString();
 172  260
             context.staticDefs = staticDefs.toString();
 173  
         }
 174  
     }
 175  
 
 176  
     public void declareBean(BSFDeclaredBean bean) throws BSFException {
 177  967
         clear();
 178  967
     }
 179  
 
 180  
     public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
 181  0
         clear();
 182  0
     }
 183  
 
 184  
     // called under synchronized (beans)
 185  
     protected C compile(CompilerContext context) throws Throwable {
 186  260
         return compile((JaninoCompilerContext) context);
 187  
     }
 188  
 
 189  
     protected CompilerContext newContext(Key<C> key) throws BSFException {
 190  260
         return new JaninoCompilerContext(key);
 191  
     }
 192  
 
 193  
     protected static void addImplementsToCode(StringBuilder code, List<String> implementsList) {
 194  330
         if (!implementsList.isEmpty()) {
 195  140
             Iterator<String> it = implementsList.iterator();
 196  140
             code.append(" implements");
 197  280
             while (it.hasNext()) {
 198  140
                 String interfaceName = it.next();
 199  140
                 code.append(' ').append(interfaceName);
 200  140
                 if (it.hasNext()) code.append(',');
 201  140
             }
 202  
         }
 203  330
     }
 204  
 
 205  
     protected void addHelperImplements(JaninoCompilerContext context, List<String> implementsList) {
 206  70
         implementsList.add(Init.class.getName());
 207  70
     }
 208  
 
 209  
     protected void compileHelperVariables(JaninoCompilerContext context, StringBuilder code, String className) {
 210  70
     }
 211  
 
 212  
     protected void compileHelperMethods(JaninoCompilerContext context, StringBuilder code, String className) {
 213  70
         code.append("public final void init(").append(LanguageEngine.class.getName()).append(" engine, Object[] beans) {");
 214  70
         code.append(className).append(".bsf = engine.getBSFFunctions();");
 215  70
         for (int i = 0; i < context.beans.length; i++) {
 216  0
             BSFDeclaredBean bean = context.beans[i];
 217  0
             code.append(className).append('.').append(bean.name).append(" = (").append(bean.type.getName()).append(") beans[").append(i).append("];");
 218  
         }
 219  70
         code.append('}');
 220  70
     }
 221  
 
 222  
     protected void compileHelper(JaninoCompilerContext context, StringBuilder code, String className) {
 223  70
         List<String> implementsList = new ArrayList<String>();
 224  70
         addHelperImplements(context, implementsList);
 225  70
         code.append("public final class ").append(className).append("Init");
 226  70
         addImplementsToCode(code, implementsList);
 227  70
         code.append(" {");
 228  70
         compileHelperVariables(context, code, className);
 229  70
         compileHelperMethods(context, code, className);
 230  70
         code.append('}');
 231  70
     }
 232  
 
 233  
     protected void addClassImplements(JaninoCompilerContext context, List<String> implementsList) {
 234  260
         Class keyImplements = implementsMap.get(context.key.getClass());
 235  260
         if (keyImplements != null) implementsList.add(keyImplements.getName());
 236  260
     }
 237  
 
 238  
     protected void compileClassVariables(JaninoCompilerContext context, StringBuilder code, String className) {
 239  70
         code.append("static ").append(BSFFunctions.class.getName()).append(" bsf;");
 240  70
         for (BSFDeclaredBean bean: context.beans) {
 241  0
             code.append("static ").append(bean.type.getName()).append(' ').append(bean.name).append(';');
 242  
         }
 243  70
     }
 244  
 
 245  
     protected void compileClassMethods(JaninoCompilerContext context, StringBuilder code, String className) throws Throwable {
 246  260
         super.compile(context);
 247  260
     }
 248  
 
 249  
     protected void addExtends(JaninoCompilerContext context, StringBuilder code) {
 250  70
     }
 251  
 
 252  
     protected void compileConstructors(JaninoCompilerContext context, StringBuilder code, String className) {
 253  70
     }
 254  
 
 255  
     protected void compileClass(JaninoCompilerContext context, StringBuilder code, String className) throws Throwable {
 256  260
         List<String> implementsList = new ArrayList<String>();
 257  260
         addClassImplements(context, implementsList);
 258  260
         code.append("public class ").append(className);
 259  260
         addExtends(context, code);
 260  260
         addImplementsToCode(code, implementsList);
 261  260
         code.append(" {");
 262  260
         compileClassVariables(context, code, className);
 263  260
         compileConstructors(context, code, className);
 264  260
         code.append(context.staticDefs);
 265  260
         compileClassMethods(context, code, className);
 266  260
         code.append('}');
 267  260
     }
 268  
 
 269  
     protected C compile(JaninoCompilerContext context) throws Throwable {
 270  260
         String fileName = engine.getVFSDelegate().absolutePath(context.key.getId());
 271  260
         StringBuilder packageNameBuffer = new StringBuilder();
 272  260
         StringBuilder classNameBuffer = new StringBuilder();
 273  260
         nameEncoder.makePackageClassName(packageNameBuffer, classNameBuffer, fileName);
 274  
 
 275  260
         ClassLoaderIClassLoader classLoaderIClassLoader = new ClassLoaderIClassLoader(context.key.getParentClassLoader(engine));
 276  
 
 277  260
         StringBuilder code = context.code;
 278  260
         if (packageNameBuffer.length() > 0) code.append("package ").append(packageNameBuffer).append(';');
 279  260
         code.append(context.imports);
 280  260
         String className = classNameBuffer.toString();
 281  260
         compileHelper(context, code, className);
 282  260
         compileClass(context, code, className);
 283  260
         Parser parser = new Parser(new Scanner(fileName, new StringReader(code.toString())));
 284  
         //System.err.println(code);
 285  260
         if (engine.isDebugOn()) System.err.println(code);
 286  260
         Java.CompilationUnit unit = parser.parseCompilationUnit();
 287  
 
 288  
         // next parts copied from janino EvaluatorBase.compileAndLoad
 289  
 
 290  260
         EnumeratorSet debugInfo = DebuggingInformation.DEFAULT_DEBUGGING_INFORMATION;
 291  
 
 292  260
         final StringBuilder errorMessage = new StringBuilder();
 293  260
         UnitCompiler.ErrorHandler errorHandler = new UnitCompiler.ErrorHandler() {
 294  
             public void handleError(String message, Location location) {
 295  0
                 if (errorMessage.length() > 0) errorMessage.append('\n');
 296  0
                 if (location != null) errorMessage.append(location).append(": ");
 297  0
                 errorMessage.append(message);
 298  0
             }
 299  
         };
 300  
         // Compile compilation unit to class files.
 301  260
         UnitCompiler uc = new UnitCompiler(unit, classLoaderIClassLoader);
 302  260
         uc.setCompileErrorHandler(errorHandler);
 303  260
         ClassFile[] classFiles = null;
 304  260
         Exception caughtException = null;
 305  
         try {
 306  260
             classFiles = uc.compileUnit(debugInfo);
 307  0
         } catch (RuntimeException e) {
 308  0
             caughtException = e;
 309  0
         } catch (CompileException e) {
 310  0
             caughtException = e;
 311  
             // Ignore, janino throws a final CompileException, complaining
 312  
             // about: "X compile errors detected."
 313  260
         }
 314  260
         if (errorMessage.length() > 0) throw new CompileException(errorMessage.toString(), null);
 315  260
         if (caughtException != null) throw new CompileException("Error compiling", null, caughtException);
 316  
 
 317  
         // Convert the class files to bytes and store them in a Map.
 318  260
         HashMap<String, byte[]> classes = new HashMap<String, byte[]>(); // String className => byte[] data
 319  602
         for (ClassFile cf: classFiles) {
 320  342
             classes.put(cf.getThisClassName(), cf.toByteArray());
 321  
         }
 322  
 
 323  
         // Create a ClassLoader that loads the generated classes.
 324  260
         ClassLoader classLoader = new ByteArrayClassLoader(classes, classLoaderIClassLoader.getClassLoader());
 325  260
         if (packageNameBuffer.length() > 0) className = packageNameBuffer.append('.').append(className).toString();
 326  260
         return (C) classLoader.loadClass(className);
 327  
     }
 328  
 
 329  
     protected V newInstance(JaninoCompilerContext context, C clz) throws Throwable {
 330  70
         return clz.newInstance();
 331  
     }
 332  
 
 333  
     protected V init(CompilerContext context, C compiled) throws Throwable {
 334  260
         initHelper(context, compiled);
 335  260
         return newInstance((JaninoCompilerContext) context, compiled);
 336  
     }
 337  
 
 338  
     protected void initHelper(CompilerContext context, C compiled) throws Throwable {
 339  70
         Init init = (Init) compiled.getClassLoader().loadClass(compiled.getName() + "Init").newInstance();
 340  70
         init.init(engine, ((JaninoCompilerContext) context).beanObjects);
 341  70
     }
 342  
 
 343  
     public C compileKey(ApplyKey<C> key, CompilerContext context) throws BSFException {
 344  260
         return compileKey(key, (JaninoCompilerContext) context);
 345  
     }
 346  
 
 347  
     public C compileKey(EvalKey<C> key, CompilerContext context) throws BSFException {
 348  0
         return compileKey(key, (JaninoCompilerContext) context);
 349  
     }
 350  
 
 351  
     public C compileKey(ExecKey<C> key, CompilerContext context) throws BSFException {
 352  0
         return compileKey(key, (JaninoCompilerContext) context);
 353  
     }
 354  
 
 355  
     protected abstract C compileKey(ApplyKey<C> key, JaninoCompilerContext context) throws BSFException;
 356  
     protected abstract C compileKey(EvalKey<C> key, JaninoCompilerContext context) throws BSFException;
 357  
     protected abstract C compileKey(ExecKey<C> key, JaninoCompilerContext context) throws BSFException;
 358  
 }