Bumping manifests a=b2g-bump
[gecko.git] / build / annotationProcessors / SDKProcessor.java
blob2ffc1905edd03677b539af72361f8704a5587cc7
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/. */
5 package org.mozilla.gecko.annotationProcessors;
7 import com.android.tools.lint.checks.ApiLookup;
8 import com.android.tools.lint.LintCliClient;
10 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
11 import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
12 import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
13 import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
14 import org.mozilla.gecko.annotationProcessors.utils.Utils;
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.util.Arrays;
21 import java.util.ArrayList;
22 import java.util.Comparator;
23 import java.util.Iterator;
24 import java.util.Properties;
25 import java.util.Scanner;
26 import java.util.Vector;
27 import java.net.URL;
28 import java.net.URLClassLoader;
30 import java.lang.reflect.Constructor;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.Member;
33 import java.lang.reflect.Method;
34 import java.lang.reflect.Modifier;
36 public class SDKProcessor {
37 public static final String GENERATED_COMMENT =
38 "// GENERATED CODE\n" +
39 "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
40 "// from annotations on Java methods. To update, change the annotations on the\n" +
41 "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
42 "// will cause your build to fail.\n" +
43 "\n";
45 private static ApiLookup sApiLookup;
46 private static int sMaxSdkVersion;
48 public static void main(String[] args) throws Exception {
49 // We expect a list of jars on the commandline. If missing, whinge about it.
50 if (args.length < 5) {
51 System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
52 System.exit(1);
55 System.out.println("Processing platform bindings...");
57 String sdkJar = args[0];
58 Vector classes = getClassList(args[1]);
59 String outdir = args[2];
60 String generatedFilePrefix = args[3];
61 sMaxSdkVersion = Integer.parseInt(args[4]);
63 LintCliClient lintClient = new LintCliClient();
64 sApiLookup = ApiLookup.get(lintClient);
66 // Start the clock!
67 long s = System.currentTimeMillis();
69 // Get an iterator over the classes in the jar files given...
70 // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
72 StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
73 headerFile.append(
74 "#ifndef " + generatedFilePrefix + "_h__\n" +
75 "#define " + generatedFilePrefix + "_h__\n" +
76 "\n" +
77 "#include \"mozilla/jni/Refs.h\"\n" +
78 "\n" +
79 "namespace mozilla {\n" +
80 "namespace widget {\n" +
81 "namespace sdk {\n" +
82 "\n");
84 StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
85 implementationFile.append(
86 "#include \"" + generatedFilePrefix + ".h\"\n" +
87 "#include \"mozilla/jni/Accessors.h\"\n" +
88 "\n" +
89 "namespace mozilla {\n" +
90 "namespace widget {\n" +
91 "namespace sdk {\n" +
92 "\n");
94 // Used to track the calls to the various class-specific initialisation functions.
95 ClassLoader loader = null;
96 try {
97 loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
98 SDKProcessor.class.getClassLoader());
99 } catch (Exception e) {
100 throw new RuntimeException(e.toString());
103 for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
104 String className = i.next();
105 System.out.println("Looking up: " + className);
107 generateClass(Class.forName(className, true, loader),
108 implementationFile,
109 headerFile);
112 implementationFile.append(
113 "} /* sdk */\n" +
114 "} /* widget */\n" +
115 "} /* mozilla */\n");
117 headerFile.append(
118 "} /* sdk */\n" +
119 "} /* widget */\n" +
120 "} /* mozilla */\n" +
121 "#endif\n");
123 writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
124 long e = System.currentTimeMillis();
125 System.out.println("SDK processing complete in " + (e - s) + "ms");
128 private static Member[] sortAndFilterMembers(Member[] members) {
129 Arrays.sort(members, new Comparator<Member>() {
130 @Override
131 public int compare(Member a, Member b) {
132 return a.getName().compareTo(b.getName());
136 ArrayList<Member> list = new ArrayList<>();
137 for (Member m : members) {
138 int version = 0;
140 if (m instanceof Method || m instanceof Constructor) {
141 version = sApiLookup.getCallVersion(
142 Utils.getClassDescriptor(m.getDeclaringClass()),
143 m.getName(),
144 Utils.getSignature(m));
145 } else if (m instanceof Field) {
146 version = sApiLookup.getFieldVersion(
147 Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
148 } else {
149 throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
152 if (version > sMaxSdkVersion) {
153 System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
154 ", version " + version + " > " + sMaxSdkVersion);
155 continue;
158 list.add(m);
161 return list.toArray(new Member[list.size()]);
164 private static void generateClass(Class<?> clazz,
165 StringBuilder implementationFile,
166 StringBuilder headerFile) {
167 String generatedName = clazz.getSimpleName();
169 CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
171 generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
172 generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
173 generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
175 headerFile.append(generator.getHeaderFileContents());
176 implementationFile.append(generator.getWrapperFileContents());
179 private static Vector<String> getClassList(String path) {
180 Scanner scanner = null;
181 try {
182 scanner = new Scanner(new FileInputStream(path));
184 Vector lines = new Vector();
185 while (scanner.hasNextLine()) {
186 lines.add(scanner.nextLine());
188 return lines;
189 } catch (Exception e) {
190 System.out.println(e.toString());
191 return null;
192 } finally {
193 if (scanner != null) {
194 scanner.close();
199 private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile,
200 StringBuilder aImplementationFile) {
201 FileOutputStream implStream = null;
202 try {
203 implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp"));
204 implStream.write(aImplementationFile.toString().getBytes());
205 } catch (IOException e) {
206 System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
207 e.printStackTrace(System.err);
208 } finally {
209 if (implStream != null) {
210 try {
211 implStream.close();
212 } catch (IOException e) {
213 System.err.println("Unable to close implStream due to "+e);
214 e.printStackTrace(System.err);
219 FileOutputStream headerStream = null;
220 try {
221 headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h"));
222 headerStream.write(aHeaderFile.toString().getBytes());
223 } catch (IOException e) {
224 System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
225 e.printStackTrace(System.err);
226 } finally {
227 if (headerStream != null) {
228 try {
229 headerStream.close();
230 } catch (IOException e) {
231 System.err.println("Unable to close headerStream due to "+e);
232 e.printStackTrace(System.err);