michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.annotationProcessors; michael@0: michael@0: import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; michael@0: import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; michael@0: import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; michael@0: import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; michael@0: michael@0: import java.io.FileOutputStream; michael@0: import java.io.IOException; michael@0: import java.util.Arrays; michael@0: import java.util.Iterator; michael@0: michael@0: public class AnnotationProcessor { michael@0: public static final String OUTFILE = "GeneratedJNIWrappers.cpp"; michael@0: public static final String HEADERFILE = "GeneratedJNIWrappers.h"; michael@0: michael@0: public static final String GENERATED_COMMENT = michael@0: "// GENERATED CODE\n" + michael@0: "// Generated by the Java program at /build/annotationProcessors at compile time from\n" + michael@0: "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" + michael@0: "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n"; michael@0: michael@0: public static void main(String[] args) { michael@0: // We expect a list of jars on the commandline. If missing, whinge about it. michael@0: if (args.length <= 1) { michael@0: System.err.println("Usage: java AnnotationProcessor jarfiles ..."); michael@0: System.exit(1); michael@0: } michael@0: michael@0: System.out.println("Processing annotations..."); michael@0: michael@0: // We want to produce the same output as last time as often as possible. Ordering of michael@0: // generated statements, therefore, needs to be consistent. michael@0: Arrays.sort(args); michael@0: michael@0: // Start the clock! michael@0: long s = System.currentTimeMillis(); michael@0: michael@0: // Get an iterator over the classes in the jar files given... michael@0: Iterator jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args); michael@0: michael@0: StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); michael@0: headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" + michael@0: "#define GeneratedJNIWrappers_h__\n\n" + michael@0: "#include \"nsXPCOMStrings.h\"\n" + michael@0: "#include \"AndroidJavaWrappers.h\"\n" + michael@0: "\n" + michael@0: "namespace mozilla {\n" + michael@0: "namespace widget {\n" + michael@0: "namespace android {\n" + michael@0: "void InitStubs(JNIEnv *jEnv);\n\n"); michael@0: michael@0: StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); michael@0: implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" + michael@0: "#include \"AndroidBridgeUtilities.h\"\n" + michael@0: "#include \"nsXPCOMStrings.h\"\n" + michael@0: "#include \"AndroidBridge.h\"\n" + michael@0: "\n" + michael@0: "namespace mozilla {\n" + michael@0: "namespace widget {\n" + michael@0: "namespace android {\n"); michael@0: michael@0: // Used to track the calls to the various class-specific initialisation functions. michael@0: StringBuilder stubInitialiser = new StringBuilder(); michael@0: stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n"); michael@0: michael@0: while (jarClassIterator.hasNext()) { michael@0: ClassWithOptions aClassTuple = jarClassIterator.next(); michael@0: michael@0: CodeGenerator generatorInstance; michael@0: michael@0: // Get an iterator over the appropriately generated methods of this class michael@0: Iterator methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass); michael@0: michael@0: if (!methodIterator.hasNext()) { michael@0: continue; michael@0: } michael@0: generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName); michael@0: michael@0: stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n"); michael@0: michael@0: // Iterate all annotated members in this class.. michael@0: while (methodIterator.hasNext()) { michael@0: AnnotatableEntity aElementTuple = methodIterator.next(); michael@0: switch (aElementTuple.mEntityType) { michael@0: case METHOD: michael@0: generatorInstance.generateMethod(aElementTuple); michael@0: break; michael@0: case FIELD: michael@0: generatorInstance.generateField(aElementTuple); michael@0: break; michael@0: case CONSTRUCTOR: michael@0: generatorInstance.generateConstructor(aElementTuple); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: headerFile.append(generatorInstance.getHeaderFileContents()); michael@0: implementationFile.append(generatorInstance.getWrapperFileContents()); michael@0: } michael@0: michael@0: implementationFile.append('\n'); michael@0: stubInitialiser.append("}"); michael@0: implementationFile.append(stubInitialiser); michael@0: michael@0: implementationFile.append("\n} /* android */\n" + michael@0: "} /* widget */\n" + michael@0: "} /* mozilla */\n"); michael@0: michael@0: headerFile.append("\n} /* android */\n" + michael@0: "} /* widget */\n" + michael@0: "} /* mozilla */\n" + michael@0: "#endif\n"); michael@0: michael@0: writeOutputFiles(headerFile, implementationFile); michael@0: long e = System.currentTimeMillis(); michael@0: System.out.println("Annotation processing complete in " + (e - s) + "ms"); michael@0: } michael@0: michael@0: private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) { michael@0: FileOutputStream headerStream = null; michael@0: try { michael@0: headerStream = new FileOutputStream(OUTFILE); michael@0: headerStream.write(aImplementationFile.toString().getBytes()); michael@0: } catch (IOException e) { michael@0: System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?"); michael@0: e.printStackTrace(System.err); michael@0: } finally { michael@0: if (headerStream != null) { michael@0: try { michael@0: headerStream.close(); michael@0: } catch (IOException e) { michael@0: System.err.println("Unable to close headerStream due to "+e); michael@0: e.printStackTrace(System.err); michael@0: } michael@0: } michael@0: } michael@0: michael@0: FileOutputStream outStream = null; michael@0: try { michael@0: outStream = new FileOutputStream(HEADERFILE); michael@0: outStream.write(aHeaderFile.toString().getBytes()); michael@0: } catch (IOException e) { michael@0: System.err.println("Unable to write " + HEADERFILE + ". Perhaps a permissions issue?"); michael@0: e.printStackTrace(System.err); michael@0: } finally { michael@0: if (outStream != null) { michael@0: try { michael@0: outStream.close(); michael@0: } catch (IOException e) { michael@0: System.err.println("Unable to close outStream due to "+e); michael@0: e.printStackTrace(System.err); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: }