123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /* 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 com.android.tools.lint.checks.ApiLookup;
- import com.android.tools.lint.LintCliClient;
- 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 org.mozilla.gecko.annotationProcessors.utils.Utils;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.util.Arrays;
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.Properties;
- import java.util.Scanner;
- import java.util.Vector;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Member;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- public class SDKProcessor {
- 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 Javamethods and rerun the build. Manually updating this file\n" +
- "// will cause your build to fail.\n" +
- "\n";
- private static ApiLookup sApiLookup;
- private static int sMaxSdkVersion;
- public static void main(String[] args) throws Exception {
- // We expect a list of jars on the commandline. If missing, whinge about it.
- if (args.length < 5) {
- System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
- System.exit(1);
- }
- System.out.println("Processing platform bindings...");
- String sdkJar = args[0];
- Vector classes = getClassList(args[1]);
- String outdir = args[2];
- String generatedFilePrefix = args[3];
- sMaxSdkVersion = Integer.parseInt(args[4]);
- LintCliClient lintClient = new LintCliClient();
- sApiLookup = ApiLookup.get(lintClient);
- // Start the clock!
- long s = System.currentTimeMillis();
- // Get an iterator over the classes in the jar files given...
- // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
- StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
- headerFile.append(
- "#ifndef " + generatedFilePrefix + "_h__\n" +
- "#define " + generatedFilePrefix + "_h__\n" +
- "\n" +
- "#include \"mozilla/jni/Refs.h\"\n" +
- "\n" +
- "namespace mozilla {\n" +
- "namespace java {\n" +
- "namespace sdk {\n" +
- "\n");
- StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
- implementationFile.append(
- "#include \"" + generatedFilePrefix + ".h\"\n" +
- "#include \"mozilla/jni/Accessors.h\"\n" +
- "\n" +
- "namespace mozilla {\n" +
- "namespace java {\n" +
- "namespace sdk {\n" +
- "\n");
- // Used to track the calls to the various class-specific initialisation functions.
- ClassLoader loader = null;
- try {
- loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
- SDKProcessor.class.getClassLoader());
- } catch (Exception e) {
- throw new RuntimeException(e.toString());
- }
- for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
- String className = i.next();
- System.out.println("Looking up: " + className);
- generateClass(Class.forName(className, true, loader),
- implementationFile,
- headerFile);
- }
- implementationFile.append(
- "} /* sdk */\n" +
- "} /* java */\n" +
- "} /* mozilla */\n");
- headerFile.append(
- "} /* sdk */\n" +
- "} /* java */\n" +
- "} /* mozilla */\n" +
- "#endif\n");
- writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
- long e = System.currentTimeMillis();
- System.out.println("SDK processing complete in " + (e - s) + "ms");
- }
- private static int getAPIVersion(Class<?> cls, Member m) {
- if (m instanceof Method || m instanceof Constructor) {
- return sApiLookup.getCallVersion(
- cls.getName().replace('.', '/'),
- Utils.getMemberName(m),
- Utils.getSignature(m));
- } else if (m instanceof Field) {
- return sApiLookup.getFieldVersion(
- Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
- } else {
- throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
- }
- }
- private static Member[] sortAndFilterMembers(Class<?> cls, Member[] members) {
- Arrays.sort(members, new Comparator<Member>() {
- @Override
- public int compare(Member a, Member b) {
- return a.getName().compareTo(b.getName());
- }
- });
- ArrayList<Member> list = new ArrayList<>();
- for (Member m : members) {
- // Sometimes (e.g. Bundle) has methods that moved to/from a superclass in a later SDK
- // version, so we check for both classes and see if we can find a minimum SDK version.
- int version = getAPIVersion(cls, m);
- final int version2 = getAPIVersion(m.getDeclaringClass(), m);
- if (version2 > 0 && version2 < version) {
- version = version2;
- }
- if (version > sMaxSdkVersion) {
- System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
- ", version " + version + " > " + sMaxSdkVersion);
- continue;
- }
- // Sometimes (e.g. KeyEvent) a field can appear in both a class and a superclass. In
- // that case we want to filter out the version that appears in the superclass, or
- // we'll have bindings with duplicate names.
- try {
- if (m instanceof Field && !m.equals(cls.getField(m.getName()))) {
- // m is a field in a superclass that has been hidden by
- // a field with the same name in a subclass.
- System.out.println("Skipping " + m.getName() +
- " from " + m.getDeclaringClass());
- continue;
- }
- } catch (final NoSuchFieldException e) {
- }
- list.add(m);
- }
- return list.toArray(new Member[list.size()]);
- }
- private static void generateClass(Class<?> clazz,
- StringBuilder implementationFile,
- StringBuilder headerFile) {
- String generatedName = clazz.getSimpleName();
- CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
- generator.generateMembers(sortAndFilterMembers(clazz, clazz.getConstructors()));
- generator.generateMembers(sortAndFilterMembers(clazz, clazz.getMethods()));
- generator.generateMembers(sortAndFilterMembers(clazz, clazz.getFields()));
- headerFile.append(generator.getHeaderFileContents());
- implementationFile.append(generator.getWrapperFileContents());
- }
- private static Vector<String> getClassList(String path) {
- Scanner scanner = null;
- try {
- scanner = new Scanner(new FileInputStream(path));
- Vector lines = new Vector();
- while (scanner.hasNextLine()) {
- lines.add(scanner.nextLine());
- }
- return lines;
- } catch (Exception e) {
- System.out.println(e.toString());
- return null;
- } finally {
- if (scanner != null) {
- scanner.close();
- }
- }
- }
- private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile,
- StringBuilder aImplementationFile) {
- FileOutputStream implStream = null;
- try {
- implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp"));
- implStream.write(aImplementationFile.toString().getBytes());
- } catch (IOException e) {
- System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
- e.printStackTrace(System.err);
- } finally {
- if (implStream != null) {
- try {
- implStream.close();
- } catch (IOException e) {
- System.err.println("Unable to close implStream due to "+e);
- e.printStackTrace(System.err);
- }
- }
- }
- FileOutputStream headerStream = null;
- try {
- headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h"));
- headerStream.write(aHeaderFile.toString().getBytes());
- } catch (IOException e) {
- System.err.println("Unable to write " + aOutputDir + ". 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);
- }
- }
- }
- }
- }
|