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