1 21 22 package org.armedbear.j; 23 24 import java.io.BufferedReader ; 25 import java.io.BufferedWriter ; 26 import java.io.IOException ; 27 import java.io.InputStreamReader ; 28 import java.io.OutputStreamWriter ; 29 import java.util.ArrayList ; 30 import java.util.Collections ; 31 import java.util.Comparator ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Vector ; 35 36 public final class TagFileManager extends Thread  37 { 38 private static final String VERSION = "1"; 40 41 private final File tagFileDir; 42 private final TagFileCatalog catalog; 43 44 private Vector queue = new Vector (); 45 private boolean enabled = true; 46 47 private TagFileCache cache; 48 49 public TagFileManager() 50 { 51 super("tag file manager"); 52 setPriority(Thread.MIN_PRIORITY); 53 setDaemon(true); 54 tagFileDir = 55 File.getInstance(Directories.getEditorDirectory(), "tagfiles"); 56 catalog = new TagFileCatalog(tagFileDir); 57 if (initialize()) 58 start(); 59 } 60 61 public void run() 62 { 63 while (true) { 64 QueueEntry entry = getEntryFromQueue(); 65 refreshTagFile(entry); 66 } 67 } 68 69 private synchronized boolean initialize() 70 { 71 if (!tagFileDir.isDirectory()) { 72 tagFileDir.mkdirs(); 73 if (!tagFileDir.isDirectory()) { 74 Log.error("TagFileManager.run can't make directory ".concat(tagFileDir.canonicalPath())); 75 queue = null; 76 return false; 77 } 78 } 79 catalog.load(); 80 cleanup(); 81 return true; 82 } 83 84 public synchronized void addToQueue(File dir, Mode mode) 85 { 86 if (queue == null) 87 return; 88 if (dir.isRemote()) 89 return; 90 QueueEntry entry = new QueueEntry(dir, mode); 91 for (int i = queue.size()-1; i >= 0; i--) { 92 if (entry.equals(queue.get(i))) 93 return; 94 } 95 queue.add(entry); 96 notify(); 97 } 98 99 public synchronized void setEnabled(boolean b) 100 { 101 boolean wasEnabled = enabled; 102 enabled = b; 103 if (enabled && !wasEnabled) 104 notify(); 105 } 106 107 private boolean ready() 108 { 109 return enabled && queue.size() > 0; 110 } 111 112 private synchronized QueueEntry getEntryFromQueue() 113 { 114 while (!ready()) { 115 try { 116 wait(); 117 } 118 catch (InterruptedException e) { 119 Log.error(e); 120 } 121 } 122 return (QueueEntry) queue.remove(0); 123 } 124 125 private final File getTagFile(File dir, Mode mode) 126 { 127 return catalog.getTagFile(dir, mode); 128 } 129 130 public void makeTagFile(File dir, Mode mode) 131 { 132 Debug.assertTrue(mode != null); 133 try { 134 if (dir.isRemote()) 135 return; 136 File oldTagfile = getTagFile(dir, mode); 137 File tagfile = Utilities.getTempFile(tagFileDir); 138 if (tagfile != null) { 139 String [] files = dir.list(); 140 if (files != null) { 141 BufferedWriter writer = 142 new BufferedWriter (new OutputStreamWriter ( 143 tagfile.getOutputStream())); 144 writer.write(VERSION); 145 writer.write('\n'); 146 for (int i = 0; i < files.length; i++) { 147 File file = File.getInstance(dir, files[i]); 148 if (mode.accepts(file.getName()) && file.isFile()) { 149 SystemBuffer buf = new SystemBuffer(file); 150 buf.load(); 151 Tagger tagger = mode.getTagger(buf); 152 tagger.run(); 153 tagger.writeTags(writer); 154 buf._empty(); 155 } 156 } 157 writer.flush(); 158 writer.close(); 159 if (tagfile.length() == 0) { 160 tagfile.delete(); 161 } else { 162 catalog.addEntry(dir, tagfile, mode); 163 catalog.save(); 164 if (oldTagfile != null) { 165 oldTagfile.delete(); 166 if (cache != null) 167 cache.remove(oldTagfile); 168 } 169 } 170 } 171 } 172 } 173 catch (Exception e) { 174 Log.error(e); 175 } 176 } 177 178 private boolean isTagFileOutOfDate(QueueEntry entry) 179 { 180 if (entry.directory.isRemote()) 181 return false; 182 File tagfile = getTagFile(entry.directory, entry.mode); 183 if (tagfile == null) 184 return true; 185 if (!tagfile.exists()) 186 return true; 187 long tagfileLastModified = tagfile.lastModified(); 188 String [] files = entry.directory.list(); 189 if (files != null) { 190 for (int i = 0; i < files.length; i++) { 191 File file = File.getInstance(entry.directory, files[i]); 192 if (!file.isFile()) 193 continue; 194 if (entry.mode.accepts(file.getName())) 195 if (file.lastModified() > tagfileLastModified) 196 return true; 197 } 198 } 199 return false; 200 } 201 202 private void refreshTagFile(QueueEntry queueEntry) 203 { 204 if (isTagFileOutOfDate(queueEntry)) 205 makeTagFile(queueEntry.directory, queueEntry.mode); 206 } 207 208 private synchronized void cleanup() 209 { 210 final int days = 5; 211 final long cutoff = System.currentTimeMillis() - 24 * 60 * 60 * 1000 * days; 212 String [] files = tagFileDir.list(); 213 for (int i = 0; i < files.length; i++) { 214 String name = files[i]; 215 if (name.equals("catalog")) { 216 continue; 218 } 219 File file = File.getInstance(tagFileDir, name); 220 if (!file.isFile()) 221 continue; 222 if (catalog.containsTagFileName(name) && file.lastModified() > cutoff) 223 continue; 224 file.delete(); 225 } 226 catalog.update(); 227 } 228 229 public List getTags(File directory, Mode mode) 230 { 231 File tagFile = getTagFile(directory, mode); 232 if (tagFile == null) { 233 Log.debug("getTags no tag file " + directory + " " + mode); 234 return null; 235 } 236 if (!tagFile.isFile()) { 237 Log.debug("getTags tag file doesn't exist"); 238 return null; 239 } 240 List tags = null; 241 if (cache != null) 243 tags = cache.getTags(tagFile); 244 if (tags == null) { 245 try { 246 BufferedReader reader = 247 new BufferedReader (new InputStreamReader (tagFile.getInputStream())); 248 String s = reader.readLine(); 249 if (s != null && s.equals(VERSION)) { 250 tags = new ArrayList (); 251 while ((s = reader.readLine()) != null) { 252 GlobalTag tag = GlobalTag.makeGlobalTag(s); 253 if (tag != null) 254 tags.add(tag); 255 } 256 } else { 257 Log.warn("getTags wrong version " + directory + " " + 258 mode); 259 } 260 reader.close(); 261 } 262 catch (IOException e) { 263 Log.error(e); 264 } 265 if (tags != null) { 266 if (cache == null) 267 cache = new TagFileCache(); 268 cache.add(directory, mode.toString(), tagFile, tags); 269 } else 270 tagFile.delete(); 271 } 272 return tags; 273 } 274 275 private static class QueueEntry 276 { 277 final File directory; 278 final Mode mode; 279 280 QueueEntry(File directory, Mode mode) 281 { 282 this.directory = directory; 283 this.mode = mode; 284 } 285 286 public boolean equals(Object obj) 287 { 288 if (this == obj) 289 return true; 290 if (obj instanceof QueueEntry) { 291 QueueEntry qe = (QueueEntry) obj; 292 if (!directory.equals(qe.directory)) 293 return false; 294 if (mode == qe.mode) 296 return true; 297 if (mode != null && mode.equals(qe.mode)) 298 return true; 299 } 300 return false; 301 } 302 } 303 304 private static class TagFileCache 305 { 306 private static final int MAX_FILES = 5; 307 308 private ArrayList list = new ArrayList (MAX_FILES); 309 310 TagFileCache() {} 311 312 synchronized List getTags(File tagFile) 313 { 314 Iterator iter = list.iterator(); 315 while (iter.hasNext()) { 316 CacheEntry entry = (CacheEntry) iter.next(); 317 if (entry.tagFile.equals(tagFile)) { 318 entry.lastAccess = System.currentTimeMillis(); 319 ArrayList newList = new ArrayList (MAX_FILES); 321 newList.add(entry); 322 for (int i = 0; i < list.size(); i++) { 323 CacheEntry e = (CacheEntry) list.get(i); 324 if (e != entry) 325 newList.add(e); 326 } 327 Debug.assertTrue(newList.size() == list.size()); 328 list = newList; 329 checkOrder(); 330 return entry.tags; 331 } 332 } 333 return null; 334 } 335 336 synchronized void add(File directory, String modeName, 337 File tagFile, List tags) 338 { 339 CacheEntry entry = new CacheEntry(directory, modeName, tagFile, tags); 340 ArrayList newList = new ArrayList (MAX_FILES); 341 newList.add(entry); 342 int count = 1; 343 for (int i = 0; i < list.size() && count < MAX_FILES; i++) { 344 CacheEntry e = (CacheEntry) list.get(i); 345 if (!e.tagFile.equals(tagFile)) { 346 newList.add(e); 347 ++count; 348 } 349 } 350 list = newList; 351 checkOrder(); 352 } 353 354 synchronized void remove(File tagFile) 355 { 356 Iterator iter = list.iterator(); 357 while (iter.hasNext()) { 358 CacheEntry entry = (CacheEntry) iter.next(); 359 if (entry.tagFile.equals(tagFile)) { 360 iter.remove(); 361 checkOrder(); 362 Log.debug("cache remove size = " + list.size()); 363 return; 364 } 365 } 366 } 368 369 void checkOrder() 371 { 372 if (Editor.isDebugEnabled()) { 373 for (int i = 0; i < list.size()-1; i++) { 374 CacheEntry entry1 = (CacheEntry) list.get(i); 375 CacheEntry entry2 = (CacheEntry) list.get(i+1); 376 if (entry1.lastAccess < entry2.lastAccess) 377 Debug.bug(); 378 } 379 } 381 } 382 383 } 390 391 private static class CacheEntry 392 { 393 final File directory; final String modeName; final File tagFile; 396 List tags; 397 long lastAccess; 399 CacheEntry(File directory, String modeName, File tagFile, 400 List tags) 401 { 402 this.directory = directory; 403 this.modeName = modeName; 404 this.tagFile = tagFile; 405 this.tags = tags; 406 this.lastAccess = System.currentTimeMillis(); 407 } 408 409 public String toString() 410 { 411 return directory.canonicalPath() + " " + modeName + " " + 412 String.valueOf(lastAccess); 413 } 414 } 415 } 416 | Popular Tags |