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
;
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
;
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" +
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");
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
);
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
);
74 "#ifndef " + generatedFilePrefix
+ "_h__\n" +
75 "#define " + generatedFilePrefix
+ "_h__\n" +
77 "#include \"mozilla/jni/Refs.h\"\n" +
79 "namespace mozilla {\n" +
80 "namespace widget {\n" +
84 StringBuilder implementationFile
= new StringBuilder(GENERATED_COMMENT
);
85 implementationFile
.append(
86 "#include \"" + generatedFilePrefix
+ ".h\"\n" +
87 "#include \"mozilla/jni/Accessors.h\"\n" +
89 "namespace mozilla {\n" +
90 "namespace widget {\n" +
94 // Used to track the calls to the various class-specific initialisation functions.
95 ClassLoader loader
= null;
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
),
112 implementationFile
.append(
115 "} /* mozilla */\n");
120 "} /* mozilla */\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
>() {
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
) {
140 if (m
instanceof Method
|| m
instanceof Constructor
) {
141 version
= sApiLookup
.getCallVersion(
142 Utils
.getClassDescriptor(m
.getDeclaringClass()),
144 Utils
.getSignature(m
));
145 } else if (m
instanceof Field
) {
146 version
= sApiLookup
.getFieldVersion(
147 Utils
.getClassDescriptor(m
.getDeclaringClass()), m
.getName());
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
);
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;
182 scanner
= new Scanner(new FileInputStream(path
));
184 Vector lines
= new Vector();
185 while (scanner
.hasNextLine()) {
186 lines
.add(scanner
.nextLine());
189 } catch (Exception e
) {
190 System
.out
.println(e
.toString());
193 if (scanner
!= null) {
199 private static void writeOutputFiles(String aOutputDir
, String aPrefix
, StringBuilder aHeaderFile
,
200 StringBuilder aImplementationFile
) {
201 FileOutputStream implStream
= null;
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
);
209 if (implStream
!= null) {
212 } catch (IOException e
) {
213 System
.err
.println("Unable to close implStream due to "+e
);
214 e
.printStackTrace(System
.err
);
219 FileOutputStream headerStream
= null;
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
);
227 if (headerStream
!= null) {
229 headerStream
.close();
230 } catch (IOException e
) {
231 System
.err
.println("Unable to close headerStream due to "+e
);
232 e
.printStackTrace(System
.err
);