001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: * Initial Developer: H2 Group
005: */
006: package org.h2.tools.doc;
007:
008: import java.io.File;
009: import java.io.FileReader;
010: import java.util.ArrayList;
011: import java.util.Collections;
012: import java.util.HashMap;
013: import java.util.Iterator;
014:
015: import org.h2.util.IOUtils;
016: import org.h2.util.StartBrowser;
017: import org.h2.util.StringUtils;
018:
019: /**
020: * The link checker makes sure that each link in the documentation
021: * points to an existing target.
022: */
023: public class LinkChecker {
024:
025: private static final boolean OPEN_EXTERNAL_LINKS = false;
026: private static final String[] IGNORE_MISSING_LINKS_TO = new String[] {
027: "SysProperties", "ErrorCode" };
028:
029: public static void main(String[] args) throws Exception {
030: new LinkChecker().run(args);
031: }
032:
033: private HashMap targets = new HashMap();
034: private HashMap links = new HashMap();
035:
036: private void run(String[] args) throws Exception {
037: String dir = "docs";
038: for (int i = 0; i < args.length; i++) {
039: if ("-dir".equals(args[i])) {
040: dir = args[++i];
041: }
042: }
043: process(dir);
044: listExternalLinks();
045: listBadLinks();
046: }
047:
048: void listExternalLinks() {
049: for (Iterator it = links.keySet().iterator(); it.hasNext();) {
050: String link = (String) it.next();
051: if (link.startsWith("http")) {
052: if (link.indexOf("//localhost") > 0) {
053: continue;
054: }
055: if (OPEN_EXTERNAL_LINKS) {
056: StartBrowser.openURL(link);
057: }
058: // System.out.println("External Link: " + link);
059: }
060: }
061: }
062:
063: void listBadLinks() throws Exception {
064: ArrayList errors = new ArrayList();
065: for (Iterator it = links.keySet().iterator(); it.hasNext();) {
066: String link = (String) it.next();
067: if (!link.startsWith("http") && !link.endsWith("h2.pdf")
068: && link.indexOf("_ja.") < 0) {
069: if (targets.get(link) == null) {
070: errors.add(links.get(link) + ": missing link "
071: + link);
072: }
073: }
074: }
075: for (Iterator it = links.keySet().iterator(); it.hasNext();) {
076: String link = (String) it.next();
077: if (!link.startsWith("http")) {
078: targets.remove(link);
079: }
080: }
081: for (Iterator it = targets.keySet().iterator(); it.hasNext();) {
082: String name = (String) it.next();
083: if (targets.get(name).equals("name")) {
084: boolean ignore = false;
085: for (int i = 0; i < IGNORE_MISSING_LINKS_TO.length; i++) {
086: if (name.indexOf(IGNORE_MISSING_LINKS_TO[i]) >= 0) {
087: ignore = true;
088: break;
089: }
090: }
091: if (!ignore) {
092: errors.add("No link to " + name);
093: }
094: }
095: }
096: Collections.sort(errors);
097: for (int i = 0; i < errors.size(); i++) {
098: System.out.println(errors.get(i));
099: }
100: if (errors.size() > 0) {
101: throw new Exception(
102: "Problems where found by the Link Checker");
103: }
104: }
105:
106: void process(String path) throws Exception {
107: if (path.endsWith("/CVS") || path.endsWith("/.svn")) {
108: return;
109: }
110: File file = new File(path);
111: if (file.isDirectory()) {
112: String[] list = file.list();
113: for (int i = 0; i < list.length; i++) {
114: process(path + "/" + list[i]);
115: }
116: } else {
117: processFile(path);
118: }
119: }
120:
121: void processFile(String path) throws Exception {
122: targets.put(path, "file");
123: String lower = StringUtils.toLowerEnglish(path);
124: if (!lower.endsWith(".html") && !lower.endsWith(".htm")) {
125: return;
126: }
127: String fileName = new File(path).getName();
128: String parent = path.substring(0, path.lastIndexOf('/'));
129: String html = IOUtils.readStringAndClose(new FileReader(path),
130: -1);
131: int idx = -1;
132: while (true) {
133: idx = html.indexOf(" id=\"", idx + 1);
134: if (idx < 0) {
135: break;
136: }
137: int start = idx + 4;
138: int end = html.indexOf("\"", start + 1);
139: if (end < 0) {
140: error(fileName, "expected \" after id= "
141: + html.substring(idx, idx + 100));
142: }
143: String ref = html.substring(start + 1, end);
144: targets.put(path + "#" + ref, "id");
145: }
146: idx = -1;
147: while (true) {
148: idx = html.indexOf("<a ", idx + 1);
149: if (idx < 0) {
150: break;
151: }
152: int equals = html.indexOf("=", idx);
153: if (equals < 0) {
154: error(fileName, "expected = after <a at "
155: + html.substring(idx, idx + 100));
156: }
157: String type = html.substring(idx + 2, equals).trim();
158: int start = html.indexOf("\"", idx);
159: if (start < 0) {
160: error(fileName, "expected \" after <a at "
161: + html.substring(idx, idx + 100));
162: }
163: int end = html.indexOf("\"", start + 1);
164: if (end < 0) {
165: error(fileName, "expected \" after <a at "
166: + html.substring(idx, idx + 100));
167: }
168: String ref = html.substring(start + 1, end);
169: if (type.equals("href")) {
170: if (ref.startsWith("http:") || ref.startsWith("https:")) {
171: // ok
172: } else if (ref.startsWith("javascript:")) {
173: ref = null;
174: // ok
175: } else if (ref.length() == 0) {
176: ref = null;
177: // ok
178: } else if (ref.startsWith("#")) {
179: ref = path + ref;
180: } else {
181: String p = parent;
182: while (ref.startsWith(".")) {
183: if (ref.startsWith("./")) {
184: ref = ref.substring(2);
185: } else if (ref.startsWith("../")) {
186: ref = ref.substring(3);
187: p = p.substring(0, p.lastIndexOf('/'));
188: }
189: }
190: ref = p + "/" + ref;
191: }
192: if (ref != null) {
193: links.put(ref, path);
194: }
195: } else if (type.equals("name")) {
196: targets.put(path + "#" + ref, "name");
197: } else {
198: error(fileName, "unsupported <a ?: "
199: + html.substring(idx, idx + 100));
200: }
201: }
202: }
203:
204: private void error(String fileName, String string) {
205: System.out.println("ERROR with " + fileName + ": " + string);
206: }
207:
208: }
|