• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Arrays;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 
28 /**
29  * Cross-references documentation among different libraries. A FederationTagger
30  * is populated with a list of {@link FederatedSite} objects which are linked
31  * against when overlapping content is discovered.
32  */
33 public final class FederationTagger {
34   private final Map<String, URL> federatedUrls = new HashMap<>();
35   private final Map<String, String> federatedXmls = new HashMap<>();
36   private final List<FederatedSite> federatedSites = new ArrayList<>();
37 
38   private boolean initialized = false;
39 
40   /**
41    * Adds a Doclava documentation site for federation. Accepts the base URL of
42    * the remote API.
43    * <p>
44    * If {@link #addSiteApi(String, String)} is not called, this will default to
45    * reading the API from "/xml/current.xml" within the site's base URL.
46    * <p>
47    * <strong>Note:</strong> Must be called before calling tag() or get() methods.
48    *
49    * @param name internally-used name for federation site
50    */
addSiteUrl(String name, URL site)51   public void addSiteUrl(String name, URL site) {
52     if (initialized) {
53       throw new IllegalStateException("Cannot add sites after calling tag() or get() methods.");
54     }
55     federatedUrls.put(name, site);
56   }
57 
58   /**
59    * Adds an explicit Doclava-generated API file for the specified site.
60    * <p>
61    * <strong>Note:</strong> Must be called before calling tag() or get() methods.
62    *
63    * @param name internally-used name for federation site (must match name used
64    *             for {@link #addSiteUrl(String, URL)})
65    * @param file path to a Doclava-generated API file
66    */
addSiteApi(String name, String file)67   public void addSiteApi(String name, String file) {
68     if (initialized) {
69       throw new IllegalStateException("Cannot add sites after calling tag() or get() methods.");
70     }
71     federatedXmls.put(name, file);
72   }
73 
tag(ClassInfo classDoc)74   public void tag(ClassInfo classDoc) {
75     initialize();
76     for (FederatedSite site : federatedSites) {
77       applyFederation(site, Arrays.asList(classDoc));
78     }
79   }
80 
tagAll(Collection<ClassInfo> classDocs)81   public void tagAll(Collection<ClassInfo> classDocs) {
82     initialize();
83     for (FederatedSite site : federatedSites) {
84       applyFederation(site, classDocs);
85     }
86   }
87 
88   /**
89    * Returns a non-{@code null} list of {@link FederatedSite} objects, one for
90    * each unique {@code name} added using {@link #addSiteUrl(String, URL)}.
91    */
getSites()92   public List<FederatedSite> getSites() {
93     initialize();
94     return federatedSites;
95   }
96 
initialize()97   private void initialize() {
98     if (initialized) {
99       return;
100     }
101 
102     for (String name : federatedXmls.keySet()) {
103       if (!federatedUrls.containsKey(name)) {
104         Errors.error(Errors.NO_FEDERATION_DATA, (SourcePositionInfo) null,
105             "Unknown documentation site for " + name);
106       }
107     }
108 
109     for (String name : federatedUrls.keySet()) {
110       try {
111         if (federatedXmls.containsKey(name)) {
112           federatedSites.add(new FederatedSite(name, federatedUrls.get(name),
113               federatedXmls.get(name)));
114         } else {
115           federatedSites.add(new FederatedSite(name, federatedUrls.get(name)));
116         }
117       } catch (ApiParseException e) {
118         String error = "Could not add site for federation: " + name;
119         if (e.getMessage() != null) {
120           error += ": " + e.getMessage();
121         }
122         Errors.error(Errors.NO_FEDERATION_DATA, (SourcePositionInfo) null, error);
123       }
124     }
125 
126     initialized = true;
127   }
128 
applyFederation(FederatedSite federationSource, Collection<ClassInfo> classDocs)129   private void applyFederation(FederatedSite federationSource, Collection<ClassInfo> classDocs) {
130     for (ClassInfo classDoc : classDocs) {
131       PackageInfo packageSpec
132           = federationSource.apiInfo().getPackages().get(classDoc.containingPackage().name());
133 
134       if (packageSpec == null) {
135         continue;
136       }
137 
138       ClassInfo classSpec = packageSpec.allClasses().get(classDoc.name());
139 
140       if (classSpec == null) {
141         continue;
142       }
143 
144       federateMethods(federationSource, classSpec, classDoc);
145       federateConstructors(federationSource, classSpec, classDoc);
146       federateFields(federationSource, classSpec, classDoc);
147       federateClass(federationSource, classDoc);
148       federatePackage(federationSource, classDoc.containingPackage());
149     }
150   }
151 
federateMethods(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)152   private void federateMethods(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
153     for (MethodInfo method : localClass.methods()) {
154       for (ClassInfo superclass : federatedClass.hierarchy()) {
155         if (superclass.allMethods().containsKey(method.getHashableName())) {
156           method.addFederatedReference(site);
157           break;
158         }
159       }
160     }
161   }
162 
federateConstructors(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)163   private void federateConstructors(FederatedSite site, ClassInfo federatedClass,
164       ClassInfo localClass) {
165     for (MethodInfo constructor : localClass.constructors()) {
166       if (federatedClass.hasConstructor(constructor)) {
167         constructor.addFederatedReference(site);
168       }
169     }
170   }
171 
federateFields(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass)172   private void federateFields(FederatedSite site, ClassInfo federatedClass, ClassInfo localClass) {
173     for (FieldInfo field : localClass.fields()) {
174       if (federatedClass.allFields().containsKey(field.name())) {
175         field.addFederatedReference(site);
176       }
177     }
178   }
179 
federateClass(FederatedSite source, ClassInfo doc)180   private void federateClass(FederatedSite source, ClassInfo doc) {
181     doc.addFederatedReference(source);
182   }
183 
federatePackage(FederatedSite source, PackageInfo pkg)184   private void federatePackage(FederatedSite source, PackageInfo pkg) {
185     pkg.addFederatedReference(source);
186   }
187 }
188