| // *************************************************************************************************************************** |
| // * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * |
| // * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * |
| // * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * |
| // * with the License. You may obtain a copy of the License at * |
| // * * |
| // * http://www.apache.org/licenses/LICENSE-2.0 * |
| // * * |
| // * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * |
| // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * |
| // * specific language governing permissions and limitations under the License. * |
| // *************************************************************************************************************************** |
| package org.apache.juneau.doc.internal; |
| |
| import static org.apache.juneau.doc.internal.Console.*; |
| |
| import java.io.*; |
| import java.util.*; |
| import java.util.regex.*; |
| |
| /** |
| * Javadoc link checker. |
| * |
| * <p> |
| * Runs against the generated javadocs folder looking for any broken internal links (missing files, invalid anchor tags, etc...). |
| */ |
| public class DocLinkTester { |
| |
| private static Map<String,Set<String>> ANCHORS = new LinkedHashMap<>(); |
| private static Pattern p = Pattern.compile("(href|src)\\=['\\\"]([^'\\\"]+)['\\\"]"); |
| private static Pattern p2 = Pattern.compile("(name|id)\\=['\\\"]([^'\\\"]+)['\\\"]"); |
| private static int errors, files, directories, links; |
| private static Map<String,File> docFiles = new HashMap<>(); |
| |
| |
| /** |
| * Entry point. |
| * |
| * @param args Not used |
| */ |
| public static void main(String[] args) { |
| try { |
| long startTime = System.currentTimeMillis(); |
| File root = new File("../target/site/apidocs").getCanonicalFile(); |
| for (File fc : new File(root, "doc-files").listFiles()) |
| docFiles.put(fc.getAbsolutePath(), fc); |
| info("Checking links in {0}", root); |
| process(root); |
| for (String df : new TreeMap<>(docFiles).keySet()) |
| error(docFiles.get(df), "unused"); |
| info("Checked {0} links in {1} files in {2} directories in {3}ms", links, files, directories, System.currentTimeMillis()-startTime); |
| if (errors == 0) |
| info("No link errors"); |
| else { |
| Console.error(errors + " errors"); // NOT DEBUG |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| private static void process(File dir) throws Exception { |
| if (dir.isDirectory()) { |
| for (File fc : dir.listFiles()) { |
| if (fc.isFile() && fc.getName().endsWith(".html")) { |
| files++; |
| resolveLinks(fc); |
| } |
| } |
| for (File fc : dir.listFiles()) { |
| if (fc.isDirectory() && ! fc.getName().equals("src-html")) { |
| directories++; |
| process(fc); |
| } |
| } |
| } |
| } |
| |
| private static boolean hasAnchor(File f, String anchor) throws Exception { |
| String key = f.getCanonicalPath(); |
| if (! ANCHORS.containsKey(key)) { |
| Set<String> s = new HashSet<>(); |
| String c2 = IOUtils.read(f); |
| Matcher m2 = p2.matcher(c2); |
| while (m2.find()) { |
| s.add(m2.group(2)); |
| } |
| ANCHORS.put(key, s); |
| } |
| return ANCHORS.get(key).contains(anchor); |
| } |
| |
| private static void resolveLinks(File f) throws Exception { |
| String contents = IOUtils.read(f); |
| Matcher m = p.matcher(contents); |
| while (m.find()) { |
| String link = m.group(2); |
| String anchor = null; |
| if (link.startsWith("https://") || link.startsWith("http://") || link.startsWith("mailto:") || link.startsWith("javascript:") || link.startsWith("$") || link.startsWith("{OVERVIEW_URL}")) |
| continue; |
| links++; |
| if (link.indexOf('?') != -1) |
| link = link.substring(0, link.indexOf('?')); |
| |
| if (link.indexOf('#') != -1) { |
| anchor = link.substring(link.lastIndexOf('#')+1); |
| link = link.substring(0, link.lastIndexOf('#')); |
| } |
| File f2 = link.isEmpty() ? f : new File(f.getParentFile().getAbsolutePath() + "/" + link); |
| if (! f2.exists()) { |
| error(f, "missingLink=["+link+"]"); |
| } else if (anchor != null) { |
| if (f2.isFile()) { |
| boolean foundAnchor = hasAnchor(f2, anchor); |
| if (! foundAnchor) |
| error(f, "missingAnchor=["+link+"#"+anchor+"]"); |
| } else { |
| error(f, "invalidAnchor=["+link+"#"+anchor+"]"); |
| } |
| } else { |
| docFiles.remove(f2.getAbsolutePath()); |
| } |
| } |
| } |
| |
| private static void error(File f, String msg) { |
| errors++; |
| Console.error("{0}: {1}", f.getAbsolutePath(), msg); |
| } |
| } |