/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.drill.exec.compile; /* * Janino - An embedded Java[TM] compiler * * Copyright (c) 2001-2010, Arno Unkrig * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the * following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import org.codehaus.commons.compiler.CompileException; import org.codehaus.commons.compiler.IClassBodyEvaluator; public class ClassBodyBuilder { private String[] optionalDefaultImports = null; private String className = IClassBodyEvaluator.DEFAULT_CLASS_NAME; private Class<?> optionalExtendedType = null; private Class<?>[] implementedTypes = new Class[0]; private String[] imports = {}; private String body; private boolean used = false; public static ClassBodyBuilder newBuilder(){ return new ClassBodyBuilder(); } private ClassBodyBuilder(){ } public ClassBodyBuilder setClassName(String className) { assertNotCooked(); this.className = className; return this; } public ClassBodyBuilder setDefaultImports(String... optionalDefaultImports) { assertNotCooked(); this.optionalDefaultImports = optionalDefaultImports; return this; } public ClassBodyBuilder setExtendedClass(Class<?> optionalExtendedType) { assertNotCooked(); this.optionalExtendedType = optionalExtendedType; return this; } public ClassBodyBuilder setImplementedInterfaces(Class<?>... implementedTypes) { assertNotCooked(); this.implementedTypes = implementedTypes; return this; } private void assertNotCooked() { assert !used; } public ClassBodyBuilder setImports(String[] imports) { assertNotCooked(); this.imports = imports; return this; } public ClassBodyBuilder setBody(String body) { assertNotCooked(); this.body = body; return this; } public String build() throws CompileException, IOException { used = true; // Wrap the class body in a compilation unit. { StringWriter sw1 = new StringWriter(); { PrintWriter pw = new PrintWriter(sw1); // Break the class name up into package name and simple class name. String packageName; // null means default package. String simpleClassName; { int idx = this.className.lastIndexOf('.'); if (idx == -1) { packageName = ""; simpleClassName = this.className; } else { packageName = this.className.substring(0, idx); simpleClassName = this.className.substring(idx + 1); } } // Print PACKAGE directive. if (!packageName.isEmpty()) { pw.print("package "); pw.print(packageName); pw.println(";"); } // Print default imports. if (this.optionalDefaultImports != null) { for (String defaultImport : this.optionalDefaultImports) { pw.print("import "); pw.print(defaultImport); pw.println(";"); } } // Print imports as declared in the document. for (String imporT : imports) { pw.print("import "); pw.print(imporT); pw.println(";"); } // Print the class declaration. pw.print("public class "); pw.print(simpleClassName); if (this.optionalExtendedType != null) { pw.print(" extends "); pw.print(this.optionalExtendedType.getCanonicalName()); } if (this.implementedTypes.length > 0) { pw.print(" implements "); pw.print(this.implementedTypes[0].getName()); for (int i = 1; i < this.implementedTypes.length; ++i) { pw.print(", "); pw.print(this.implementedTypes[i].getName()); } } pw.println(" {"); pw.close(); } StringWriter sw2 = new StringWriter(); { PrintWriter pw = new PrintWriter(sw2); pw.println("}"); pw.close(); } return sw1.toString() + body + sw2.toString(); } } // /** // * Heuristically parse IMPORT declarations at the beginning of the character stream produced by the given // * {@link Reader}. After this method returns, all characters up to and including that last IMPORT declaration have // * been read from the {@link Reader}. // * <p> // * This method does not handle comments and string literals correctly, i.e. if a pattern that looks like an IMPORT // * declaration appears within a comment or a string literal, it will be taken as an IMPORT declaration. // * // * @param r // * A {@link Reader} that supports MARK, e.g. a {@link BufferedReader} // * @return The parsed imports, e.g. {@code "java.util.*", "static java.util.Map.Entry" } // */ // protected static String[] parseImportDeclarations(Reader r) throws IOException { // final CharBuffer cb = CharBuffer.allocate(10000); // r.mark(cb.limit()); // r.read(cb); // cb.rewind(); // // List<String> imports = new ArrayList<String>(); // int afterLastImport = 0; // for (Matcher matcher = IMPORT_STATEMENT_PATTERN.matcher(cb); matcher.find();) { // imports.add(matcher.group(1)); // afterLastImport = matcher.end(); // } // r.reset(); // r.skip(afterLastImport); // return imports.toArray(new String[imports.size()]); // } // // private static final Pattern IMPORT_STATEMENT_PATTERN = Pattern.compile("\\bimport\\s+" + "(" + "(?:static\\s+)?" // + "[\\p{javaLowerCase}\\p{javaUpperCase}_\\$][\\p{javaLowerCase}\\p{javaUpperCase}\\d_\\$]*" // + "(?:\\.[\\p{javaLowerCase}\\p{javaUpperCase}_\\$][\\p{javaLowerCase}\\p{javaUpperCase}\\d_\\$]*)*" // + "(?:\\.\\*)?" + ");"); // @Override // public Object createInstance(Reader reader) throws CompileException, IOException { // this.cook(reader); // try { // return this.getClazz().newInstance(); // } catch (InstantiationException ie) { // CompileException ce = new CompileException( // ("Class is abstract, an interface, an array class, a primitive type, or void; " // + "or has no zero-parameter constructor"), null); // ce.initCause(ie); // throw ce; // } catch (IllegalAccessException iae) { // CompileException ce = new CompileException("The class or its zero-parameter constructor is not accessible", null); // ce.initCause(iae); // throw ce; // } // } }