/* 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); } } } } }