KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > core > scripting > FileObserverThread


1 /*
2   The contents of this file are subject to the Mozilla Public License Version 1.1
3   (the "License"); you may not use this file except in compliance with the
4   License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
5   
6   Software distributed under the License is distributed on an "AS IS" basis,
7   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
8   for the specific language governing rights and
9   limitations under the License.
10
11   The Original Code is "The Columba Project"
12   
13   The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
14   Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
15   
16   All Rights Reserved.
17 */

18 package org.columba.core.scripting;
19
20 import java.io.File JavaDoc;
21 import java.io.FileFilter JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Vector JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30 import java.util.regex.Pattern JavaDoc;
31
32 import org.columba.core.gui.scripting.ScriptManagerDocument;
33 import org.columba.core.scripting.config.BeanshellConfig;
34 import org.columba.core.scripting.config.OptionsObserver;
35 import org.columba.core.scripting.interpreter.InterpreterManager;
36 import org.columba.core.scripting.model.ColumbaScript;
37
38 /**
39  The FileObserverThread is a timer that polls the file system to check if any
40  new .bsh scripts were created or existing scripts modified, since the last
41  time it was run.<br>
42  <br>
43  The polling behaviour can be enabled or disabled in the &lt;columba
44  dir&gt;/scripts/config.xml, as well as the polling interval. <br>
45  <br>
46  The default polling interval is of 5 seconds.
47
48  @author Celso Pinto (cpinto@yimports.com)
49 */

