1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.tools.plugin.javadoc;
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.net.URI;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Optional;
31 import java.util.regex.Pattern;
32
33 import org.apache.maven.settings.Settings;
34 import org.codehaus.plexus.languages.java.version.JavaVersion;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43 public class JavadocLinkGenerator {
44
45
46
47
48 public enum JavadocToolVersionRange {
49 JDK7_OR_LOWER(null, JavaVersion.parse("1.8")),
50 JDK8_OR_9(JavaVersion.parse("1.8"), JavaVersion.parse("10")),
51 JDK10_OR_HIGHER(JavaVersion.parse("10"), null);
52
53
54 private final JavaVersion lowerBound;
55 private final JavaVersion upperBound;
56
57 JavadocToolVersionRange(JavaVersion lowerBound, JavaVersion upperBound) {
58 this.lowerBound = lowerBound;
59 this.upperBound = upperBound;
60 }
61
62 static JavadocToolVersionRange findMatch(JavaVersion javadocVersion) {
63 for (JavadocToolVersionRange range : values()) {
64 if ((range.lowerBound == null || javadocVersion.isAtLeast(range.lowerBound))
65 && (range.upperBound == null || javadocVersion.isBefore(range.upperBound))) {
66 return range;
67 }
68 }
69 throw new IllegalArgumentException("Found no matching javadoc tool version range for " + javadocVersion);
70 }
71 }
72
73 private static final Logger LOG = LoggerFactory.getLogger(JavadocLinkGenerator.class);
74 private final List<JavadocSite> externalJavadocSites;
75 private final JavadocSite internalJavadocSite;
76
77
78
79
80
81
82
83
84 public JavadocLinkGenerator(URI internalJavadocSiteUrl, String internalJavadocVersion) {
85 this(internalJavadocSiteUrl, internalJavadocVersion, Collections.emptyList(), null);
86 }
87
88
89
90
91
92
93
94 public JavadocLinkGenerator(List<URI> externalJavadocSiteUrls, Settings settings) {
95 this(null, null, externalJavadocSiteUrls, settings);
96 }
97
98
99
100
101
102
103
104
105
106 public JavadocLinkGenerator(
107 URI internalJavadocSiteUrl,
108 String internalJavadocVersion,
109 List<URI> externalJavadocSiteUrls,
110 Settings settings) {
111 if (internalJavadocSiteUrl != null) {
112
113 JavaVersion javadocVersion = JavaVersion.parse(internalJavadocVersion);
114 internalJavadocSite =
115 new JavadocSite(internalJavadocSiteUrl, JavadocToolVersionRange.findMatch(javadocVersion), false);
116 } else {
117 internalJavadocSite = null;
118 }
119 if (externalJavadocSiteUrls != null) {
120 externalJavadocSites = new ArrayList<>(externalJavadocSiteUrls.size());
121 for (URI siteUrl : externalJavadocSiteUrls) {
122 try {
123 externalJavadocSites.add(new JavadocSite(siteUrl, settings));
124 } catch (IOException e) {
125 LOG.warn("Could not use {} as base URL: {}", siteUrl, e.getMessage(), e);
126 }
127 }
128 } else {
129 externalJavadocSites = Collections.emptyList();
130 }
131 if (internalJavadocSite == null && externalJavadocSites.isEmpty()) {
132 throw new IllegalArgumentException(
133 "Either internal or at least one accessible external javadoc " + "URLs must be given!");
134 }
135 }
136
137
138
139
140
141
142
143
144
145
146
147 public URI createLink(FullyQualifiedJavadocReference javadocReference) {
148 if (!javadocReference.isExternal() && internalJavadocSite != null) {
149 return internalJavadocSite.createLink(javadocReference);
150 } else {
151 JavadocSite javadocSite = externalJavadocSites.stream()
152 .filter(base ->
153 base.hasEntryFor(javadocReference.getModuleName(), javadocReference.getPackageName()))
154 .findFirst()
155 .orElseThrow(() -> new IllegalArgumentException("Found no javadoc site for " + javadocReference));
156 return javadocSite.createLink(javadocReference);
157 }
158 }
159
160
161
162
163
164
165
166
167
168
169 public URI createLink(String binaryName) {
170 Map.Entry<String, String> packageAndClassName = JavadocSite.getPackageAndClassName(binaryName);
171
172 JavadocSite javadocSite = externalJavadocSites.stream()
173 .filter(base -> base.hasEntryFor(Optional.empty(), Optional.of(packageAndClassName.getKey())))
174 .findFirst()
175 .orElse(null);
176 if (javadocSite == null) {
177 if (internalJavadocSite != null) {
178 javadocSite = internalJavadocSite;
179 } else {
180 throw new IllegalArgumentException("Found no javadoc site for " + binaryName);
181 }
182 }
183 return javadocSite.createLink(packageAndClassName.getKey(), packageAndClassName.getValue());
184 }
185
186 public URI getInternalJavadocSiteBaseUrl() {
187 if (internalJavadocSite == null) {
188 throw new IllegalStateException("Could not get docroot of internal javadoc as it hasn't been set");
189 }
190 return internalJavadocSite.getBaseUri();
191 }
192
193
194
195
196
197
198
199
200
201 public static boolean isLinkValid(URI url, Path baseDirectory) {
202 if (url.isAbsolute()) {
203 try (BufferedReader reader = JavadocSite.getReader(url.toURL(), null)) {
204 if (url.getFragment() != null) {
205 Pattern pattern = JavadocSite.getAnchorPattern(url.getFragment());
206 if (reader.lines().noneMatch(pattern.asPredicate())) {
207 return false;
208 }
209 }
210 } catch (IOException e) {
211 return false;
212 }
213 return true;
214 } else {
215 Path file = baseDirectory.resolve(url.getPath());
216 boolean exists = Files.exists(file);
217 if (!exists) {
218 LOG.debug("Could not find file given through '{}' in resolved path '{}'", url, file);
219 }
220 return exists;
221 }
222 }
223 }