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