diff options
author | Ben Dodson <bjdodson@google.com> | 2010-08-04 15:21:06 -0700 |
---|---|---|
committer | Ben Dodson <bjdodson@google.com> | 2010-08-04 17:50:13 -0700 |
commit | 920dbbbaca6aa578f3b26d89e99d12754c26ed60 (patch) | |
tree | ff22fba664681032459f526d51f14411403ea187 /src/com/google/doclava/DoclavaDiff.java | |
parent | c8f6c750effdcfe65efc5a7d3bb62c4693cf4231 (diff) | |
download | android_external_doclava-920dbbbaca6aa578f3b26d89e99d12754c26ed60.tar.gz android_external_doclava-920dbbbaca6aa578f3b26d89e99d12754c26ed60.tar.bz2 android_external_doclava-920dbbbaca6aa578f3b26d89e99d12754c26ed60.zip |
Initial import of Doclava project
Change-Id: Ia5ae56f1700fce98e0ae6954fa2df617ec0537bb
Diffstat (limited to 'src/com/google/doclava/DoclavaDiff.java')
-rw-r--r-- | src/com/google/doclava/DoclavaDiff.java | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/src/com/google/doclava/DoclavaDiff.java b/src/com/google/doclava/DoclavaDiff.java new file mode 100644 index 0000000..e043246 --- /dev/null +++ b/src/com/google/doclava/DoclavaDiff.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.doclava; + +import com.google.clearsilver.jsilver.JSilver; +import com.google.clearsilver.jsilver.data.Data; +import com.google.clearsilver.jsilver.resourceloader.CompositeResourceLoader; +import com.google.clearsilver.jsilver.resourceloader.FileSystemResourceLoader; +import com.google.clearsilver.jsilver.resourceloader.ResourceLoader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * This class is used to generate a web page highlighting the differences and + * similarities among various Java libraries. + * + */ +public final class DoclavaDiff { + private final String outputDir; + private final JSilver jSilver; + private final List<FederatedSite> sites = new ArrayList<FederatedSite>(); + + public static void main(String[] args) { + new DoclavaDiff(args).generateSite(); + } + + public DoclavaDiff(String[] args) { + // TODO: options parsing + try { + sites.add(new FederatedSite("Android", new URL("http://manatee/doclava/android"))); + sites.add(new FederatedSite("GWT", new URL("http://manatee/doclava/gwt"))); + //sites.add(new FederatedSite("Crore", new URL("http://manatee/doclava/crore"))); + outputDir = "build"; + } catch (Exception e) { + throw new AssertionError(e); + } + + // TODO: accept external templates + List<ResourceLoader> resourceLoaders = new ArrayList<ResourceLoader>(); + resourceLoaders.add(new FileSystemResourceLoader("assets/templates")); + + ResourceLoader compositeResourceLoader = new CompositeResourceLoader(resourceLoaders); + jSilver = new JSilver(compositeResourceLoader); + } + + public void generateSite() { + Data data = generateHdf(); + generateHtml("diff.cs", data, new File(outputDir + "/diff.html")); + } + + /** + * Creates an HDF with this structure: + * <pre> + * sites.0.name = Android + * sites.0.url = http://developer.android.com/reference + * sites.1.name = GWT + * sites.1.url = http://gwt.googlecode.com + * packages.0.name = java.lang + * packages.0.sites.0.hasPackage = 1 + * packages.0.sites.0.link = http://developer.android.com/reference/java/lang + * packages.0.sites.1.hasPackage = 0 + * packages.0.classes.0.qualifiedName = java.lang.Object + * packages.0.classes.0.sites.0.hasClass = 1 + * packages.0.classes.0.sites.0.link = http://developer.android.com/reference/java/lang/Object + * packages.0.classes.0.sites.1.hasClass = 0 + * packages.0.classes.0.methods.0.signature = wait() + * packages.0.classes.0.methods.0.sites.0.hasMethod = 1 + * packages.0.classes.0.methods.0.sites.0.link = http://developer.android.com/reference/java/lang/Object#wait + * packages.0.classes.0.methods.0.sites.1.hasMethod = 0 + * </pre> + */ + private Data generateHdf() { + Data data = jSilver.createData(); + + data.setValue("triangle.opened", "../assets/templates/assets/images/triangle-opened.png"); + data.setValue("triangle.closed", "../assets/templates/assets/images/triangle-closed.png"); + + int i = 0; + for (FederatedSite site : sites) { + String base = "sites." + (i++); + data.setValue(base + ".name", site.name()); + data.setValue(base + ".url", site.baseUrl().toString()); + } + + List<String> allPackages = knownPackages(sites); + + int p = 0; + for (String pkg : allPackages) { + PackageInfo packageInfo = new PackageInfo(pkg); + String packageBase = "packages." + (p++); + data.setValue(packageBase + ".name", pkg); + + int s = 0; + for (FederatedSite site : sites) { + String siteBase = packageBase + ".sites." + (s++); + if (site.apiInfo().getPackages().containsKey(pkg)) { + data.setValue(siteBase + ".hasPackage", "1"); + data.setValue(siteBase + ".link", site.linkFor(packageInfo.htmlPage())); + } else { + data.setValue(siteBase + ".hasPackage", "0"); + } + } + + if (packageUniqueToSite(pkg, sites)) { + continue; + } + + List<String> packageClasses = knownClassesForPackage(pkg, sites); + int c = 0; + for (String qualifiedClassName : packageClasses) { + String classBase = packageBase + ".classes." + (c++); + data.setValue(classBase + ".qualifiedName", qualifiedClassName); + + s = 0; + for (FederatedSite site : sites) { + String siteBase = classBase + ".sites." + (s++); + ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName); + if (classInfo != null) { + data.setValue(siteBase + ".hasClass", "1"); + data.setValue(siteBase + ".link", site.linkFor(classInfo.htmlPage())); + } else { + data.setValue(siteBase + ".hasClass", "0"); + } + } + + if (agreeOnClass(qualifiedClassName, sites)) { + continue; + } + + if (classUniqueToSite(qualifiedClassName, sites)) { + continue; + } + + int m = 0; + List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites); + for (MethodInfo method : methods) { + if (agreeOnMethod(qualifiedClassName, method, sites)) { + continue; + } + + String methodBase = classBase + ".methods." + (m++); + data.setValue(methodBase + ".signature", method.prettySignature()); + int k = 0; + for (FederatedSite site : sites) { + String siteBase = methodBase + ".sites." + (k++); + if (site.apiInfo().findClass(qualifiedClassName) == null) { + data.setValue(siteBase + ".hasMethod", "0"); + continue; + } + Map<String,MethodInfo> siteMethods + = site.apiInfo().findClass(qualifiedClassName).allMethods(); + if (siteMethods.containsKey(method.getHashableName())) { + data.setValue(siteBase + ".hasMethod", "1"); + data.setValue(siteBase + ".link", site.linkFor(method.htmlPage())); + } else { + data.setValue(siteBase + ".hasMethod", "0"); + } + } + } + } + } + + return data; + } + + /** + * Returns a list of all known packages from all sites. + */ + private List<String> knownPackages(List<FederatedSite> sites) { + Set<String> allPackages = new LinkedHashSet<String>(); + for (FederatedSite site : sites) { + Map<String, PackageInfo> packages = site.apiInfo().getPackages(); + for (String pkg : packages.keySet()) { + allPackages.add(pkg); + } + } + + List<String> packages = new ArrayList<String>(allPackages); + Collections.sort(packages); + return packages; + } + + /** + * Returns all known classes from all sites for a given package. + */ + private List<String> knownClassesForPackage(String pkg, List<FederatedSite> sites) { + Set<String> allClasses = new LinkedHashSet<String>(); + for (FederatedSite site : sites) { + PackageInfo packageInfo = site.apiInfo().getPackages().get(pkg); + if (packageInfo == null) { + continue; + } + HashMap<String, ClassInfo> classes = packageInfo.allClasses(); + for (Map.Entry<String, ClassInfo> entry : classes.entrySet()) { + allClasses.add(entry.getValue().qualifiedName()); + } + } + + List<String> classes = new ArrayList<String>(allClasses); + Collections.sort(classes); + return classes; + } + + /** + * Returns all known methods from all sites for a given class. + */ + private List<MethodInfo> knownMethodsForClass(String qualifiedClassName, + List<FederatedSite> sites) { + + Map<String, MethodInfo> allMethods = new HashMap<String, MethodInfo>(); + for (FederatedSite site : sites) { + ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName); + if (classInfo == null) { + continue; + } + + for (Map.Entry<String, MethodInfo> entry: classInfo.allMethods().entrySet()) { + allMethods.put(entry.getKey(), entry.getValue()); + } + } + + List<MethodInfo> methods = new ArrayList<MethodInfo>(); + methods.addAll(allMethods.values()); + return methods; + } + + /** + * Returns true if the list of sites all completely agree on the given + * package. All sites must possess the package, all classes it contains, and + * all methods of each class. + */ + private boolean agreeOnPackage(String pkg, List<FederatedSite> sites) { + for (FederatedSite site : sites) { + if (site.apiInfo().getPackages().get(pkg) == null) { + return false; + } + } + + List<String> classes = knownClassesForPackage(pkg, sites); + for (String clazz : classes) { + if (!agreeOnClass(clazz, sites)) { + return false; + } + } + return true; + } + + /** + * Returns true if the list of sites all agree on the given class. Each site + * must have the class and agree on its methods. + */ + private boolean agreeOnClass(String qualifiedClassName, List<FederatedSite> sites) { + List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites); + for (MethodInfo method : methods) { + if (!agreeOnMethod(qualifiedClassName, method, sites)) { + return false; + } + } + return true; + } + + /** + * Returns true if the list of sites all contain the given method. + */ + private boolean agreeOnMethod(String qualifiedClassName, MethodInfo method, + List<FederatedSite> sites) { + + for (FederatedSite site : sites) { + ClassInfo siteClass = site.apiInfo().findClass(qualifiedClassName); + if (siteClass == null) { + return false; + } + + if (!siteClass.supportsMethod(method)) { + return false; + } + } + return true; + } + + /** + * Returns true if the given package is known to exactly one of the given sites. + */ + private boolean packageUniqueToSite(String pkg, List<FederatedSite> sites) { + int numSites = 0; + for (FederatedSite site : sites) { + if (site.apiInfo().getPackages().containsKey(pkg)) { + numSites++; + } + } + return numSites == 1; + } + + /** + * Returns true if the given class is known to exactly one of the given sites. + */ + private boolean classUniqueToSite(String qualifiedClassName, List<FederatedSite> sites) { + int numSites = 0; + for (FederatedSite site : sites) { + if (site.apiInfo().findClass(qualifiedClassName) != null) { + numSites++; + } + } + return numSites == 1; + } + + private void generateHtml(String template, Data data, File file) { + ClearPage.ensureDirectory(file); + + OutputStreamWriter stream = null; + try { + stream = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); + String rendered = jSilver.render(template, data); + stream.write(rendered, 0, rendered.length()); + } catch (IOException e) { + System.out.println("error: " + e.getMessage() + "; when writing file: " + file.getAbsolutePath()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException ignored) {} + } + } + } +}
\ No newline at end of file |