xref: /aosp_15_r20/external/doclava/src/com/google/doclava/DoclavaDiff.java (revision feeed43c7c55e85932c547a3cefc559df175227c)
1*feeed43cSAndroid Build Coastguard Worker /*
2*feeed43cSAndroid Build Coastguard Worker  * Copyright (C) 2010 Google Inc.
3*feeed43cSAndroid Build Coastguard Worker  *
4*feeed43cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*feeed43cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*feeed43cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*feeed43cSAndroid Build Coastguard Worker  *
8*feeed43cSAndroid Build Coastguard Worker  * http://www.apache.org/licenses/LICENSE-2.0
9*feeed43cSAndroid Build Coastguard Worker  *
10*feeed43cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*feeed43cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*feeed43cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*feeed43cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*feeed43cSAndroid Build Coastguard Worker  * limitations under the License.
15*feeed43cSAndroid Build Coastguard Worker  */
16*feeed43cSAndroid Build Coastguard Worker 
17*feeed43cSAndroid Build Coastguard Worker package com.google.doclava;
18*feeed43cSAndroid Build Coastguard Worker 
19*feeed43cSAndroid Build Coastguard Worker import com.google.clearsilver.jsilver.JSilver;
20*feeed43cSAndroid Build Coastguard Worker import com.google.clearsilver.jsilver.data.Data;
21*feeed43cSAndroid Build Coastguard Worker import com.google.clearsilver.jsilver.resourceloader.CompositeResourceLoader;
22*feeed43cSAndroid Build Coastguard Worker import com.google.clearsilver.jsilver.resourceloader.FileSystemResourceLoader;
23*feeed43cSAndroid Build Coastguard Worker import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
24*feeed43cSAndroid Build Coastguard Worker import java.io.File;
25*feeed43cSAndroid Build Coastguard Worker import java.io.FileOutputStream;
26*feeed43cSAndroid Build Coastguard Worker import java.io.IOException;
27*feeed43cSAndroid Build Coastguard Worker import java.io.OutputStreamWriter;
28*feeed43cSAndroid Build Coastguard Worker import java.net.URL;
29*feeed43cSAndroid Build Coastguard Worker import java.util.ArrayList;
30*feeed43cSAndroid Build Coastguard Worker import java.util.Collections;
31*feeed43cSAndroid Build Coastguard Worker import java.util.HashMap;
32*feeed43cSAndroid Build Coastguard Worker import java.util.LinkedHashSet;
33*feeed43cSAndroid Build Coastguard Worker import java.util.List;
34*feeed43cSAndroid Build Coastguard Worker import java.util.Map;
35*feeed43cSAndroid Build Coastguard Worker import java.util.Set;
36*feeed43cSAndroid Build Coastguard Worker 
37*feeed43cSAndroid Build Coastguard Worker /**
38*feeed43cSAndroid Build Coastguard Worker  * This class is used to generate a web page highlighting the differences and
39*feeed43cSAndroid Build Coastguard Worker  * similarities among various Java libraries.
40*feeed43cSAndroid Build Coastguard Worker  *
41*feeed43cSAndroid Build Coastguard Worker  */
42*feeed43cSAndroid Build Coastguard Worker public final class DoclavaDiff {
43*feeed43cSAndroid Build Coastguard Worker   private final String outputDir;
44*feeed43cSAndroid Build Coastguard Worker   private final JSilver jSilver;
45*feeed43cSAndroid Build Coastguard Worker   private final List<FederatedSite> sites = new ArrayList<FederatedSite>();
46*feeed43cSAndroid Build Coastguard Worker 
main(String[] args)47*feeed43cSAndroid Build Coastguard Worker   public static void main(String[] args) {
48*feeed43cSAndroid Build Coastguard Worker     new DoclavaDiff(args).generateSite();
49*feeed43cSAndroid Build Coastguard Worker   }
50*feeed43cSAndroid Build Coastguard Worker 
DoclavaDiff(String[] args)51*feeed43cSAndroid Build Coastguard Worker   public DoclavaDiff(String[] args) {
52*feeed43cSAndroid Build Coastguard Worker     // TODO: options parsing
53*feeed43cSAndroid Build Coastguard Worker     try {
54*feeed43cSAndroid Build Coastguard Worker       sites.add(new FederatedSite("Android", new URL("http://manatee/doclava/android")));
55*feeed43cSAndroid Build Coastguard Worker       sites.add(new FederatedSite("GWT", new URL("http://manatee/doclava/gwt")));
56*feeed43cSAndroid Build Coastguard Worker       //sites.add(new FederatedSite("Crore", new URL("http://manatee/doclava/crore")));
57*feeed43cSAndroid Build Coastguard Worker       outputDir = "build";
58*feeed43cSAndroid Build Coastguard Worker     } catch (Exception e) {
59*feeed43cSAndroid Build Coastguard Worker       throw new AssertionError(e);
60*feeed43cSAndroid Build Coastguard Worker     }
61*feeed43cSAndroid Build Coastguard Worker 
62*feeed43cSAndroid Build Coastguard Worker     // TODO: accept external templates
63*feeed43cSAndroid Build Coastguard Worker     List<ResourceLoader> resourceLoaders = new ArrayList<ResourceLoader>();
64*feeed43cSAndroid Build Coastguard Worker     resourceLoaders.add(new FileSystemResourceLoader("assets/templates"));
65*feeed43cSAndroid Build Coastguard Worker 
66*feeed43cSAndroid Build Coastguard Worker     ResourceLoader compositeResourceLoader = new CompositeResourceLoader(resourceLoaders);
67*feeed43cSAndroid Build Coastguard Worker     jSilver = new JSilver(compositeResourceLoader);
68*feeed43cSAndroid Build Coastguard Worker   }
69*feeed43cSAndroid Build Coastguard Worker 
generateSite()70*feeed43cSAndroid Build Coastguard Worker   public void generateSite() {
71*feeed43cSAndroid Build Coastguard Worker     Data data = generateHdf();
72*feeed43cSAndroid Build Coastguard Worker     generateHtml("diff.cs", data, new File(outputDir + "/diff.html"));
73*feeed43cSAndroid Build Coastguard Worker   }
74*feeed43cSAndroid Build Coastguard Worker 
75*feeed43cSAndroid Build Coastguard Worker   /**
76*feeed43cSAndroid Build Coastguard Worker    * Creates an HDF with this structure:
77*feeed43cSAndroid Build Coastguard Worker    * <pre>
78*feeed43cSAndroid Build Coastguard Worker    * sites.0.name = projectA
79*feeed43cSAndroid Build Coastguard Worker    * sites.0.url = http://proja.domain.com/reference
80*feeed43cSAndroid Build Coastguard Worker    * sites.1.name = projectB
81*feeed43cSAndroid Build Coastguard Worker    * sites.1.url = http://projb.domain.com
82*feeed43cSAndroid Build Coastguard Worker    * packages.0.name = java.lang
83*feeed43cSAndroid Build Coastguard Worker    * packages.0.sites.0.hasPackage = 1
84*feeed43cSAndroid Build Coastguard Worker    * packages.0.sites.0.link = http://proja.domain.com/reference/java/lang
85*feeed43cSAndroid Build Coastguard Worker    * packages.0.sites.1.hasPackage = 0
86*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.qualifiedName = java.lang.Object
87*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.sites.0.hasClass = 1
88*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.sites.0.link = http://proja.domain.com/reference/java/lang/Object
89*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.sites.1.hasClass = 0
90*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.methods.0.signature = wait()
91*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.methods.0.sites.0.hasMethod = 1
92*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.methods.0.sites.0.link = http://proja.domain.com/reference/java/lang/Object#wait
93*feeed43cSAndroid Build Coastguard Worker    * packages.0.classes.0.methods.0.sites.1.hasMethod = 0
94*feeed43cSAndroid Build Coastguard Worker    * </pre>
95*feeed43cSAndroid Build Coastguard Worker    */
generateHdf()96*feeed43cSAndroid Build Coastguard Worker   private Data generateHdf() {
97*feeed43cSAndroid Build Coastguard Worker     Data data = jSilver.createData();
98*feeed43cSAndroid Build Coastguard Worker 
99*feeed43cSAndroid Build Coastguard Worker     data.setValue("triangle.opened", "../assets/templates/assets/images/triangle-opened.png");
100*feeed43cSAndroid Build Coastguard Worker     data.setValue("triangle.closed", "../assets/templates/assets/images/triangle-closed.png");
101*feeed43cSAndroid Build Coastguard Worker 
102*feeed43cSAndroid Build Coastguard Worker     int i = 0;
103*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
104*feeed43cSAndroid Build Coastguard Worker       String base = "sites." + (i++);
105*feeed43cSAndroid Build Coastguard Worker       data.setValue(base + ".name", site.name());
106*feeed43cSAndroid Build Coastguard Worker       data.setValue(base + ".url", site.baseUrl().toString());
107*feeed43cSAndroid Build Coastguard Worker     }
108*feeed43cSAndroid Build Coastguard Worker 
109*feeed43cSAndroid Build Coastguard Worker     List<String> allPackages = knownPackages(sites);
110*feeed43cSAndroid Build Coastguard Worker 
111*feeed43cSAndroid Build Coastguard Worker     int p = 0;
112*feeed43cSAndroid Build Coastguard Worker     for (String pkg : allPackages) {
113*feeed43cSAndroid Build Coastguard Worker       PackageInfo packageInfo = new PackageInfo(pkg);
114*feeed43cSAndroid Build Coastguard Worker       String packageBase = "packages." + (p++);
115*feeed43cSAndroid Build Coastguard Worker       data.setValue(packageBase + ".name", pkg);
116*feeed43cSAndroid Build Coastguard Worker 
117*feeed43cSAndroid Build Coastguard Worker       int s = 0;
118*feeed43cSAndroid Build Coastguard Worker       for (FederatedSite site : sites) {
119*feeed43cSAndroid Build Coastguard Worker         String siteBase = packageBase + ".sites." + (s++);
120*feeed43cSAndroid Build Coastguard Worker         if (site.apiInfo().getPackages().containsKey(pkg)) {
121*feeed43cSAndroid Build Coastguard Worker           data.setValue(siteBase + ".hasPackage", "1");
122*feeed43cSAndroid Build Coastguard Worker           data.setValue(siteBase + ".link", site.linkFor(packageInfo.htmlPage()));
123*feeed43cSAndroid Build Coastguard Worker         } else {
124*feeed43cSAndroid Build Coastguard Worker           data.setValue(siteBase + ".hasPackage", "0");
125*feeed43cSAndroid Build Coastguard Worker         }
126*feeed43cSAndroid Build Coastguard Worker       }
127*feeed43cSAndroid Build Coastguard Worker 
128*feeed43cSAndroid Build Coastguard Worker       if (packageUniqueToSite(pkg, sites)) {
129*feeed43cSAndroid Build Coastguard Worker         continue;
130*feeed43cSAndroid Build Coastguard Worker       }
131*feeed43cSAndroid Build Coastguard Worker 
132*feeed43cSAndroid Build Coastguard Worker       List<String> packageClasses = knownClassesForPackage(pkg, sites);
133*feeed43cSAndroid Build Coastguard Worker       int c = 0;
134*feeed43cSAndroid Build Coastguard Worker       for (String qualifiedClassName : packageClasses) {
135*feeed43cSAndroid Build Coastguard Worker         String classBase = packageBase + ".classes." + (c++);
136*feeed43cSAndroid Build Coastguard Worker         data.setValue(classBase + ".qualifiedName", qualifiedClassName);
137*feeed43cSAndroid Build Coastguard Worker 
138*feeed43cSAndroid Build Coastguard Worker         s = 0;
139*feeed43cSAndroid Build Coastguard Worker         for (FederatedSite site : sites) {
140*feeed43cSAndroid Build Coastguard Worker           String siteBase = classBase + ".sites." + (s++);
141*feeed43cSAndroid Build Coastguard Worker           ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName);
142*feeed43cSAndroid Build Coastguard Worker           if (classInfo != null) {
143*feeed43cSAndroid Build Coastguard Worker             data.setValue(siteBase + ".hasClass", "1");
144*feeed43cSAndroid Build Coastguard Worker             data.setValue(siteBase + ".link", site.linkFor(classInfo.htmlPage()));
145*feeed43cSAndroid Build Coastguard Worker           } else {
146*feeed43cSAndroid Build Coastguard Worker             data.setValue(siteBase + ".hasClass", "0");
147*feeed43cSAndroid Build Coastguard Worker           }
148*feeed43cSAndroid Build Coastguard Worker         }
149*feeed43cSAndroid Build Coastguard Worker 
150*feeed43cSAndroid Build Coastguard Worker         if (agreeOnClass(qualifiedClassName, sites)) {
151*feeed43cSAndroid Build Coastguard Worker           continue;
152*feeed43cSAndroid Build Coastguard Worker         }
153*feeed43cSAndroid Build Coastguard Worker 
154*feeed43cSAndroid Build Coastguard Worker         if (classUniqueToSite(qualifiedClassName, sites)) {
155*feeed43cSAndroid Build Coastguard Worker           continue;
156*feeed43cSAndroid Build Coastguard Worker         }
157*feeed43cSAndroid Build Coastguard Worker 
158*feeed43cSAndroid Build Coastguard Worker         int m = 0;
159*feeed43cSAndroid Build Coastguard Worker         List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites);
160*feeed43cSAndroid Build Coastguard Worker         for (MethodInfo method : methods) {
161*feeed43cSAndroid Build Coastguard Worker           if (agreeOnMethod(qualifiedClassName, method, sites)) {
162*feeed43cSAndroid Build Coastguard Worker             continue;
163*feeed43cSAndroid Build Coastguard Worker           }
164*feeed43cSAndroid Build Coastguard Worker 
165*feeed43cSAndroid Build Coastguard Worker           String methodBase = classBase + ".methods." + (m++);
166*feeed43cSAndroid Build Coastguard Worker           data.setValue(methodBase + ".signature", method.prettySignature());
167*feeed43cSAndroid Build Coastguard Worker           int k = 0;
168*feeed43cSAndroid Build Coastguard Worker           for (FederatedSite site : sites) {
169*feeed43cSAndroid Build Coastguard Worker             String siteBase = methodBase + ".sites." + (k++);
170*feeed43cSAndroid Build Coastguard Worker             if (site.apiInfo().findClass(qualifiedClassName) == null) {
171*feeed43cSAndroid Build Coastguard Worker               data.setValue(siteBase + ".hasMethod", "0");
172*feeed43cSAndroid Build Coastguard Worker               continue;
173*feeed43cSAndroid Build Coastguard Worker             }
174*feeed43cSAndroid Build Coastguard Worker             Map<String,MethodInfo> siteMethods
175*feeed43cSAndroid Build Coastguard Worker                 = site.apiInfo().findClass(qualifiedClassName).allMethods();
176*feeed43cSAndroid Build Coastguard Worker             if (siteMethods.containsKey(method.getHashableName())) {
177*feeed43cSAndroid Build Coastguard Worker               data.setValue(siteBase + ".hasMethod", "1");
178*feeed43cSAndroid Build Coastguard Worker               data.setValue(siteBase + ".link", site.linkFor(method.htmlPage()));
179*feeed43cSAndroid Build Coastguard Worker             } else {
180*feeed43cSAndroid Build Coastguard Worker               data.setValue(siteBase + ".hasMethod", "0");
181*feeed43cSAndroid Build Coastguard Worker             }
182*feeed43cSAndroid Build Coastguard Worker           }
183*feeed43cSAndroid Build Coastguard Worker         }
184*feeed43cSAndroid Build Coastguard Worker       }
185*feeed43cSAndroid Build Coastguard Worker     }
186*feeed43cSAndroid Build Coastguard Worker 
187*feeed43cSAndroid Build Coastguard Worker     return data;
188*feeed43cSAndroid Build Coastguard Worker   }
189*feeed43cSAndroid Build Coastguard Worker 
190*feeed43cSAndroid Build Coastguard Worker   /**
191*feeed43cSAndroid Build Coastguard Worker    * Returns a list of all known packages from all sites.
192*feeed43cSAndroid Build Coastguard Worker    */
knownPackages(List<FederatedSite> sites)193*feeed43cSAndroid Build Coastguard Worker   private List<String> knownPackages(List<FederatedSite> sites) {
194*feeed43cSAndroid Build Coastguard Worker     Set<String> allPackages = new LinkedHashSet<String>();
195*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
196*feeed43cSAndroid Build Coastguard Worker       Map<String, PackageInfo> packages = site.apiInfo().getPackages();
197*feeed43cSAndroid Build Coastguard Worker       for (String pkg : packages.keySet()) {
198*feeed43cSAndroid Build Coastguard Worker         allPackages.add(pkg);
199*feeed43cSAndroid Build Coastguard Worker       }
200*feeed43cSAndroid Build Coastguard Worker     }
201*feeed43cSAndroid Build Coastguard Worker 
202*feeed43cSAndroid Build Coastguard Worker     List<String> packages = new ArrayList<String>(allPackages);
203*feeed43cSAndroid Build Coastguard Worker     Collections.sort(packages);
204*feeed43cSAndroid Build Coastguard Worker     return packages;
205*feeed43cSAndroid Build Coastguard Worker   }
206*feeed43cSAndroid Build Coastguard Worker 
207*feeed43cSAndroid Build Coastguard Worker   /**
208*feeed43cSAndroid Build Coastguard Worker    * Returns all known classes from all sites for a given package.
209*feeed43cSAndroid Build Coastguard Worker    */
knownClassesForPackage(String pkg, List<FederatedSite> sites)210*feeed43cSAndroid Build Coastguard Worker   private List<String> knownClassesForPackage(String pkg, List<FederatedSite> sites) {
211*feeed43cSAndroid Build Coastguard Worker     Set<String> allClasses = new LinkedHashSet<String>();
212*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
213*feeed43cSAndroid Build Coastguard Worker       PackageInfo packageInfo = site.apiInfo().getPackages().get(pkg);
214*feeed43cSAndroid Build Coastguard Worker       if (packageInfo == null) {
215*feeed43cSAndroid Build Coastguard Worker         continue;
216*feeed43cSAndroid Build Coastguard Worker       }
217*feeed43cSAndroid Build Coastguard Worker       HashMap<String, ClassInfo> classes = packageInfo.allClasses();
218*feeed43cSAndroid Build Coastguard Worker       for (Map.Entry<String, ClassInfo> entry : classes.entrySet()) {
219*feeed43cSAndroid Build Coastguard Worker         allClasses.add(entry.getValue().qualifiedName());
220*feeed43cSAndroid Build Coastguard Worker       }
221*feeed43cSAndroid Build Coastguard Worker     }
222*feeed43cSAndroid Build Coastguard Worker 
223*feeed43cSAndroid Build Coastguard Worker     List<String> classes = new ArrayList<String>(allClasses);
224*feeed43cSAndroid Build Coastguard Worker     Collections.sort(classes);
225*feeed43cSAndroid Build Coastguard Worker     return classes;
226*feeed43cSAndroid Build Coastguard Worker   }
227*feeed43cSAndroid Build Coastguard Worker 
228*feeed43cSAndroid Build Coastguard Worker   /**
229*feeed43cSAndroid Build Coastguard Worker    * Returns all known methods from all sites for a given class.
230*feeed43cSAndroid Build Coastguard Worker    */
knownMethodsForClass(String qualifiedClassName, List<FederatedSite> sites)231*feeed43cSAndroid Build Coastguard Worker   private List<MethodInfo> knownMethodsForClass(String qualifiedClassName,
232*feeed43cSAndroid Build Coastguard Worker       List<FederatedSite> sites) {
233*feeed43cSAndroid Build Coastguard Worker 
234*feeed43cSAndroid Build Coastguard Worker     Map<String, MethodInfo> allMethods = new HashMap<String, MethodInfo>();
235*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
236*feeed43cSAndroid Build Coastguard Worker       ClassInfo classInfo = site.apiInfo().findClass(qualifiedClassName);
237*feeed43cSAndroid Build Coastguard Worker       if (classInfo == null) {
238*feeed43cSAndroid Build Coastguard Worker         continue;
239*feeed43cSAndroid Build Coastguard Worker       }
240*feeed43cSAndroid Build Coastguard Worker 
241*feeed43cSAndroid Build Coastguard Worker       for (Map.Entry<String, MethodInfo> entry: classInfo.allMethods().entrySet()) {
242*feeed43cSAndroid Build Coastguard Worker         allMethods.put(entry.getKey(), entry.getValue());
243*feeed43cSAndroid Build Coastguard Worker       }
244*feeed43cSAndroid Build Coastguard Worker     }
245*feeed43cSAndroid Build Coastguard Worker 
246*feeed43cSAndroid Build Coastguard Worker     List<MethodInfo> methods = new ArrayList<MethodInfo>();
247*feeed43cSAndroid Build Coastguard Worker     methods.addAll(allMethods.values());
248*feeed43cSAndroid Build Coastguard Worker     return methods;
249*feeed43cSAndroid Build Coastguard Worker   }
250*feeed43cSAndroid Build Coastguard Worker 
251*feeed43cSAndroid Build Coastguard Worker   /**
252*feeed43cSAndroid Build Coastguard Worker    * Returns true if the list of sites all completely agree on the given
253*feeed43cSAndroid Build Coastguard Worker    * package. All sites must possess the package, all classes it contains, and
254*feeed43cSAndroid Build Coastguard Worker    * all methods of each class.
255*feeed43cSAndroid Build Coastguard Worker    */
agreeOnPackage(String pkg, List<FederatedSite> sites)256*feeed43cSAndroid Build Coastguard Worker   private boolean agreeOnPackage(String pkg, List<FederatedSite> sites) {
257*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
258*feeed43cSAndroid Build Coastguard Worker       if (site.apiInfo().getPackages().get(pkg) == null) {
259*feeed43cSAndroid Build Coastguard Worker         return false;
260*feeed43cSAndroid Build Coastguard Worker       }
261*feeed43cSAndroid Build Coastguard Worker     }
262*feeed43cSAndroid Build Coastguard Worker 
263*feeed43cSAndroid Build Coastguard Worker     List<String> classes = knownClassesForPackage(pkg, sites);
264*feeed43cSAndroid Build Coastguard Worker     for (String clazz : classes) {
265*feeed43cSAndroid Build Coastguard Worker       if (!agreeOnClass(clazz, sites)) {
266*feeed43cSAndroid Build Coastguard Worker         return false;
267*feeed43cSAndroid Build Coastguard Worker       }
268*feeed43cSAndroid Build Coastguard Worker     }
269*feeed43cSAndroid Build Coastguard Worker     return true;
270*feeed43cSAndroid Build Coastguard Worker   }
271*feeed43cSAndroid Build Coastguard Worker 
272*feeed43cSAndroid Build Coastguard Worker   /**
273*feeed43cSAndroid Build Coastguard Worker    * Returns true if the list of sites all agree on the given class. Each site
274*feeed43cSAndroid Build Coastguard Worker    * must have the class and agree on its methods.
275*feeed43cSAndroid Build Coastguard Worker    */
agreeOnClass(String qualifiedClassName, List<FederatedSite> sites)276*feeed43cSAndroid Build Coastguard Worker   private boolean agreeOnClass(String qualifiedClassName, List<FederatedSite> sites) {
277*feeed43cSAndroid Build Coastguard Worker     List<MethodInfo> methods = knownMethodsForClass(qualifiedClassName, sites);
278*feeed43cSAndroid Build Coastguard Worker     for (MethodInfo method : methods) {
279*feeed43cSAndroid Build Coastguard Worker       if (!agreeOnMethod(qualifiedClassName, method, sites)) {
280*feeed43cSAndroid Build Coastguard Worker         return false;
281*feeed43cSAndroid Build Coastguard Worker       }
282*feeed43cSAndroid Build Coastguard Worker     }
283*feeed43cSAndroid Build Coastguard Worker     return true;
284*feeed43cSAndroid Build Coastguard Worker   }
285*feeed43cSAndroid Build Coastguard Worker 
286*feeed43cSAndroid Build Coastguard Worker   /**
287*feeed43cSAndroid Build Coastguard Worker    * Returns true if the list of sites all contain the given method.
288*feeed43cSAndroid Build Coastguard Worker    */
agreeOnMethod(String qualifiedClassName, MethodInfo method, List<FederatedSite> sites)289*feeed43cSAndroid Build Coastguard Worker   private boolean agreeOnMethod(String qualifiedClassName, MethodInfo method,
290*feeed43cSAndroid Build Coastguard Worker       List<FederatedSite> sites) {
291*feeed43cSAndroid Build Coastguard Worker 
292*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
293*feeed43cSAndroid Build Coastguard Worker       ClassInfo siteClass = site.apiInfo().findClass(qualifiedClassName);
294*feeed43cSAndroid Build Coastguard Worker       if (siteClass == null) {
295*feeed43cSAndroid Build Coastguard Worker         return false;
296*feeed43cSAndroid Build Coastguard Worker       }
297*feeed43cSAndroid Build Coastguard Worker 
298*feeed43cSAndroid Build Coastguard Worker       if (!siteClass.supportsMethod(method)) {
299*feeed43cSAndroid Build Coastguard Worker         return false;
300*feeed43cSAndroid Build Coastguard Worker       }
301*feeed43cSAndroid Build Coastguard Worker     }
302*feeed43cSAndroid Build Coastguard Worker     return true;
303*feeed43cSAndroid Build Coastguard Worker   }
304*feeed43cSAndroid Build Coastguard Worker 
305*feeed43cSAndroid Build Coastguard Worker   /**
306*feeed43cSAndroid Build Coastguard Worker    * Returns true if the given package is known to exactly one of the given sites.
307*feeed43cSAndroid Build Coastguard Worker    */
packageUniqueToSite(String pkg, List<FederatedSite> sites)308*feeed43cSAndroid Build Coastguard Worker   private boolean packageUniqueToSite(String pkg, List<FederatedSite> sites) {
309*feeed43cSAndroid Build Coastguard Worker     int numSites = 0;
310*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
311*feeed43cSAndroid Build Coastguard Worker       if (site.apiInfo().getPackages().containsKey(pkg)) {
312*feeed43cSAndroid Build Coastguard Worker         numSites++;
313*feeed43cSAndroid Build Coastguard Worker       }
314*feeed43cSAndroid Build Coastguard Worker     }
315*feeed43cSAndroid Build Coastguard Worker     return numSites == 1;
316*feeed43cSAndroid Build Coastguard Worker   }
317*feeed43cSAndroid Build Coastguard Worker 
318*feeed43cSAndroid Build Coastguard Worker   /**
319*feeed43cSAndroid Build Coastguard Worker    * Returns true if the given class is known to exactly one of the given sites.
320*feeed43cSAndroid Build Coastguard Worker    */
classUniqueToSite(String qualifiedClassName, List<FederatedSite> sites)321*feeed43cSAndroid Build Coastguard Worker   private boolean classUniqueToSite(String qualifiedClassName, List<FederatedSite> sites) {
322*feeed43cSAndroid Build Coastguard Worker     int numSites = 0;
323*feeed43cSAndroid Build Coastguard Worker     for (FederatedSite site : sites) {
324*feeed43cSAndroid Build Coastguard Worker       if (site.apiInfo().findClass(qualifiedClassName) != null) {
325*feeed43cSAndroid Build Coastguard Worker         numSites++;
326*feeed43cSAndroid Build Coastguard Worker       }
327*feeed43cSAndroid Build Coastguard Worker     }
328*feeed43cSAndroid Build Coastguard Worker     return numSites == 1;
329*feeed43cSAndroid Build Coastguard Worker   }
330*feeed43cSAndroid Build Coastguard Worker 
generateHtml(String template, Data data, File file)331*feeed43cSAndroid Build Coastguard Worker   private void generateHtml(String template, Data data, File file) {
332*feeed43cSAndroid Build Coastguard Worker     ClearPage.ensureDirectory(file);
333*feeed43cSAndroid Build Coastguard Worker 
334*feeed43cSAndroid Build Coastguard Worker     OutputStreamWriter stream = null;
335*feeed43cSAndroid Build Coastguard Worker     try {
336*feeed43cSAndroid Build Coastguard Worker       stream = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
337*feeed43cSAndroid Build Coastguard Worker       String rendered = jSilver.render(template, data);
338*feeed43cSAndroid Build Coastguard Worker       stream.write(rendered, 0, rendered.length());
339*feeed43cSAndroid Build Coastguard Worker     } catch (IOException e) {
340*feeed43cSAndroid Build Coastguard Worker       System.out.println("error: " + e.getMessage() + "; when writing file: " + file.getAbsolutePath());
341*feeed43cSAndroid Build Coastguard Worker     } finally {
342*feeed43cSAndroid Build Coastguard Worker       if (stream != null) {
343*feeed43cSAndroid Build Coastguard Worker         try {
344*feeed43cSAndroid Build Coastguard Worker           stream.close();
345*feeed43cSAndroid Build Coastguard Worker         } catch (IOException ignored) {}
346*feeed43cSAndroid Build Coastguard Worker       }
347*feeed43cSAndroid Build Coastguard Worker     }
348*feeed43cSAndroid Build Coastguard Worker   }
349*feeed43cSAndroid Build Coastguard Worker }
350