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 &quot;{@link #EXTERNAL_DOC_ROOT_URL_FILE external_doc_root_urls.txt}&quot; 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 &quot;base&quot; 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}(&quot;super.important.debugginginformation&quot;, null))  {
134   debugln(&quot;Super-duper important!&quot;)
135}</code></blockquote>
136
137      <p><i>(Unless otherwise noted, all below &quot;See&quot; 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/> &nbsp; &nbsp; <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 &quot;{@link CodeletBaseConfig#OFFLINE_PACKAGE_LIST_DIR_NAME offline_package_lists}&quot;. 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 &quot;{@link CodeletBaseConfig#OFFLINE_PACKAGE_LIST_DIR_NAME offline_package_lists}&quot;. 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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; <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}