50 public class FileObserverThread
51     extends Thread JavaDoc
52     implements OptionsObserver,
53                 ScriptManagerDocument
54 {
55
56     private static final Logger JavaDoc LOG = Logger.getLogger(FileObserverThread.class.getName());
57
58     private final BeanshellConfig config;
59     private final ScriptFileFilter fileFilter;
60     private final InterpreterManager interpreterManager;
61     private final List JavaDoc observers;
62     private Map JavaDoc<String JavaDoc,ColumbaScript> scriptList;
63
64     private long lastExecution;
65     private int pollingInterval = -1;
66     private boolean finish = false;
67
68     private static FileObserverThread self = null;
69
70     private FileObserverThread()
71     {
72
73         config = BeanshellConfig.getInstance();
74         fileFilter = new ScriptFileFilter();
75         interpreterManager = new InterpreterManager();
76
77         scriptList = new HashMap JavaDoc<String JavaDoc, ColumbaScript>();
78         observers = new Vector JavaDoc();
79         lastExecution = System.currentTimeMillis();
80
81         pollingInterval = config.getOptions().getInternalPollingInterval();
82         fileFilter.compileFilter(interpreterManager.getSupportedExtensions());
83
84     }
85
86     public void setScriptList(Map JavaDoc scripts)
87     {
88         scriptList = scripts;
89     }
90
91     public void finish()
92     {
93         finish = true;
94     }
95
96     private synchronized void executeRefresh(boolean force)
97     {
98         List JavaDoc changedFiles = checkFiles();
99
100         if (changedFiles.size() > 0)
101             execChangedFiles(changedFiles);
102
103         lastExecution = System.currentTimeMillis();
104
105     }
106
107     public void run()
108     {
109         config.getOptions().addObserver(this);
110
111         while (!finish)
112         {
113
114             executeRefresh(false);
115
116             try
117             {
118                 sleep(pollingInterval);
119             }
120             catch (InterruptedException JavaDoc ex)
121             {}
122
123         }
124
125         config.getOptions().removeObserver(this);
126         self = null;
127     }
128
129     private List JavaDoc checkFiles()
130     {
131
132         List JavaDoc changedFiles = new ArrayList JavaDoc(),
133             removedScripts = new ArrayList JavaDoc(),
134             addedScripts = new ArrayList JavaDoc();
135
136         // check current file list for changes
137
ColumbaScript script = null;
138         Map.Entry JavaDoc entry = null;
139
140         synchronized (scriptList)
141         {
142
143             for (Iterator JavaDoc itCurrent = scriptList.entrySet().iterator(); itCurrent.hasNext();)
144             {
145                 entry = (Map.Entry JavaDoc) itCurrent.next();
146                 script = (ColumbaScript) entry.getValue();
147                 
148                 LOG.fine("current script.name="+script.getName());
149                 LOG.fine("current script.path="+script.getPath());
150                 
151                 if (!script.exists())
152                 {
153                     // it isn't possible to undo whatever the script did
154
removedScripts.add(script);
155                     itCurrent.remove();
156                     continue;
157                 }
158
159                 if (script.getLastModified() > lastExecution)
160                     changedFiles.add(script);
161
162             }
163
164             /* check for new files in the scripts directory */
165             File JavaDoc[] scripts = getNewScripts();
166             LOG.fine("script file count="+scripts.length);
167             
168             for (int i = 0; i < scripts.length; i++)
169             {
170                 LOG.fine("script file="+scripts[i].getAbsolutePath());
171                 
172                 if (!scriptList.containsKey(scripts[i].getPath()))
173                 {
174                     script = new ColumbaScript(scripts[i]);
175                     
176                     LOG.fine("added script.name="+script.getName());
177                     LOG.fine("added script.path="+script.getPath());
178                     
179                     changedFiles.add(script);
180                     scriptList.put(scripts[i].getPath(), script);
181                     addedScripts.add(script);
182                 }
183             }
184
185         }
186
187         for (Iterator JavaDoc it = observers.iterator(); it.hasNext();)
188         {
189
190             IScriptsObserver obs = (IScriptsObserver) it.next();
191             if (removedScripts.size() > 0)
192                 obs.scriptsRemoved(removedScripts);
193
194             if (addedScripts.size() > 0)
195                 obs.scriptsAdded(addedScripts);
196
197             if (changedFiles.size() > 0)
198                 obs.scriptsChanged(changedFiles);
199
200         }
201
202         return changedFiles;
203
204     }
205
206     private File JavaDoc[] getNewScripts()
207     {
208         /*
209            * I specifically want this here to ensure that the directory exists and
210            * this method never returns null.
211            *
212            * Any files that were in the observation list have already been
213            * previously removed by checkFiles().
214            */

215         File JavaDoc configPath = config.getPath();
216         if (!configPath.exists() || !configPath.isDirectory())
217         {
218             LOG.warning("Scripts directory doesn't exist:" + configPath.getPath());
219             return new File JavaDoc[]{};
220         }
221
222         LOG.fine("script search path="+configPath.getAbsolutePath());
223         
224         return configPath.listFiles(fileFilter);
225     }
226
227     private void execChangedFiles(List JavaDoc files)
228     {
229         for (Iterator JavaDoc it = files.iterator(); it.hasNext();)
230             interpreterManager.executeScript((ColumbaScript) it.next());
231     }
232
233     private class ScriptFileFilter
234         implements FileFilter JavaDoc
235     {
236
237         private Pattern JavaDoc extensionPattern = null;
238
239         private String JavaDoc join(String JavaDoc[] values, char separator)
240         {
241
242             StringBuffer JavaDoc bf = new StringBuffer JavaDoc(256);
243             for (int i = 0; i < values.length; i++)
244                 bf = bf.append(values[i] + separator);
245
246             if (bf.length() > 0) bf = bf.deleteCharAt(bf.length() - 1);
247
248             return bf.toString();
249
250         }
251
252         public void compileFilter(String JavaDoc[] validExtensions)
253         {
254             extensionPattern =
255                 Pattern.compile(".*\\.(".concat(join(validExtensions, '|')).concat(")$"));
256             LOG.fine("valid extensions pattern="+extensionPattern.toString());
257         }
258
259         public boolean accept(File JavaDoc aPathname)
260         {
261             boolean accept = extensionPattern.matcher(aPathname.getPath()).matches();
262             LOG.fine("accept="+aPathname.getAbsolutePath() + " -> "+accept);
263             
264             return accept;
265         }
266
267     }
268
269     public void pollingIntervalChanged(int interval)
270     {
271         pollingInterval = interval;
272     }
273
274     public void pollingStateChanged(boolean enabled)
275     {
276         /*TODO stop polling thread?! */
277     }
278
279     public static FileObserverThread getInstance()
280     {
281         if (self == null)
282             self = new FileObserverThread();
283
284         return self;
285     }
286
287     public void addObserver(IScriptsObserver observer)
288     {
289         if (!observers.contains(observer)) observers.add(observer);
290     }
291
292     public void removeObserver(IScriptsObserver observer)
293     {
294         observers.remove(observer);
295     }
296
297     public List JavaDoc getScripts()
298     {
299         return new ArrayList JavaDoc<ColumbaScript>(scriptList.values());
300     }
301
302     public void refreshScriptList()
303     {
304         executeRefresh(true);
305     }
306
307     public ColumbaScript getScript(String JavaDoc path)
308     {
309         return (ColumbaScript) scriptList.get(path);
310     }
311
312     public void removeScript(ColumbaScript[] scripts)
313     {
314
315         synchronized (scriptList)
316         {
317
318             for (int i = 0; i < scripts.length; i++)
319             {
320
321                 /* really delete file */
322                 LOG.fine("Removing script: " + scripts[i].getPath());
323
324                 if (scripts[i].exists()) scripts[i].deleteFromDisk();
325
326                 /* remove from script list */
327                 scriptList.remove(scripts[i].getPath());
328
329             }
330
331         }
332
333         List JavaDoc removed = Arrays.asList(scripts);
334         for (Iterator JavaDoc it = observers.iterator(); it.hasNext();)
335             ((IScriptsObserver) it.next()).scriptsRemoved(removed);
336
337     }
338
339 }
340
Popular Tags