001package Torello.JavaDoc.SyntaxHiLite;
002
003import Torello.Java.FileNode;
004import Torello.Java.StrPrint;
005import Torello.Java.FileRW;
006import Torello.Java.StorageWriter;
007
008import Torello.Java.Function.QuadFunction;
009
010// Needed for a JavaDoc Comment
011import Torello.Java.FileTransfer;
012
013import Torello.JavaDoc.Annotations.LinkJavaSource;
014
015import java.util.TreeSet;
016
017import java.io.File;
018
019
020/**
021 * An {@code abstract} Parent-Class for both {@link HLC32} and {@link HLC64}.  The bulkwork of
022 * methods and fields needed to run both of these classes can be placed in the abstract parent.
023 * In fact, there are only two {@code abstract} implementatio methods that subclasses need to
024 * implement in order to properly fullfill this {@code abstract} Parent-Class,
025 */
026public abstract class AbstractHashCodeHLC<NUMBER extends Number> implements HiLiteCache
027{
028    static final short NUM_DIRS = 5000;
029
030    static
031    {
032        if ((NUM_DIRS < 1000) || (NUM_DIRS > 9999))
033            throw new InternalError("Wrong Number of NUM_DIRS");
034    }
035
036
037    // ********************************************************************************************
038    // ********************************************************************************************
039    // Instance Fields
040    // ********************************************************************************************
041    // ********************************************************************************************
042
043
044    /** This is nothing more than a "reified" Generic Type Parameter.  No more, no less. */
045    public final Class<NUMBER> NUMBER_CLASS;
046
047    /** This is, as the name clearly says, the Cache's Storae-Directory */
048    public final String cacheSaveDirectory;
049
050
051    // This is the list of Hash-Codes for all Code/HTML pairs stored in the cache.  This is the
052    // exact data-structure that is referred to as the "Master Hash File"
053    // 
054    // This has also been recently converted to "Package-Private", instead of "Private"
055    // See Above Note for Details.
056
057    final TreeSet<NUMBER> hashCodes;
058
059
060    // ********************************************************************************************
061    // ********************************************************************************************
062    // Constructor
063    // ********************************************************************************************
064    // ********************************************************************************************
065
066
067    /**
068     * This will load the hashCodes table to memory from the file-system directory identified
069     * by {@code String}-Parameter {@code 'cacheSaveDirectory'}.  An exception shall be thrown
070     * if this file is not found, or the specified directory doesn't exist.
071     *
072     * @param cacheSaveDirectory This constructor presumes that this cache has been used and
073     * visited before.  This directory name should point to your local-cache of the
074     * {@code HiLite.ME} Server Code hilite past-operations.
075     *
076     * @throws CacheError This error will throw if the cache has not been instantiated, or
077     * is corrupted.  If the specified directory does not exist, then this {@code Error} shall
078     * also throw.  The chain-cause {@code Throwable} should be visible, and is included as the 
079     * {@code Throwable.getCause()}.
080     */
081    @LinkJavaSource(handle="TreeSetMethods", name="checkCSD")
082    @LinkJavaSource(handle="TreeSetMethods", name="checkTS")
083    public AbstractHashCodeHLC(
084            final String        cacheSaveDirectory,
085            final Class<NUMBER> NUMBER_CLASS
086        )
087    {
088        this.cacheSaveDirectory = TreeSetMethods.checkCSD(cacheSaveDirectory);
089        this.hashCodes          = TreeSetMethods.checkTS(this.cacheSaveDirectory, NUMBER_CLASS);
090        this.NUMBER_CLASS       = NUMBER_CLASS;
091    }
092
093
094    // ********************************************************************************************
095    // ********************************************************************************************
096    // Initialize a Directory for Cachine - Create if need be, Erase its contents, if non-empty
097    // ********************************************************************************************
098    // ********************************************************************************************
099
100
101    /**
102     * This will initialize a cache-file in the file-system directory identified by parameter
103     * {@code String cacheSaveDirectory}.  If the directory specified does not exist,
104     * {@code File.mkdirs()} will be invoked, thereby creating that directory.  If the specified
105     * directory already exists - it's contents shall be fully wiped, meaning all files deleted.
106     *
107     * <BR /><BR /><DIV CLASS=JDHint>
108     * <B>Erasing Contents:</B> If the directory structure provided to this method is non-empty,
109     * the <B STYLE="color: red;"><I>its entire contents shall be erased by a call to</I></B>
110     * <B>{@link FileTransfer#deleteFilesRecursive(FileNode, FileNodeFilter, FileNodeFilter,
111     * Appendable)  FileTransfer#deleteFilesRecursive}.</B>, as per the statement below
112     * </DIV>
113     * 
114     * <BR /><DIV CLASS=SNIP>{@code 
115     * FileTransfer.deleteFilesRecursive
116     *     (FileNode.createRoot(cacheSaveDirectory).loadTree(), sw);
117     * }</DIV>
118     * 
119     * <BR />This method saves a brand-new (empty) Hash-Code List (a java.util.TreeSet) to disk, 
120     * using  Java Object Serialization.  It is not actually important to know whether this Cache
121     * is going to be a 32-Bit or a 64-Bit Cache.  The {@code TreeSet} which is written to disk is
122     * empty.  Therefore, in all actuality, what is written to disk is a "Raw-Types" TreeSet 
123     * (precisely because of Java's Generic Erasure).  Thus it is perfectly irrelevant what is
124     * written to disk.
125     * 
126     * @param cacheSaveDirectory This constructor presumes that this cache has been used and
127     * visited before.  This directory name should point to your local-cache of 
128     * {@code HiLite.ME} Server Code hilite past-operations.
129     * 
130     * @param sw This receives log-writes from the call to
131     * {@link FileTransfer#deleteFilesRecursive} which clears the files currently in the cache.
132     * This parameter may be null, and if it is, output-text will be shunted.
133     * 
134     * @throws CacheError This exception will be throw if there are errors deleting any
135     * old-cache files currently in the directory; or if there is any error creating the new
136     * master hash-cache file.  The chain-cause {@code Throwable} should be visible, and is 
137     * included as the {@code Throwable.getCause()}.
138     */
139    @LinkJavaSource(handle="TreeSetMethods", name="initializeDirectory")
140    public static String initializeDirectory(String cacheSaveDirectory, StorageWriter sw)
141    { return TreeSetMethods.initializeDirectory(cacheSaveDirectory, sw); }
142
143
144    // ********************************************************************************************
145    // ********************************************************************************************
146    // Implemented Interface Methods
147    // ********************************************************************************************
148    // ********************************************************************************************
149
150
151    public long totalSize()
152    {
153        return FileNode
154            .createRoot(this.cacheSaveDirectory)
155            .loadTree()
156            .getDirTotalContentsSize();
157    }
158
159    public int totalNumber()
160    {
161        return FileNode
162            .createRoot(this.cacheSaveDirectory)
163            .loadTree()
164            .count();
165    }
166
167    @LinkJavaSource(handle="TreeSetMethods", name="persistMasterHashToDisk")
168    public void persistMasterHashToDisk() throws CacheError
169    { TreeSetMethods.persistMasterHashToDisk(this.hashCodes, this.cacheSaveDirectory); }
170
171
172    // ********************************************************************************************
173    // ********************************************************************************************
174    // Implemented Interface Methods: Check In and Out
175    // ********************************************************************************************
176    // ********************************************************************************************
177
178
179    @LinkJavaSource(handle="CheckInOut", name="get")
180    public String get(
181            final String    sourceCodeAsString,
182            final String    codeTypeParam,
183            final boolean   includeLineNumbers,
184            final byte      styleNum
185        )
186    {
187        return CheckInOut.get(
188            sourceCodeAsString,
189            this.computeCacheKey
190                (codeTypeParam, includeLineNumbers, styleNum, sourceCodeAsString),
191            this
192        );
193    }
194
195    @LinkJavaSource(handle="CheckInOut", name="checkIn")
196    public void checkIn(
197            final String    sourceCodeAsString,
198            final String    hilitedCodeAsString, 
199            final String    codeTypeParam,
200            final boolean   includeLineNumbers,
201            final byte      styleNum
202        )
203    {
204        CheckInOut.checkIn(
205            sourceCodeAsString,
206            hilitedCodeAsString,
207            this.computeCacheKey
208                (codeTypeParam, includeLineNumbers, styleNum, sourceCodeAsString),
209            this 
210        );
211    }
212
213
214    // ********************************************************************************************
215    // ********************************************************************************************
216    // Abstract Methods
217    // ********************************************************************************************
218    // ********************************************************************************************
219
220
221    /**
222     * Compute a Hash-Code for a given Source-File, and it's HiLiting Parameters
223     * @param codeTypeParam         <EMBED CLASS='external-html' DATA-FILE-ID=HLC_PARAM_CODE_TP>
224     * @param includeLineNumbers    <EMBED CLASS='external-html' DATA-FILE-ID=HLC_PARAM_INC_LINEN>
225     * @param styleNum              <EMBED CLASS='external-html' DATA-FILE-ID=HLC_PARAM_STYLE_N>
226     * @param sourceCodeAsString    <EMBED CLASS='external-html' DATA-FILE-ID=HLC_PARAM_SRC_ASSTR>
227     * @return A key which may be used for saving a file to disk.
228     */
229    public abstract NUMBER computeCacheKey(
230            final String    codeTypeParam,
231            final boolean   includeLineNumbers,
232            final byte      styleNum,
233            final String    sourceCodeAsString
234        );
235
236    abstract String getSubDirName(NUMBER hashCode);
237
238
239    // ********************************************************************************************
240    // ********************************************************************************************
241    // Main Method for invoking '' ...
242    // ********************************************************************************************
243    // ********************************************************************************************
244
245
246    /**
247     * A Main-Method which invokes {@link #initializeDirectory(String, StorageWriter)}
248     */
249    public static void main(String[] argv)
250    {
251        if (argv.length != 1)
252        {
253            System.out.println(
254                "argv.length != 1\n" +
255                "argv[0] must contain the Cache-Directory Name.\n"
256            );
257
258            System.exit(1);
259        }
260
261        initializeDirectory(argv[0], new StorageWriter());
262    }
263}