001/*license*\ 002 Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com) 003 004 This software is dual-licensed under the: 005 - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version; 006 - Apache Software License (ASL) version 2.0. 007 008 Either license may be applied at your discretion. More information may be found at 009 - http://en.wikipedia.org/wiki/Multi-licensing. 010 011 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: 012 - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt 013 - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt 014\*license*/ 015package com.github.aliteralmind.codelet; 016 import com.github.xbn.io.PlainTextFileUtil; 017 import com.github.xbn.lang.ExceptionUtil; 018 import com.github.xbn.text.CrashIfString; 019 import com.github.xbn.util.PropertiesUtil; 020 import java.io.IOException; 021 import java.net.MalformedURLException; 022 import java.nio.file.AccessDeniedException; 023 import java.nio.file.NoSuchFileException; 024 import java.util.Iterator; 025 import java.util.Properties; 026/** 027 <p>Initializes Codelet by loading all configuration--This is {@linkplain TagletProcessor#TagletProcessor(CodeletInstance) triggered} by the first codelet-taglet encountered by {@code javadoc.exe}.</p> 028 029 <p>This:<ol> 030 <li>Obtains the {@link #CODELET_CONFIG_DIR_SYS_PROP_NAME codelet_config_dir} system property as passed into the {@code javadoc} application.</li> 031 <li>Loads {@linkplain CodeletBaseConfig base configuration} from {@link #BASE_CONFIG_FILE_NAME codelet.properties}, as exists in the configuration directory. This includes the {@linkplain #CODELET_RQD_NAMED_DBGRS_CONFIG_FILE Codelet-required} and {@linkplain #NAMED_DEBUGGERS_CONFIG_FILE user-created} named debuggers, and the external JavaDoc library {@linkplain #EXTERNAL_DOC_ROOT_URL_FILE package-lists}.</li> 032 <li>Loads {@linkplain CodeletTemplateConfig default templates}.</li> 033 <li>Loads the {@linkplain TemplateOverrides template-override} configuration from {@link #TMPL_OVERRIDES_CONFIG_FILE_NAME template_overrides_config}.</li> 034 </ol>This order is required to avoid <a href="http://en.wikipedia.org/wiki/Circular_dependency">circular dependencies</a>.</p> 035 036 <h4>Automated {@linkplain CodeletBootstrap#CODELET_RQD_NAMED_DBGRS_CONFIG_FILE named debuggers}</h4> 037 038 <p>{@code zzconfiguration.}<ul> 039 <li>{@code nameddebuglevels.listallafterload}: List all levels after being loaded.</li> 040 <li>{@code nameddebuglevels.eachquery}: List each level when queried--regardless if on or off. Use this to determine any unused levels that may exist in the configuration file.</li> 041 <li>{@code allvaluessummary}: List all {@linkplain CodeletBaseConfig basic configuration} values after complete.</li> 042 <li>{@code progress}: The basic steps taken while loading all configuration.</li> 043 <li>{@code templateoverrides.}<ul> 044 <li>{@code allentriespostloaded}: List all entries organized by JavaDoc file.</li> 045 <li>{@code eachentryasloaded}: List all entries as they are loaded.</li> 046 </ul></li> 047 </ul></p> 048 049 <p><b>Full names:</b></p> 050 051<blockquote><pre>zzconfiguration.nameddebuglevels.listallafterload 052zzconfiguration.nameddebuglevels.eachquery 053zzconfiguration.allvaluessummary 054zzconfiguration.progress 055zzconfiguration.templateoverrides.allentriespostloaded 056zzconfiguration.templateoverrides.eachentryasloaded</pre></blockquote> 057 058 * @since 0.1.0 059 * @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. <a href="http://codelet.aliteralmind.com">{@code http://codelet.aliteralmind.com}</a>, <a href="https://github.com/aliteralmind/codelet">{@code https://github.com/aliteralmind/codelet}</a> 060 **/ 061public enum CodeletBootstrap { 062 INSTANCE; 063 static { 064 try { 065 CodeletBootstrap.loadConfiguration(); 066 } catch(Exception x) { 067 throw new ExceptionInInitializerError( 068 new IllegalStateException("Attempting to load Codelet configuration.", x)); 069 } 070 } 071 private static String configDir ; 072 private static CodeletBaseConfig baseConfig ; 073 private static CodeletTemplateConfig tmplConfig ; 074 private static TemplateOverrides tmplOverrides; 075 private static final String NAMED_DBG_LVL_PREFIX = "named_debuggers_config"; 076 /** 077 <p>The name of the system property that is <a href="{@docRoot}/overview-summary.html#install_taglets">passed</a> into the {@code javadoc} application, whose value is the directory in which all Codelet configuration files are stored--Equal to {@code "codelet_config_dir"}. </p> 078 079 <p>{@link #BASE_CONFIG_FILE_NAME codelet.properties}, {@link #TMPL_OVERRIDES_CONFIG_FILE_NAME template_overrides_config.txt}, and "{@link #EXTERNAL_DOC_ROOT_URL_FILE external_doc_root_urls.txt}" must all be in this directory.</p> 080 081 * @see CodeletBootstrap 082 * @see #getCodeletConfigDir() 083 */ 084 public static final String CODELET_CONFIG_DIR_SYS_PROP_NAME = "codelet_config_dir"; 085 /** 086 <p>The name of the "base" configuration file--Equal to {@code "codelet.properties"}.</p> 087 088 * @see #TMPL_OVERRIDES_CONFIG_FILE_NAME 089 * @see com.github.aliteralmind.codelet.CodeletBaseConfig 090 */ 091 public static final String BASE_CONFIG_FILE_NAME = "codelet.properties"; 092 /** 093 <p>The name of the configuration file containing user-created named-debugging-levels--Equal to {@code "named_debuggers_config.txt"}.</p> 094 095 <p><i>(View <a href="{@docRoot}/../codelet_config/named_debuggers_config.txt">{@code {@docRoot}/../codelet_config/named_debuggers_config.txt}</a>.)</i></p> 096 097 <p>This file contains a list of zero or more {@linkplain com.github.aliteralmind.codelet.util.NamedDebuggers#newMapFromConfigFile(Map, Iterator, String, Appendable) names}, each of which is associated to a specific debugging task and {@linkplain CodeletBaseConfig#GLOBAL_DEBUG_LEVEL level}. These are in addition to those in the {@linkplain #CODELET_RQD_NAMED_DBGRS_CONFIG_FILE Codelet-required} configuration file.</p> 098 099 <p>Named debuggers allow for very specific control over what information is logged, <i>without having to recompile code</i>. In particular, named debuggers are useful for debugging <a href="CustomizationInstructions.html#overview">custom customizers</a>.</p> 100 101 <p>All possible level numbers:<ul> 102<!-- 103 Originates in 104 com.github.aliteralmind.codelet.util.NamedDebuggers 105 needed by 106 com.github.aliteralmind.codelet.CodeletBootstrap 107 ...START 108 --> 109 <li><b>{@code -1}</b>: Never output.</li> 110 <li><b>{@code 0}</b>: Always output (even if {@link com.github.xbn.io.DebugLevel#OFF OFF}).</li> 111 <li><b>{@code 1}</b>: Output only when the actual level {@linkplain com.github.xbn.io.DebugLevel#isOn() on}--equal to or greater than {@link com.github.xbn.io.DebugLevel#ONE ONE}.</li> 112 <li><b>{@code 2}</b>: Output when the actual level is {@link com.github.xbn.io.DebugLevel#TWO TWO} or greater.</li> 113 <li><b>{@code 3}</b>: Output when the actual level is {@link com.github.xbn.io.DebugLevel#THREE THREE} or greater.</li> 114 <li><b>{@code 4}</b>: Output when the actual level is {@link com.github.xbn.io.DebugLevel#FOUR FOUR} or {@link com.github.xbn.io.DebugLevel#FIVE FIVE}.</li> 115 <li><b>{@code 5}</b>: Output only when the actual level is {@code FIVE}.</li> 116<!-- 117 Originates in 118 com.github.aliteralmind.codelet.util.NamedDebuggers 119 needed by 120 com.github.aliteralmind.codelet.CodeletBootstrap 121 ...END 122 --> 123 </ul></p> 124 125 <h4>Example</h4> 126 127 <p>Add this line to {@code "named_debuggers_config.txt"}:</p> 128 129<blockquote><pre>super.important.debugginginformation=2</pre></blockquote> 130 131 <p>Then associate specific debugging statements to it:</p> 132 133<blockquote><code>if({@link CodeletBaseConfig#isDebugOn(CodeletInstance, String) isDebugOn}("super.important.debugginginformation", null)) { 134 debugln("Super-duper important!") 135}</code></blockquote> 136 137 <p><i>(Unless otherwise noted, all below "See" links are located in {@link CodeletBaseConfig}.)</i></p> 138 139 * @see com.github.aliteralmind.codelet.util.NamedDebuggers#newMapFromConfigFile(Map, Iterator, String, Appendable) NamedDebuggers#newMapFromConfigFile 140 * @see CodeletBaseConfig#GLOBAL_DEBUG_LEVEL GLOBAL_DEBUG_LEVEL 141 * @see CodeletBaseConfig#isDebugOn(CodeletInstance, String) isDebugOn(s,ci) 142 * @see CodeletBaseConfig#getDebugApblIfOn(CodeletInstance, String) getDebugApblIfOn(ci,s) 143 * @see CodeletBaseConfig#getDebugAptrIfOn(CodeletInstance, String) getDebugAptrIfOn(ci,s) 144 */ 145 public static final String NAMED_DEBUGGERS_CONFIG_FILE = NAMED_DBG_LVL_PREFIX + ".txt"; 146 /** 147 <p>The name of the configuration file containing Codelet-required named debuggers--Equal to {@code "named_debuggers_config_CODELET_RQD.txt"}.</p> 148 149 <p><i>(View <a href="{@docRoot}/../codelet_config/named_debuggers_config_CODELET_RQD.txt">{@code {@docRoot}/../codelet_config/named_debuggers_config_CODELET_RQD.txt}</a>.)</i></p> 150 151 <p>This file contains a list of {@linkplain com.github.aliteralmind.codelet.util.NamedDebuggers#newMapFromConfigFile(Map, Iterator, String, Appendable) names}, each of which is associated to a specific debugging task and {@linkplain CodeletBaseConfig#GLOBAL_DEBUG_LEVEL level}. These are in addition to those in the {@linkplain #NAMED_DEBUGGERS_CONFIG_FILE user-created} configuration file.</p> 152 153 <p>Changing the level numbers in this file allows you to print or suppress very specific aspects of debugging information that is <i>already built into Codelet</i>. <b>Warning:</b> Changing the <i>names</i> of any level in this file will result in an error. All Codelet-required levels are prefixed with {@code "zz"}.</p> 154 155 <p>An example of a function taking advantage of named debuggers is 156 <br/> <code>{@link BasicCustomizers}.{@link BasicCustomizers#lineRange(CodeletInstance, CodeletType, Integer, Boolean, String, Integer, Boolean, String, String) lineRange}</code>.</p> 157 158 * @see #NAMED_DEBUGGERS_CONFIG_FILE 159 * @see com.github.aliteralmind.codelet.util.NamedDebuggers#newMapFromConfigFile(Map, Iterator, String, Appendable) NamedDebuggers#newMapFromConfigFile 160 */ 161 public static final String CODELET_RQD_NAMED_DBGRS_CONFIG_FILE = NAMED_DBG_LVL_PREFIX + "_CODELET_RQD.txt"; 162 /** 163 <p>The name of the file in which all <a href="http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#externalreferencedclasses">external {@code {@docRoot}} urls</a> are listed--Equal to {@code "external_doc_root_urls.txt"}.</p> 164 165 <p>These urls are the directories in which an external JavaDoc library's <a href="http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#package-list">{@code package-list}</a> file exists. Each url must end with a slash: {@code '/'}.</p> 166 167 <p>Each {@code package-list} file is also stored locally, in a sub-directory named "{@link CodeletBaseConfig#OFFLINE_PACKAGE_LIST_DIR_NAME offline_package_lists}". The offline files are automatically used when the online version is not accessible or available. These files may be manually created and, if {@linkplain CodeletBaseConfig#AUTO_UPDATE_OFFLINE_PACKAGE_LISTS configured}, are automatically updated.</p> 168 169 <p>Each line is in the format</p> 170 171<blockquote><pre>[offline_file_name_prefix] [url]</pre></blockquote> 172 173 <p>Where<ul> 174 <li><code>[offline_file_name]</code> is the name of the locally-stored file (aside from {@code ".txt"}), which exists in a sub-directory named "{@link CodeletBaseConfig#OFFLINE_PACKAGE_LIST_DIR_NAME offline_package_lists}". This is in the {@linkplain #CODELET_CONFIG_DIR_SYS_PROP_NAME same directory} as this {@code "external_doc_root_urls.txt"} file. Must only contain letters, digits, and underscores ({@code '_'}).</li> 175 <li><code>[url]</code> is the url to the JavaDoc document root ({@code "{@docRoot}"}) of an external Java library. Must end with a slash ({@code '/'}), and must contain the library's {@code "package-list"} file.</li> 176 </ul>The file-name and url are separated with at least one space or tab.</p> 177 178 <h4>Example file</h4> 179 180<blockquote><pre>templatefeather http://aliteralmind.com/docs/computer/programming/templatefeather/documentation/javadoc/ 181xbnjava http://aliteralmind.com/docs/computer/programming/xbnjava/documentation/javadoc/ 182commons_collections http://commons.apache.org/proper/commons-collections/javadocs/api-release/ 183commons_io http://commons.apache.org/proper/commons-io/javadocs/api-2.4/ 184commons_lang http://commons.apache.org/proper/commons-lang/javadocs/api-release/ 185java http://docs.oracle.com/javase/7/docs/api/ 186javadoc http://docs.oracle.com/javase/7/docs/jdk/api/javadoc/doclet/ 187junit http://junit.sourceforge.net/javadoc/</pre></blockquote> 188 189 <p>If the path of {@code "external_doc_root_urls.txt"} is 190 <br/> <code>C:\java_code\my_package\codelet_config\external_doc_root_urls.txt</code> 191 <br/>then the path to the {@code "commons_io"} offline package-list is 192 <br/> <code>C:\java_code\my_package\codelet_config\offline_package_lists\commons_io.txt</code> 193 <br/>The {@code ".txt"} postfix is {@linkplain CodeletBaseConfig#PKGLIST_OFFLINE_NAME_POSTFIX customizable}.</p> 194 195 <p><i>(View <a href="{@docRoot}/../codelet_config/external_doc_root_urls.txt">{@code {@docRoot}/../codelet_config/external_doc_root_urls.txt}</a>.)</i></p> 196 197 <p>This configuration file is loaded by <code>{@link com.github.aliteralmind.codelet.util.AllOnlineOfflineDocRoots}.{@link com.github.aliteralmind.codelet.util.AllOnlineOfflineDocRoots#newFromConfigLineIterator(Iterator, String, String, int, long, RefreshOffline, IfError, Appendable, Appendable) newFromConfigLineIterator}</code></p> 198 199 <p>Related (all in {@link CodeletBaseConfig}):<ul> 200 <li>{@link CodeletBaseConfig#PKGLIST_ONLINE_ATTEMPT_SLEEP_MILLS pkglist_online_attempt_sleep_mills}: The pause between each attempt.</li> 201 <li>{@link CodeletBaseConfig#PKGLIST_ONLINE_FAILS_BEHAVIOR pkglist_if_online_retrieval_fails__warn_crash}: The behavior after all attempts fail</li> 202 <li>{@link CodeletBaseConfig#AUTO_UPDATE_OFFLINE_PACKAGE_LISTS pkglist_auto_refresh_offline__yes_no}: After successfully retrieved, should the packages in its offline counterpart be {@linkplain com.github.aliteralmind.codelet.util.OnlineOfflineDocRoot#refreshOffline(Appendable, Appendable) refreshed}?</li> 203 <li>{@link CodeletBaseConfig#PKGLIST_OFFLINE_NAME_POSTFIX pkglist_offline_name_postfix}: The postfix added to each offline-name in the {@linkplain CodeletBootstrap#EXTERNAL_DOC_ROOT_URL_FILE configuration file}.</li> 204 <li>{@link CodeletBaseConfig#OFFLINE_PACKAGE_LIST_DIR_NAME}: The name of the sub-directory, existing in the main Codelet configuration directory, in which offline package lists are stored.</li> 205 </ul></p> 206 207 * @see com.github.aliteralmind.codelet.alter.NewJavaDocLinkReplacerFor#getDocRootUrlToTargetClass(CodeletInstance, Class) NewJavaDocLinkReplacerFor#getDocRootUrlToTargetClass 208 * @see com.github.aliteralmind.codelet.util.AllOnlineOfflineDocRoots#newFromConfigLineIterator(Iterator, String, String, int, long, RefreshOffline, IfError, Appendable, Appendable) util.AllOnlineOfflineDocRoots#newFromConfigLineIterator 209 */ 210 public static final String EXTERNAL_DOC_ROOT_URL_FILE = "external_doc_root_urls.txt"; 211 /** 212 <p>The name of the {@linkplain TemplateOverrides template-overrides} configuration file--Equal to {@code "template_overrides_config.txt"}.</p> 213 214 * @see #BASE_CONFIG_FILE_NAME 215 * @see com.github.aliteralmind.codelet.TemplateOverrides 216 */ 217 public static final String TMPL_OVERRIDES_CONFIG_FILE_NAME = "template_overrides_config.txt"; 218// static final CodeletBootstrap loadConfigGetInstance() throws ClassNotFoundException, NoSuchFileException, AccessDeniedException, MalformedURLException, IOException, InterruptedException { 219 private static final void loadConfiguration() throws ClassNotFoundException, NoSuchFileException, AccessDeniedException, MalformedURLException, IOException, InterruptedException { 220 if(wasLoaded()) { 221 throw new IllegalStateException("Configuration already loaded. wasLoaded()=true"); 222 } 223 224 configDir = System.getProperty(CODELET_CONFIG_DIR_SYS_PROP_NAME, null); 225 226 //0.1.4 227 CrashIfString.nullEmpty(configDir, "[System property \"" + CODELET_CONFIG_DIR_SYS_PROP_NAME + "\", which is required to be passed into javadoc.exe, via \"-J-Dcodelet_config_dir\"]", null); 228 229 String configDirEquals = CODELET_CONFIG_DIR_SYS_PROP_NAME + "=" + configDir; 230 Properties props = PropertiesUtil. 231 getPropertiesFromFile(configDir + BASE_CONFIG_FILE_NAME, configDirEquals); 232 233 Iterator<String> externalJDDocRootConfigItr = PlainTextFileUtil. 234 getLineIterator(configDir + EXTERNAL_DOC_ROOT_URL_FILE, 235 configDirEquals); 236 237 Iterator<String> rqdDebugLevelConfigItr = PlainTextFileUtil. 238 getLineIterator(configDir + CODELET_RQD_NAMED_DBGRS_CONFIG_FILE, 239 configDirEquals); 240 Iterator<String> debugLevelConfigItr = PlainTextFileUtil. 241 getLineIterator(configDir + NAMED_DEBUGGERS_CONFIG_FILE, 242 configDirEquals); 243 244 baseConfig = CodeletBaseConfig.loadConfigGetInstance(props, 245 configDir, externalJDDocRootConfigItr, 246 rqdDebugLevelConfigItr, debugLevelConfigItr); 247 248 tmplConfig = CodeletTemplateConfig.loadConfigGetInstance(); 249 250 Iterator<String> overridesItr = PlainTextFileUtil. 251 getLineIterator(configDir + TMPL_OVERRIDES_CONFIG_FILE_NAME, configDirEquals); 252 tmplOverrides = TemplateOverrides.loadConfigGetInstance(overridesItr); 253 } 254 /** 255 <p>Was all Codelet configuration properly loaded?.</p> 256 257 * @return <code>{@link TemplateOverrides}.{@link TemplateOverrides#wasLoaded() wasLoaded}()</code> 258 */ 259 public static final boolean wasLoaded() { 260 return TemplateOverrides.wasLoaded(); 261 } 262 /** 263 <p>The directory in which all Codelet configuration files exist, as passed in via the {@code javadoc.exe} system property named {@code "codelet_config_dir"}.</p> 264 265 * @see #CODELET_CONFIG_DIR_SYS_PROP_NAME 266 */ 267 public static final String getCodeletConfigDir() { 268 return configDir; 269 } 270}