All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.com.swabunga.spell.engine.SpellDictionaryCachedDichoDisk Maven / Gradle / Ivy

Go to download

A simple spell checker add-on for RSyntaxTextArea. It will spell-check comments in source code, or the entire file if you are editing plain text. Spelling errors are squiggle-underlined with the color of your choice, and tooltips are available offering any spelling suggestions.

The newest version!
/*
Jazzy - a Java library for Spell Checking
Copyright (C) 2001 Mindaugas Idzelis
Full text of license can be found in LICENSE.txt

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
package org.fife.com.swabunga.spell.engine;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Yet another SpellDictionary this one is based on Damien Guillaume's
 * Diskbased dictionary but adds a cache to try to improve a bit on performance.
 *
 * @author Robert Gustavsson
 * @version 0.01
 */
public class SpellDictionaryCachedDichoDisk extends SpellDictionaryDichoDisk {

    // Only used for testing to measure the effectiveness of the cache.
    private int hits;
    private int codes;

    public static final String JAZZY_DIR = ".jazzy";
    public static final String PRE_CACHE_FILE_EXT = ".pre";

    private static final int DEFAULT_MAX_CACHE_SIZE = 10000;

    private int maxCacheSize;
    private Map suggestionCache;
    private String preCacheFileName;
    private String preCacheDir;

    /**
     * Dictionary Convenience Constructor.
     *
     * @param wordList The word list file.
     * @throws IOException If an IO error occurs.
     */
    public SpellDictionaryCachedDichoDisk(File wordList) throws IOException {
        super(wordList);
        loadPreCache(wordList, DEFAULT_MAX_CACHE_SIZE);
    }

    /**
     * Dictionary Convenience Constructor.
     *
     * @param wordList The word list file.
     * @param encoding The encoding to use.
     * @throws IOException If an IO error occurs.
     */
    public SpellDictionaryCachedDichoDisk(File wordList, String encoding)
            throws IOException {
        this(wordList, encoding, DEFAULT_MAX_CACHE_SIZE);
    }

    /**
     * Dictionary Convenience Constructor.
     *
     * @param wordList The word list file.
     * @param encoding The encoding to use.
     * @param maxCacheSize The maximum size of the cache.
     * @throws IOException If an IO error occurs.
     */
    public SpellDictionaryCachedDichoDisk(File wordList, String encoding, int maxCacheSize)
            throws IOException {
        super(wordList, encoding);
        loadPreCache(wordList, maxCacheSize);
    }

    /**
     * Dictionary constructor that uses an aspell phonetic file to
     * build the transformation table.
     *
     * @param wordList The word list file.
     * @param phonetic The phonetic file.
     * @throws IOException If an IO error occurs.
     */
    public SpellDictionaryCachedDichoDisk(File wordList, File phonetic)
            throws IOException {
        super(wordList, phonetic);
        loadPreCache(wordList, DEFAULT_MAX_CACHE_SIZE);
    }

    /**
     * Dictionary constructor that uses an aspell phonetic file to
     * build the transformation table.
     *
     * @param wordList The word list file.
     * @param phonetic The phonetic file.
     * @param encoding The encoding to use.
     * @throws IOException If an IO error occurs.
     */
    public SpellDictionaryCachedDichoDisk(File wordList, File phonetic, String encoding)
            throws IOException {
        super(wordList, phonetic, encoding);
        loadPreCache(wordList, DEFAULT_MAX_CACHE_SIZE);
    }

    /**
     * Add a word permanently to the dictionary (and the dictionary file).
     * not implemented !
     */
    @Override
    public boolean addWord(String word) {
        return false;
    }

    /**
     * Clears the cache and resets the debugging hit/codes counters.
     */
    public void clearCache() {
        suggestionCache.clear();
        codes = 0;
        hits = 0;
    }

    /**
     * Returns the size of the suggestion cache. Useful for debugging.
     *
     * @return The size of the suggestion cache.
     */
    protected int getCacheSize() {
        return suggestionCache.size();
    }

    /**
     * Returns the number of times the cache has been hit/used.
     * Only really useful for testing.
     *
     * @return The cache usage count.
     */
    protected int getHits() {
        return hits;
    }

