|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.annotationProcessors; |
|
6 |
|
7 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; |
|
8 import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; |
|
9 import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; |
|
10 import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; |
|
11 |
|
12 import java.io.FileOutputStream; |
|
13 import java.io.IOException; |
|
14 import java.util.Arrays; |
|
15 import java.util.Iterator; |
|
16 |
|
17 public class AnnotationProcessor { |
|
18 public static final String OUTFILE = "GeneratedJNIWrappers.cpp"; |
|
19 public static final String HEADERFILE = "GeneratedJNIWrappers.h"; |
|
20 |
|
21 public static final String GENERATED_COMMENT = |
|
22 "// GENERATED CODE\n" + |
|
23 "// Generated by the Java program at /build/annotationProcessors at compile time from\n" + |
|
24 "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" + |
|
25 "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n"; |
|
26 |
|
27 public static void main(String[] args) { |
|
28 // We expect a list of jars on the commandline. If missing, whinge about it. |
|
29 if (args.length <= 1) { |
|
30 System.err.println("Usage: java AnnotationProcessor jarfiles ..."); |
|
31 System.exit(1); |
|
32 } |
|
33 |
|
34 System.out.println("Processing annotations..."); |
|
35 |
|
36 // We want to produce the same output as last time as often as possible. Ordering of |
|
37 // generated statements, therefore, needs to be consistent. |
|
38 Arrays.sort(args); |
|
39 |
|
40 // Start the clock! |
|
41 long s = System.currentTimeMillis(); |
|
42 |
|
43 // Get an iterator over the classes in the jar files given... |
|
44 Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args); |
|
45 |
|
46 StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); |
|
47 headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" + |
|
48 "#define GeneratedJNIWrappers_h__\n\n" + |
|
49 "#include \"nsXPCOMStrings.h\"\n" + |
|
50 "#include \"AndroidJavaWrappers.h\"\n" + |
|
51 "\n" + |
|
52 "namespace mozilla {\n" + |
|
53 "namespace widget {\n" + |
|
54 "namespace android {\n" + |
|
55 "void InitStubs(JNIEnv *jEnv);\n\n"); |
|
56 |
|
57 StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); |
|
58 implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" + |
|
59 "#include \"AndroidBridgeUtilities.h\"\n" + |
|
60 "#include \"nsXPCOMStrings.h\"\n" + |
|
61 "#include \"AndroidBridge.h\"\n" + |
|
62 "\n" + |
|
63 "namespace mozilla {\n" + |
|
64 "namespace widget {\n" + |
|
65 "namespace android {\n"); |
|
66 |
|
67 // Used to track the calls to the various class-specific initialisation functions. |
|
68 StringBuilder stubInitialiser = new StringBuilder(); |
|
69 stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n"); |
|
70 |
|
71 while (jarClassIterator.hasNext()) { |
|
72 ClassWithOptions aClassTuple = jarClassIterator.next(); |
|
73 |
|
74 CodeGenerator generatorInstance; |
|
75 |
|
76 // Get an iterator over the appropriately generated methods of this class |
|
77 Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass); |
|
78 |
|
79 if (!methodIterator.hasNext()) { |
|
80 continue; |
|
81 } |
|
82 generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName); |
|
83 |
|
84 stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n"); |
|
85 |
|
86 // Iterate all annotated members in this class.. |
|
87 while (methodIterator.hasNext()) { |
|
88 AnnotatableEntity aElementTuple = methodIterator.next(); |
|
89 switch (aElementTuple.mEntityType) { |
|
90 case METHOD: |
|
91 generatorInstance.generateMethod(aElementTuple); |
|
92 break; |
|
93 case FIELD: |
|
94 generatorInstance.generateField(aElementTuple); |
|
95 break; |
|
96 case CONSTRUCTOR: |
|
97 generatorInstance.generateConstructor(aElementTuple); |
|
98 break; |
|
99 } |
|
100 } |
|
101 |
|
102 headerFile.append(generatorInstance.getHeaderFileContents()); |
|
103 implementationFile.append(generatorInstance.getWrapperFileContents()); |
|
104 } |
|
105 |
|
106 implementationFile.append('\n'); |
|
107 stubInitialiser.append("}"); |
|
108 implementationFile.append(stubInitialiser); |
|
109 |
|
110 implementationFile.append("\n} /* android */\n" + |
|
111 "} /* widget */\n" + |
|
112 "} /* mozilla */\n"); |
|
113 |
|
114 headerFile.append("\n} /* android */\n" + |
|
115 "} /* widget */\n" + |
|
116 "} /* mozilla */\n" + |
|
117 "#endif\n"); |
|
118 |
|
119 writeOutputFiles(headerFile, implementationFile); |
|
120 long e = System.currentTimeMillis(); |
|
121 System.out.println("Annotation processing complete in " + (e - s) + "ms"); |
|
122 } |
|
123 |
|
124 private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) { |
|
125 FileOutputStream headerStream = null; |
|
126 try { |
|
127 headerStream = new FileOutputStream(OUTFILE); |
|
128 headerStream.write(aImplementationFile.toString().getBytes()); |
|
129 } catch (IOException e) { |
|
130 System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?"); |
|
131 e.printStackTrace(System.err); |
|
132 } finally { |
|
133 if (headerStream != null) { |
|
134 try { |
|
135 headerStream.close(); |
|
136 } catch (IOException e) { |
|
137 System.err.println("Unable to close headerStream due to "+e); |
|
138 e.printStackTrace(System.err); |
|
139 } |
|
140 } |
|
141 } |
|
142 |
|
143 FileOutputStream outStream = null; |
|
144 try { |
|
145 outStream = new FileOutputStream(HEADERFILE); |
|
146 outStream.write(aHeaderFile.toString().getBytes()); |
|
147 } catch (IOException e) { |
|
148 System.err.println("Unable to write " + HEADERFILE + ". Perhaps a permissions issue?"); |
|
149 e.printStackTrace(System.err); |
|
150 } finally { |
|
151 if (outStream != null) { |
|
152 try { |
|
153 outStream.close(); |
|
154 } catch (IOException e) { |
|
155 System.err.println("Unable to close outStream due to "+e); |
|
156 e.printStackTrace(System.err); |
|
157 } |
|
158 } |
|
159 } |
|
160 } |
|
161 } |