KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > dotmarketing > util > DotSpellChecker


1 /*
2  * Created on 28/06/2005
3  *
4  */

5 package com.dotmarketing.util;
6
7 import java.io.File JavaDoc;
8 import java.io.FileFilter JavaDoc;
9 import java.io.FileNotFoundException JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import com.swabunga.spell.engine.SpellDictionary;
18 import com.swabunga.spell.engine.SpellDictionaryHashMap;
19 import com.swabunga.spell.engine.Word;
20 import com.swabunga.spell.event.AbstractWordFinder;
21 import com.swabunga.spell.event.SpellChecker;
22 import com.swabunga.spell.event.WordFinder;
23 import com.swabunga.spell.event.WordNotFoundException;
24
25 /**
26  * Class used via AJAX to spell checks fields in the dotCMS
27  * This class internally uses the Jazzy library and method to perform the spellchecking
28  * @author David
29  *
30  */

31 public class DotSpellChecker {
32
33     /**
34      * This class represent a misspelled word in the process of spelling check.
35      * @author david
36      *
37      */

38     public class MisspelledWord {
39         
40         /*
41          * The misspelled word
42          */

43         public String JavaDoc word;
44         /*
45          * The list of possible suggested corrections
46          */

47         public String JavaDoc[] suggestions;
48         /*
49          * The offset in the whole text when the word begins
50          */

51         public int wordBegin = -1;
52         /*
53          * The offset in the whole text when the word ends
54          */

55         public int wordEnd = -1;
56
57         /**
58          * Constructor of the class
59          * @param word The mispelled word
60          * @param suggestions The list of suggestions
61          */

62         public MisspelledWord(String JavaDoc word, String JavaDoc[] suggestions) {
63             super();
64             this.word = word;
65             this.suggestions = suggestions;
66         }
67
68         /**
69          * Constructor of the class
70          * @param word The mispelled word
71          * @param begin The offset in the whole text when the word begins
72          * @param end The offset in the whole text when the word ends
73          * @param suggestions The list of suggestions
74          */

75         public MisspelledWord(String JavaDoc word, int begin, int end, String JavaDoc[] suggestions) {
76             super();
77             this.word = word;
78             this.suggestions = suggestions;
79             wordBegin = begin;
80             wordEnd = end;
81         }
82
83         /**
84          * Returns the list of possible suggested corrections
85          * @return The list of possible suggested corrections
86          */

87         public String JavaDoc[] getSuggestions() {
88             return suggestions;
89         }
90
91         /**
92          * Sets the list of possible suggested corrections
93          * @param suggestions The list of possible suggested corrections
94          */

95         public void setSuggestions(String JavaDoc[] suggestions) {
96             this.suggestions = suggestions;
97         }
98
99         /**
100          * Returns the misspelled word
101          * @return The misspelled word
102          */

103         public String JavaDoc getWord() {
104             return word;
105         }
106
107         /**
108          * Sets the misspelled word
109          * @param word The misspelled word
110          */

111         public void setWord(String JavaDoc word) {
112             this.word = word;
113         }
114
115         /**
116          * Returns the offset in the whole text when the word begins
117          * @return The offset in the whole text when the word begins
118          */

119         public int getWordBegin() {
120             return wordBegin;
121         }
122
123         /**
124          * Sets the offset in the whole text when the word begins
125          * @param wordBegin The offset in the whole text when the word begins
126          */

127         public void setWordBegin(int wordBegin) {
128             this.wordBegin = wordBegin;
129         }
130
131         /**
132          * Returns the offset in the whole text when the word ends
133          * @return The offset in the whole text when the word ends
134          */

135         public int getWordEnd() {
136             return wordEnd;
137         }
138
139         /**
140          * Sets the offset in the whole text when the word ends
141          * @param wordEnd The offset in the whole text when the word ends
142          */

143         public void setWordEnd(int wordEnd) {
144             this.wordEnd = wordEnd;
145         }
146     }
147
148     /**
149      * Class internally used to match the words to spell check
150      * @author david
151      *
152      */

153     public class DotWordFinder extends AbstractWordFinder {
154
155         /**
156          * Constructor
157          * @param inText Text to find for the word.
158          */

159         public DotWordFinder(String JavaDoc inText) {
160             super(inText);
161         }
162
163         /**
164          * This method looks for the next word to be checked, in the process of looking for the next word this method
165          * ignores all the HTML and velocity reserved words and tags, those ones are not going to be spell checked.
166          * @return The matched word to be checked
167          */

168         public com.swabunga.spell.event.Word next() {
169
170             if (currentWord == null)
171                 throw new WordNotFoundException("No more words found.");
172
173             currentWord.copy(nextWord);
174
175             setSentenceIterator(currentWord);
176
177             int i = currentWord.getEnd();
178             boolean finished = false;
179             boolean started = false;
180
181             search: /* Find words. */
182             while (i < text.length() && !finished) {
183                 if (!started && isWordChar(i)) {
184                     nextWord.setStart(i++);
185                     started = true;
186                     continue search;
187                 } else if (started) {
188                     if (isWordChar(i)) {
189                         i++;
190                         continue search;
191                     } else {
192                         nextWord.setText(text.substring(nextWord.getStart(), i));
193                         finished = true;
194                         break search;
195                     }
196                 }
197
198                 int lastIndex = i;
199                 // Ignore things inside tags.
200
// ignore css styles
201
i = ignore(i, "<style", "/style>");
202                 // ignore javascripts
203
i = ignore(i, "<script", "/script>");
204                 // ignore html tags
205
i = ignore(i, "<", ">");
206                 // ignore html reserved chars like &nbsp; &lt; ...
207
i = ignore(i, "&", ";");
208                 // ignore velocity
209
i = ignore(i, "#end", "");
210                 i = ignore(i, "#", ")");
211                 i = ignore(i, "${", "}");
212                 i = ignore(i, "$!{", "}");
213
214                 if (lastIndex == i)
215                     i++;
216             }
217
218             if (!started) {
219                 nextWord = null;
220             } else if (!finished) {
221                 nextWord.setText(text.substring(nextWord.getStart(), i));
222             }
223
224             return currentWord;
225         }
226     }
227
228     private SpellChecker spellCheck = null;
229     private WordFinder finder = null;
230     private SpellDictionary personalDict = null;
231     private String JavaDoc currentDict = "";
232
233     private static Map JavaDoc<String JavaDoc, List JavaDoc<SpellDictionary>> dicts;
234     private static boolean initialized = false;
235
236     /**
237      * This method is used at the server startup to initialize the dictionaries,
238      * the dictionaries initilization process is a very time consuming task, that's why this
239      * process uses a separate thread to initialize the dictionaries on background.
240      * This process tries to read Config.getStringProperty("MASTER_DICTS_DIR") to find the base dictionaries
241      * directory inside the WEB-INF folder of the web application.
242      * @param force true If you want to force a reinitialization even if the dictionaries were already loaded before.
243      * @param sync true If you want to wait until the initialization finishes
244      */

245     public synchronized static void initializeDicts(boolean force, boolean sync) {
246         if (initialized && !force)
247             return;
248         initialized = true;
249
250         Thread JavaDoc initThread = new Thread JavaDoc("Spellchecker Init Thread") {
251             public void run() {
252                 Logger.debug(DotSpellChecker.class, "Initializing SpellChecker dicts thread");
253                 long before = System.currentTimeMillis();
254                 
255                 dicts = new HashMap JavaDoc<String JavaDoc, List JavaDoc<SpellDictionary>>();
256
257                 String JavaDoc dictsDirPath = Config.CONTEXT.getRealPath(Config.getStringProperty("MASTER_DICTS_DIR"));
258
259                 File JavaDoc dictsDir = new File JavaDoc(dictsDirPath);
260
261                 if (dictsDir.exists() && dictsDir.isDirectory()) {
262                     File JavaDoc[] dicsDirs = dictsDir.listFiles();
263
264                     if (dicsDirs.length == 0) {
265                         Logger.error(DotSpellChecker.class, "No dictionaries found inside: "
266                                 + dictsDir.getAbsolutePath());
267                     }
268
269                     for (int i = 0; i < dicsDirs.length; i++) {
270                         File JavaDoc currentDir = dicsDirs[i];
271                         if (currentDir.isDirectory()) {
272                             File JavaDoc[] dictFiles = currentDir.listFiles(new FileFilter JavaDoc() {
273                                 public boolean accept(File JavaDoc pathname) {
274                                     return pathname.isFile() && pathname.canRead()
275                                             && pathname.getName().endsWith(".dict");
276                                 }
277                             });
278                             File JavaDoc phonetFile = new File JavaDoc(currentDir.getAbsolutePath() + File.separator
279                                     + currentDir.getName() + ".phonet");
280                             boolean withPhonetFile = false;
281                             if (phonetFile.exists() && phonetFile.canRead())
282                                 withPhonetFile = true;
283
284                             List JavaDoc<SpellDictionary> spellDicts = new ArrayList JavaDoc<SpellDictionary>();
285                             for (int j = 0; j < dictFiles.length; j++) {
286                                 SpellDictionary dictionary = null;
287                                 try {
288                                     if (withPhonetFile) {
289                                         dictionary = new SpellDictionaryHashMap(dictFiles[j], phonetFile);
290                                     } else {
291                                         dictionary = new SpellDictionaryHashMap(dictFiles[j]);
292                                     }
293                                 } catch (Exception JavaDoc e) {
294                                     Logger.error(DotSpellChecker.class, "Exception initializing dictionaries", e);
295                                 }
296                                 spellDicts.add(dictionary);
297                             }
298                             if (dictFiles.length > 0)
299                                 dicts.put(currentDir.getName(), spellDicts);
300                         }
301                     }
302
303                 } else {
304                     Logger.error(DotSpellChecker.class, "MASTER_DICTS_DIR = " + dictsDir.getAbsolutePath() + " not found.");
305                 }
306
307                 long after = System.currentTimeMillis();
308
309                 Logger.debug(DotSpellChecker.class, "End Initializing SpellChecker dicts thread time: " + (after - before) + " ms.");
310
311             }
312         };
313         initThread.start();
314         if (sync)
315             try {
316                 initThread.join();
317             } catch (InterruptedException JavaDoc e) {
318                 Logger.error(DotSpellChecker.class, "Error Initializing SpellChecker dicts thread", e);
319             }
320
321     }
322
323     /**
324      * DotSpellCheck constructor
325      * This method will try to initialize the dictionaries if they weren't initilized before.
326      * @throws IOException If the process found an error reading the dictionaries
327      * @throws FileNotFoundException If the dictionaries are not found
328      */

329     public DotSpellChecker() throws FileNotFoundException JavaDoc, IOException JavaDoc {
330         super();
331
332         if (!DotSpellChecker.initialized) {
333             DotSpellChecker.initializeDicts(false, true);
334         }
335         
336         // Creating the spellchecker
337
spellCheck = new SpellChecker();
338
339         // Loading default dict
340
List JavaDoc defaultDics = null;
341         String JavaDoc defaultDicName = Config.getStringProperty("DEFAULT_DIC");
342         ;
343
344         if (UtilMethods.isSet(defaultDicName) && dicts.get(defaultDicName) != null) {
345             defaultDics = (List JavaDoc) dicts.get(defaultDicName);
346         }
347
348         if (defaultDics == null) {
349             List JavaDoc<String JavaDoc> keys = new ArrayList JavaDoc<String JavaDoc>(dicts.keySet());
350             defaultDicName = (String JavaDoc) keys.get(0);
351             defaultDics = (List JavaDoc) dicts.get(keys.get(0));
352         }
353
354         if (defaultDics != null) {
355             Iterator JavaDoc it = defaultDics.iterator();
356             while (it.hasNext()) {
357                 SpellDictionary dictionary = (SpellDictionary) it.next();
358                 spellCheck.addDictionary(dictionary);
359             }
360         } else
361             throw new FileNotFoundException JavaDoc("Default dictionary: " + defaultDicName + " not found.");
362
363         currentDict = defaultDicName;
364
365         String JavaDoc dictsDirPath = Config.CONTEXT.getRealPath(Config.getStringProperty("MASTER_DICTS_DIR"));
366         File JavaDoc personalDictFile = new File JavaDoc(dictsDirPath + File.separator + defaultDicName + File.separator
367                 + defaultDicName + ".personal");
368         if (!personalDictFile.exists())
369             personalDictFile.createNewFile();
370         if (personalDictFile.exists() && personalDictFile.canRead()) {
371             personalDict = new SpellDictionaryHashMap(personalDictFile);
372         }
373         spellCheck.addDictionary(personalDict);
374
375     }
376
377     /**
378      * Returns the current dictionary used by the class
379      * @return The current dictionary
380      */

381     public String JavaDoc getCurrentDictionary() {
382         return currentDict;
383     }
384
385     /**
386      * This method changes the current dictionrary used to do the spell checking
387      * @param newDict The new dictionary to set
388      * @return true If the new dictionary exists and was set correctly.
389      * @throws FileNotFoundException If the dictionary file wasn't found
390      * @throws IOException If the process wasn't able to read the new dictionary.
391      */

392     public boolean changeDictionary(String JavaDoc newDict) throws FileNotFoundException JavaDoc, IOException JavaDoc {
393
394         if (currentDict.equals(newDict))
395             return false;
396
397         // Loading default dict
398
List JavaDoc newDicts = null;
399
400         if (UtilMethods.isSet(newDict) && dicts.get(newDict) != null) {
401             newDicts = (List JavaDoc) dicts.get(newDict);
402         }
403
404         if (newDicts == null) {
405             throw new FileNotFoundException JavaDoc("Dictionary: " + newDict + " not found.");
406         }
407
408         // Creating the spellchecker
409
spellCheck = new SpellChecker();
410
411         Iterator JavaDoc it = newDicts.iterator();
412         while (it.hasNext()) {
413             SpellDictionary dictionary = (SpellDictionary) it.next();
414             spellCheck.addDictionary(dictionary);
415         }
416
417         String JavaDoc dictsDirPath = Config.CONTEXT.getRealPath(Config.getStringProperty("MASTER_DICTS_DIR"));
418         File JavaDoc personalDictFile = new File JavaDoc(dictsDirPath + File.separator + newDict + File.separator + newDict
419                 + ".personal");
420         if (!personalDictFile.exists())
421             personalDictFile.createNewFile();
422         if (personalDictFile.exists() && personalDictFile.canRead()) {
423             personalDict = new SpellDictionaryHashMap(personalDictFile);
424         }
425         spellCheck.addDictionary(personalDict);
426
427         currentDict = newDict;
428
429         return true;
430     }
431
432     /**
433      * Triggers the spelling check of the given text
434      * @param text The text to check.
435      */

436     public void startSpellChecking(String JavaDoc text) {
437         finder = new DotWordFinder(text);
438     }
439
440     /**
441      * Returns the next misspelled word found and the posible corrections.
442      * @return The next misspelled word class (which includes the corrections) or null if no more errors were found.
443      */

444     public MisspelledWord getNextMisspelledWord() {
445         boolean found = false;
446         while (finder.hasNext()) {
447             com.swabunga.spell.event.Word nextWord = finder.next();
448             if (nextWord.length() <= 0 || nextWord.getText().toUpperCase().equals(nextWord.getText()))
449                 continue;
450             String JavaDoc nextWordStr = nextWord.getText();
451             boolean firstInUpperCase = false;
452             if (Character.isUpperCase(nextWordStr.charAt(0))) {
453                 nextWordStr = Character.toLowerCase(nextWordStr.charAt(0))
454                         + ((nextWordStr.length() > 1) ? nextWordStr.substring(1, nextWordStr.length()) : "");
455                 firstInUpperCase = true;
456             }
457             List JavaDoc suggestions = spellCheck.getSuggestions(nextWordStr, 3);
458             String JavaDoc[] suggestionsArr = new String JavaDoc[suggestions.size()];
459             if (suggestions.size() > 0) {
460                 int i = 0;
461                 Iterator JavaDoc it = suggestions.iterator();
462                 while (it.hasNext()) {
463                     Word sug = (Word) it.next();
464                     if (sug.getCost() == 0) {
465                         found = false;
466                         break;
467                     }
468                     found = true;
469                     String JavaDoc sugStr = sug.getWord();
470                     if (firstInUpperCase) {
471                         sugStr = Character.toUpperCase(sugStr.charAt(0))
472                                 + ((sugStr.length() > 1) ? sugStr.substring(1, sugStr.length()) : "");
473                     }
474                     suggestionsArr[i++] = sugStr;
475                 }
476             } else {
477                 found = true;
478             }
479             if (found) {
480                 int wordPos = nextWord.getStart();
481                 int wordEnd = nextWord.getEnd();
482                 MisspelledWord word = new MisspelledWord(nextWord.getText(), wordPos, wordEnd, suggestionsArr);
483                 return word;
484             }
485         }
486         return null;
487     }
488
489     /**
490      * Replace the current mispelled word by the given word.
491      * @param newWord The correction to set.
492      * @return
493      */

494     public String JavaDoc replaceWord(String JavaDoc newWord) {
495         finder.replace(newWord);
496         return finder.getText();
497     }
498
499     /**
500      * Adds a word to the current dictionary.
501      * @param newWord The new word to be added to the dictionary.
502      */

503     public void addToDictionary(String JavaDoc newWord) {
504         if (personalDict != null)
505             personalDict.addWord(newWord);
506     }
507
508     /**
509      * This method allows you to find suggestions for a single word without starting the
510      * whole spelling process over a text.
511      * @param nextWord Word to find spelling suggestions
512      * @return A misspelledWord class containing the suggestions or null if no suggestions were found.
513      */

514     public MisspelledWord getSuggestions(String JavaDoc nextWord) {
515         boolean found = false;
516         if (!UtilMethods.isSet(nextWord))
517             return null;
518
519         String JavaDoc nextWordStr = nextWord;
520         boolean firstInUpperCase = false;
521         if (Character.isUpperCase(nextWordStr.charAt(0))) {
522             nextWordStr = Character.toLowerCase(nextWordStr.charAt(0))
523                     + ((nextWordStr.length() > 1) ? nextWordStr.substring(1, nextWordStr.length()) : "");
524             firstInUpperCase = true;
525         }
526
527         List JavaDoc suggestions = spellCheck.getSuggestions(nextWordStr, 3);
528         String JavaDoc[] suggestionsArr = new String JavaDoc[suggestions.size()];
529         if (suggestions.size() > 0) {
530             int i = 0;
531             Iterator JavaDoc it = suggestions.iterator();
532             while (it.hasNext()) {
533                 Word sug = (Word) it.next();
534                 found = true;
535                 String JavaDoc sugStr = sug.getWord();
536                 if (firstInUpperCase) {
537                     sugStr = Character.toUpperCase(sugStr.charAt(0))
538                             + ((sugStr.length() > 1) ? sugStr.substring(1, sugStr.length()) : "");
539                 }
540                 suggestionsArr[i++] = sugStr;
541             }
542         } else {
543             found = false;
544         }
545         if (found) {
546             MisspelledWord word = new MisspelledWord(nextWord, suggestionsArr);
547             return word;
548         }
549         return null;
550     }
551
552     /**
553      * Returns the list of possible dictionaries found in the system
554      * @return The list of loaded dictionaries.
555      */

556     public String JavaDoc[] getDictionaries() {
557         return (String JavaDoc[]) dicts.keySet().toArray(new String JavaDoc[0]);
558     }
559
560 }
561
Free Books   Free Magazines  
Popular Tags