1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.doclava;
18 
19 import com.google.doclava.apicheck.ApiParseException;
20 import java.net.URL;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 
26 /**
27  * Cross-references documentation among different libraries. A FederationTagger
28  * is populated with a list of {@link FederatedSite} objects which are linked
29  * against when overlapping content is discovered.
30  */
31 public final class FederationTagger {
32   private final Map<String, URL> federatedUrls = new HashMap<String, URL>();
33   private final Map<String, String> federatedXmls = new HashMap<String, String>();
34   private final List<FederatedSite> federatedSites = new ArrayList<FederatedSite>();
35   private boolean initialized = false;
36   /**
37    * Adds a Doclava documentation site for federation. Accepts the base URL of
38    * the remote API.
39    */
addSiteUrl(String name, URL site)40   public void addSiteUrl(String name, URL site) {
41     federatedUrls.put(name, site);
42   }
43 
addSiteApi(String name, String file)44   public void addSiteApi(String name, String file) {
45     federatedXmls.put(name, file);
46   }
47 
tag(ClassInfo classDoc)48   public void tag(ClassInfo classDoc) {
49     initialize();
50     for (FederatedSite site : federatedSites) {
51       applyFederation(site, new ClassInfo[] { classDoc });
52     }
53   }
54 
tagAll(ClassInfo[] classDocs)55   public void tagAll(ClassInfo[] classDocs) {
56     initialize();
57     for (FederatedSite site : federatedSites) {
58       applyFederation(site, classDocs);
59     }
60   }
61 
initialize()62   private void initialize() {
63     if (initialized) {
64       return;
65     }
66 
67     for (String name : federatedXmls.keySet()) {
68       if (!federatedUrls.containsKey(name)) {
69         Errors.error(Errors.NO_FEDERATION_DATA, null, "Unknown documentation site for " + name);
70       }
71     }
72 
73     for (String name : federatedUrls.keySet()) {
74       try {
75         if (federatedXmls.containsKey(name)) {
76           federatedSites.add(new FederatedSite(name, federatedUrls.get(name),
77               federatedXmls.get(name)));
78         } else {
79           federatedSites.add(new FederatedSite(name, federatedUrls.get(name)));
80         }
81       } catch (ApiParseException e) {
82         String error = "Could not add site for federation: " + name;
83         if (e.getMessage() != null) {
84           error += ": " + e.getMessage();
85         }
86         Errors.error(Errors.NO_FEDERATION_DATA, null, error);
87       }
88     }
89 
90     initialized = true;
91   }
92 
applyFederation(FederatedSite federationSource, ClassInfo[] classDocs)93   private void applyFederation(FederatedSite federationSource, ClassInfo[] classDocs) {
94     for (ClassInfo classDoc : classDocs) {
95       PackageInfo packageSpec
96           = federationSource.apiInfo().getPackages().get(classDoc.containingPackage().name());
97 
98       if (packageSpec == null) {
99         continue;
100       }
101 
102       ClassInfo classSpec = packageSpec.allClasses().get(classDoc.name());
103 
104       if (classSpec == null) {
105         continue;
106       }
107 
108       federateMethods(federationSource, classSpec, classDoc);
109       federateConstructors(federationSource, classSpec, classDoc);
110       federateFields(federationSource, classSpec, classDoc);
111       federateClass(federationSource, classDoc);
112       federatePackage(federationSource, classDoc.containingPackage());
113     }
114   }
115 
federateMethods(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)116   private void federateMethods(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
117     for (MethodInfo method : localClass.methods()) {
118       for (ClassInfo superclass : federatedClass.hierarchy()) {
119         if (superclass.allMethods().containsKey(method.getHashableName())) {
120           method.addFederatedReference(site);
121           break;
122         }
123       }
124     }
125   }
126 
federateConstructors(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)127   private void federateConstructors(FederatedSite site, ClassInfo federatedClass,
128       ClassInfo localClass) {
129     for (MethodInfo constructor : localClass.constructors()) {
130       if (federatedClass.hasConstructor(constructor)) {
131         constructor.addFederatedReference(site);
132       }
133     }
134   }
135 
federateFields(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)136   private void federateFields(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
137     for (FieldInfo field : localClass.fields()) {
138       if (federatedClass.allFields().containsKey(field.name())) {
139         field.addFederatedReference(site);
140       }
141     }
142   }
143 
federateClass(FederatedSite source, ClassInfo doc)144   private void federateClass(FederatedSite source, ClassInfo doc) {
145     doc.addFederatedReference(source);
146   }
147 
federatePackage(FederatedSite source, PackageInfo pkg)148   private void federatePackage(FederatedSite source, PackageInfo pkg) {
149     pkg.addFederatedReference(source);
150   }
151 }