    /**
     * Returns a list of strings (words) for the code.
     */
    @Override
    public List getWords(String code) {
        List list;
        codes++;
        if (suggestionCache.containsKey(code)) {
            hits++;
            list = getCachedList(code);
            return list;
        }
        list = super.getWords(code);
        addToCache(code, list);

        return list;
    }

    /**
     * This method returns the cached suggestionlist and also moves the code to
     * the top of the codeRefQueue to indicate this code has recently been
     * referenced.
     */
    private List getCachedList(String code) {
        CacheObject obj = suggestionCache.get(code);
        obj.setRefTime();
        return obj.getSuggestionList();
    }

    /**
     * Adds a code and it's suggestion list to the cache.
     */
    private void addToCache(String code, List l) {
        String c = null;
        String lowestCode = null;
        long lowestTime = Long.MAX_VALUE;
        Iterator it;
        CacheObject obj;

        if (suggestionCache.size() >= maxCacheSize) {
            it = suggestionCache.keySet().iterator();
            while (it.hasNext()) {
                c = it.next();
                obj = suggestionCache.get(c);
                if (obj.getRefTime() == 0) {
                    lowestCode = c;
                    break;
                }
                if (lowestTime > obj.getRefTime()) {
                    lowestCode = c;
                    lowestTime = obj.getRefTime();
                }
            }
            suggestionCache.remove(lowestCode);
        }
        suggestionCache.put(code, new CacheObject(l));
    }

    /**
     * Returns the full path to the precache directory that will be used.
     *
     * @return The precache directory.
     */
    public static String getPreCacheDir() {
        return System.getProperty("user.home") + "/" + JAZZY_DIR;
    }

    /**
     * Load the cache from file. The cache file has the same name as the
     * dico file with the .pre extension added.
     */
    @SuppressWarnings("unchecked")
    private void loadPreCache(File dicoFile, int maxCacheSize) throws IOException {

        this.maxCacheSize = maxCacheSize;
        suggestionCache = new HashMap<>(maxCacheSize);

        String code;
        List suggestions;
        long size;
        long time;
        File preFile;
        ObjectInputStream in;

        preCacheDir = getPreCacheDir();
        preCacheFileName = preCacheDir + "/" + dicoFile.getName() + PRE_CACHE_FILE_EXT;
        //System.out.println(preCacheFileName);
        preFile = new File(preCacheFileName);
        if (!preFile.exists()) {
            //System.err.println("No precache file");
            return;
        }
        //System.out.println("Precaching...");
        in = new ObjectInputStream(new FileInputStream(preFile));
        try {
            size = in.readLong();
            for (int i = 0; i < size; i++) {
                code = (String)in.readObject();
                time = in.readLong();
                suggestions = (List)in.readObject();
                suggestionCache.put(code, new CacheObject(suggestions, time));
            }
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
        in.close();
    }

    /**
     * Saves the current cache to file.
     */
    public void saveCache() throws IOException {
        String code;
        CacheObject obj;
        File preFile;
        File preDir;
        ObjectOutputStream out;
        Iterator it;

        if (preCacheFileName == null || preCacheDir == null) {
            //System.err.println("Precache filename has not been set.");
            return;
        }
        //System.out.println("Saving cache to precache file...");
        preDir = new File(preCacheDir);
        if (!preDir.exists())
            preDir.mkdir();
        preFile = new File(preCacheFileName);
        out = new ObjectOutputStream(new FileOutputStream(preFile));
        it = suggestionCache.keySet().iterator();
        out.writeLong(suggestionCache.size());
        while (it.hasNext()) {
            code = it.next();
            obj = suggestionCache.get(code);
            out.writeObject(code);
            out.writeLong(obj.getRefTime());
            out.writeObject(obj.getSuggestionList());
        }
        out.close();
    }

    private static class CacheObject implements Serializable { // robert: static

        private List suggestions;
        private long refTime;

        CacheObject(List list) {
            this.suggestions = list;
        }

        CacheObject(List list, long time) {
            this.suggestions = list;
            this.refTime = time;
        }

        public List getSuggestionList() {
            return suggestions;
        }

        public void setRefTime() {
            refTime = System.currentTimeMillis();
        }

        public long getRefTime() {
            return refTime;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy