
src.com.github.aliteralmind.codelet.util.AllOnlineOfflineDocRoots Maven / Gradle / Ivy
Show all versions of codelet Show documentation
/*license*\
Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com)
This software is dual-licensed under the:
- Lesser General Public License (LGPL) version 3.0 or, at your option, any later version;
- Apache Software License (ASL) version 2.0.
Either license may be applied at your discretion. More information may be found at
- http://en.wikipedia.org/wiki/Multi-licensing.
The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at:
- LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
- ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
\*license*/
package com.github.aliteralmind.codelet.util;
import com.github.xbn.io.NewTextAppenterFor;
import com.github.xbn.lang.BadDuplicateException;
import com.github.xbn.lang.CrashIfObject;
import com.github.xbn.util.IfError;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;
import static com.github.xbn.lang.XbnConstants.*;
/**
Collection of {@code package-list}s from all external Java libraries used by a project, for mapping a package name to its JavaDoc document root url--even if that online {@code package-list} is inaccessible. This information is the equivalent of {@code javadoc.exe}'s {@code -link} and {@code -linkoffline} options.
While it may be possible to read in the values of {@code -link} and {@code -linkoffline}, as passed into {@code javadoc.exe}, doing so would make Codelet more dependant on {@code com.sun.javadoc}, which is against its goal of minimizing dependencies on this non-standard package.
@since 0.1.0
@author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. {@code http://codelet.aliteralmind.com}, {@code https://github.com/aliteralmind/codelet}
**/
public class AllOnlineOfflineDocRoots {
private final Map nameToRootMap;
private final Map urlToRootMap ;
private final Map pkgToUrlMap ;
/**
An immutable map whose key is the doc-root's {@linkplain OnlineOfflineDocRoot#getName() name}, and value is its {@code OnlineOfflineDocRoot}.
@see #getPkgToUrlMap()
**/
public Map getNameToRootMap() {
return nameToRootMap;
}
/**
An immutable map whose key is the doc-root's {@linkplain OnlineOfflineDocRoot#getUrlDir() url}, and value is its {@code OnlineOfflineDocRoot}.
@see #getPkgToUrlMap()
**/
public Map getUrlToRootMap() {
return urlToRootMap;
}
/**
An immutable map whose key is a {@linkplain OnlineOfflineDocRoot#getPackageList() package}, and value is its document root url.
@see #getUrlToRootMap()
@see #getNameToRootMap()
**/
public Map getPkgToUrlMap() {
return pkgToUrlMap;
}
/**
@return {@link #appendToString(StringBuilder) appendToString}(new StringBuilder()).toString()
**/
public String toString() {
return appendToString(new StringBuilder()).toString();
}
/**
@param to_appendTo May not be {@code null}.
@see #toString()
**/
public StringBuilder appendToString(StringBuilder to_appendTo) {
try {
to_appendTo.append("All doc-roots:").append(LINE_SEP);
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(to_appendTo, "to_appendTo", null, rx);
}
for (Map.Entry entry : getNameToRootMap().entrySet()) {
to_appendTo.append(" - ").append(entry.getValue()).append(LINE_SEP);
}
return to_appendTo;
}
/**
Create a new {@code AllOnlineOfflineDocRoots} from a configuration file, where each line contains two items: the doc-root's offline file path and online document-root url.
Each line in a configuration file is in the format
[offline_file_path] [url]
Where
[offline_file_path]
is the full path of the locally-stored file. This must exist, and be both readable and writable.
[url]
is the url to the JavaDoc document root ({@code "{@docRoot}"}) for an external Java library. Must end with a slash ({@code '/'}), and must contain the library's {@code "package-list"} file.
The file-path and url are separated with at least one space or tab.
(Lines starting with {@code '#'} are ignored. Empty lines are not allowed.)
Example
If both {@code offlineName_prefixPath} and {@code offlineName_postfix} are {@code null}:
{@code C:\java_code\config\javadoc_offline_package_lists\java.txt http://docs.oracle.com/javase/7/docs/api/}
An equivalent is to set
- {@code offlineName_prefixPath} to {@code "C:\java_code\config\javadoc_offline_package_lists\"}
- and {@code offlineName_postfix} to {@code ".txt"}
and then the config line can be
{@code java http://docs.oracle.com/javase/7/docs/api/}
Steps for each line in {@code line_itr}:
- If {@code online_attemptCount} is
- Greater than zero: This creates the {@code OnlineOfflineDocRoot} with
{@link OnlineOfflineDocRoot}.{@link OnlineOfflineDocRoot#newFromOnline(String, String, String, int, long, IfError, RefreshOffline, Appendable, Appendable) newFromOnline}(name, url, path, online_attemptCount, online_sleepMills, if_error, refresh_offline, debug_ifNonNull, dbgError_ifNonNull)
- Equal to zero (or if retrieving from online fails, and {@code if_error.}{@link com.github.xbn.util.IfError#WARN WARN}): This creates the {@code OnlineOfflineDocRoot} with
OnlineOfflineDocRoot.{@link OnlineOfflineDocRoot#newFromOffline(String, String, String, Appendable, Appendable) newFromOffline}(name, url, path, debug_ifNonNull, dbgError_ifNonNull)
@param line_itr May not be {@code null}, and should have at least one item. All offline paths must be unique, and all urls must be unique.
@param offlineName_prefixPath If non-{@code null}, this is the base directory appended to each offline name, as described above. Setting this to {@code null} is the same as the empty string ({@code ""}).
@param offlineName_postfix If non-{@code null}, this is the postfix appended to each offline name.
@param refresh_offline When {@code online_attemptCount} is greater than zero, should the offline {@code package-list} be refreshed from the online version? If {@code online_attemptCount} is zero, this parameter is ignored.
@see com.github.aliteralmind.codelet.CodeletBootstrap#EXTERNAL_DOC_ROOT_URL_FILE
**/
public static final AllOnlineOfflineDocRoots newFromConfigLineIterator(Iterator line_itr, String offlineName_prefixPath, String offlineName_postfix, int online_attemptCount, long online_sleepMills, RefreshOffline refresh_offline, IfError if_error, Appendable debug_ifNonNull, Appendable dbgError_ifNonNull) throws InterruptedException {
Map nameToRootMap = new TreeMap();
Map urlToRootMap = new TreeMap();
Map pkgToUrlMap = new TreeMap();
int lineNum = 1;
try {
while(line_itr.hasNext()) {
String line = line_itr.next();
if(line.startsWith("#")) {
continue;
}
String[] nameUrl = oneOrMoreSpcTabPtrn.split(line, 0);
if(nameUrl.length != 2) {
String msg = "[line=" + lineNum + "] Line has " + nameUrl.length + " parts. Must have two: \"" + line + "\"";
NewTextAppenterFor.appendableSuppressIfNull(dbgError_ifNonNull).
appentln(msg);
throw new IllegalArgumentException(msg);
}
String name = nameUrl[0];
String url = nameUrl[1];
String path = offlineName_prefixPath + nameUrl[0] + offlineName_postfix;
OnlineOfflineDocRoot docRoot = null;
if(online_attemptCount > 0) {
docRoot = OnlineOfflineDocRoot.newFromOnline(name, url, path, online_attemptCount, online_sleepMills, if_error, refresh_offline, debug_ifNonNull, dbgError_ifNonNull);
}
if(docRoot == null) {
//Either retrieving online failed, or online_attemptCount is zero
NewTextAppenterFor.appendableSuppressIfNull(debug_ifNonNull).appentln("Online package-list not retrieved. Retrieving offline version.");
docRoot = OnlineOfflineDocRoot.newFromOffline(name, url, path, debug_ifNonNull, dbgError_ifNonNull);
}
if(nameToRootMap.containsKey(name)) {
String msg = "[line=" + lineNum + "] Duplicate name: \"" + line + "\"";
NewTextAppenterFor.appendableSuppressIfNull(dbgError_ifNonNull).appentln(msg);
throw new BadDuplicateException(msg);
}
if(urlToRootMap.containsKey(url)) {
String msg = "[line=" + lineNum + "] Duplicate url: \"" + url + "\"";
NewTextAppenterFor.appendableSuppressIfNull(dbgError_ifNonNull).appentln(msg);
throw new BadDuplicateException(msg);
}
for(String pkg : docRoot.getPackageList()) {
if(pkgToUrlMap.containsKey(pkg)) {
String msg = "[line=" + lineNum + "] Duplicate package: \"" + pkg + "\". In both " + docRoot.getName() + " and " + urlToRootMap.get(pkgToUrlMap.get(pkg)).getName() + ".";
if(dbgError_ifNonNull != null) {
NewTextAppenterFor.appendableSuppressIfNull(dbgError_ifNonNull).appentln(msg);
}
throw new BadDuplicateException(msg);
}
pkgToUrlMap.put(pkg, url);
pkgToUrlMap.put(pkg, docRoot.getUrlDir());
}
nameToRootMap.put(name, docRoot);
urlToRootMap.put(url, docRoot);
lineNum++;
}
} catch(RuntimeException rx) {
throw CrashIfObject.nullOrReturnCause(line_itr, "line_itr", null, rx);
}
return new AllOnlineOfflineDocRoots(
Collections.unmodifiableMap(nameToRootMap),
Collections.unmodifiableMap(urlToRootMap),
Collections.unmodifiableMap(pkgToUrlMap));
}
private static final Pattern oneOrMoreSpcTabPtrn = Pattern.compile("[ \t]+");
private AllOnlineOfflineDocRoots(Map nameToRoot_map, Map urlToRoot_map, Map pkgToUrl_map) {
nameToRootMap = nameToRoot_map;
urlToRootMap = urlToRoot_map;
pkgToUrlMap = pkgToUrl_map;
}
}