| /* 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 SOURCE_FILE = "GeneratedJNIWrappers.cpp"; |
| public static final String HEADER_FILE = "GeneratedJNIWrappers.h"; |
| public static final String NATIVES_FILE = "GeneratedJNINatives.h"; |
| |
| public static final String GENERATED_COMMENT = |
| "// GENERATED CODE\n" + |
| "// Generated by the Java program at /build/annotationProcessors at compile time\n" + |
| "// from annotations on Java methods. To update, change the annotations on the\n" + |
| "// corresponding Java methods and rerun the build. Manually updating this file\n" + |
| "// will cause your build to fail.\n" + |
| "\n"; |
| |
| private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); |
| private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); |
| private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT); |
| |
| 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<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args); |
| |
| headerFile.append( |
| "#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" + |
| "#define " + getHeaderGuardName(HEADER_FILE) + "\n" + |
| "\n" + |
| "#include \"mozilla/jni/Refs.h\"\n" + |
| "\n" + |
| "namespace mozilla {\n" + |
| "namespace widget {\n" + |
| "\n"); |
| |
| implementationFile.append( |
| "#include \"GeneratedJNIWrappers.h\"\n" + |
| "#include \"mozilla/jni/Accessors.h\"\n" + |
| "\n" + |
| "namespace mozilla {\n" + |
| "namespace widget {\n" + |
| "\n"); |
| |
| nativesFile.append( |
| "#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" + |
| "#define " + getHeaderGuardName(NATIVES_FILE) + "\n" + |
| "\n" + |
| "#include \"GeneratedJNIWrappers.h\"\n" + |
| "#include \"mozilla/jni/Natives.h\"\n" + |
| "\n" + |
| "namespace mozilla {\n" + |
| "namespace widget {\n" + |
| "\n"); |
| |
| while (jarClassIterator.hasNext()) { |
| generateClass(jarClassIterator.next()); |
| } |
| |
| implementationFile.append( |
| "} /* widget */\n" + |
| "} /* mozilla */\n"); |
| |
| headerFile.append( |
| "} /* widget */\n" + |
| "} /* mozilla */\n" + |
| "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n"); |
| |
| nativesFile.append( |
| "} /* widget */\n" + |
| "} /* mozilla */\n" + |
| "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n"); |
| |
| writeOutputFile(SOURCE_FILE, implementationFile); |
| writeOutputFile(HEADER_FILE, headerFile); |
| writeOutputFile(NATIVES_FILE, nativesFile); |
| |
| long e = System.currentTimeMillis(); |
| System.out.println("Annotation processing complete in " + (e - s) + "ms"); |
| } |
| |
| private static void generateClass(final ClassWithOptions annotatedClass) { |
| // Get an iterator over the appropriately generated methods of this class |
| final GeneratableElementIterator methodIterator |
| = new GeneratableElementIterator(annotatedClass); |
| final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses(); |
| |
| if (!methodIterator.hasNext() && innerClasses.length == 0) { |
| return; |
| } |
| |
| final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass); |
| generatorInstance.generateClasses(innerClasses); |
| |
| // Iterate all annotated members in this class.. |
| while (methodIterator.hasNext()) { |
| AnnotatableEntity aElementTuple = methodIterator.next(); |
| switch (aElementTuple.mEntityType) { |
| case METHOD: |
| generatorInstance.generateMethod(aElementTuple); |
| break; |
| case NATIVE: |
| generatorInstance.generateNative(aElementTuple); |
| break; |
| case FIELD: |
| generatorInstance.generateField(aElementTuple); |
| break; |
| case CONSTRUCTOR: |
| generatorInstance.generateConstructor(aElementTuple); |
| break; |
| } |
| } |
| |
| headerFile.append(generatorInstance.getHeaderFileContents()); |
| implementationFile.append(generatorInstance.getWrapperFileContents()); |
| nativesFile.append(generatorInstance.getNativesFileContents()); |
| |
| for (ClassWithOptions innerClass : innerClasses) { |
| generateClass(innerClass); |
| } |
| } |
| |
| private static String getHeaderGuardName(final String name) { |
| return name.replaceAll("\\W", "_"); |
| } |
| |
| private static void writeOutputFile(final String name, |
| final StringBuilder content) { |
| FileOutputStream outStream = null; |
| try { |
| outStream = new FileOutputStream(name); |
| outStream.write(content.toString().getBytes()); |
| } catch (IOException e) { |
| System.err.println("Unable to write " + name + ". 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); |
| } |
| } |
| } |
| } |
| } |