1 19 20 package org.openide.filesystems; 21 22 import java.io.BufferedInputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.OutputStream ; 26 import java.lang.ref.Reference ; 27 import java.lang.ref.WeakReference ; 28 import java.util.Date ; 29 import java.util.Enumeration ; 30 import java.util.HashSet ; 31 import java.util.Set ; 32 import java.util.logging.Logger ; 33 import org.openide.util.Lookup; 34 import org.openide.util.LookupEvent; 35 import org.openide.util.LookupListener; 36 import org.openide.util.Union2; 37 38 50 final class MIMESupport extends Object { 51 55 private static final Reference <FileObject> EMPTY = new WeakReference <FileObject>(null); 56 private static Reference <FileObject> lastFo = EMPTY; 57 private static Reference <FileObject> lastCfo = EMPTY; 58 private static Object lock = new Object (); 59 60 61 private static Logger ERR = Logger.getLogger(MIMESupport.class.getName()); 62 63 private MIMESupport() { 64 } 65 66 70 static String findMIMEType(FileObject fo, String def) { 71 if (!fo.isValid() || fo.isFolder()) { 72 return null; 73 } 74 75 if ((def != null) && !CachedFileObject.isAnyResolver()) { 76 return def; 77 } 78 79 CachedFileObject cfo = null; 80 81 try { 82 synchronized (lock) { 83 CachedFileObject lcfo = (CachedFileObject)lastCfo.get(); 84 if (lcfo == null || fo != lastFo.get() || timeOf(fo) != timeOf(lcfo)) { 85 cfo = new CachedFileObject(fo); 86 } else { 87 cfo = lcfo; 88 } 89 90 lastCfo = EMPTY; 91 } 92 93 return cfo.getMIMEType(def); 94 } finally { 95 synchronized (lock) { 96 lastFo = new WeakReference <FileObject>(fo); 97 lastCfo = new WeakReference <FileObject>(cfo); 98 } 99 } 100 } 101 private static long timeOf(FileObject fo) { 102 if (fo == null) { 103 throw new NullPointerException (); 104 } 105 Date d = fo.lastModified(); 106 assert d != null : "Null lastModified from " + fo; 107 return d.getTime(); 108 } 109 110 112 static MIMEResolver[] getResolvers() { 113 return CachedFileObject.getResolvers(); 114 } 115 116 private static class CachedFileObject extends FileObject implements FileChangeListener { 117 static Lookup.Result<MIMEResolver> result; 118 private static Union2<MIMEResolver[],Set <Thread >> resolvers; 120 private static MIMEResolver[] previousResolvers; 121 122 String mimeType; 123 java.util.Date lastModified; 124 CachedInputStream fixIt; 125 126 128 FileObject fileObj; 129 130 CachedFileObject(FileObject fo) { 131 fileObj = fo; 132 lastModified = fileObj.lastModified(); 133 fileObj.addFileChangeListener(FileUtil.weakFileChangeListener(this, fileObj)); 134 } 135 136 private static MIMEResolver[] getResolvers() { 137 Set <Thread > creators; 138 synchronized (CachedFileObject.class) { 139 if (resolvers != null && resolvers.hasFirst()) { 140 return resolvers.first(); 141 } 142 if (resolvers != null) { 143 creators = resolvers.second(); 144 if (creators.contains (Thread.currentThread())) { 145 ERR.fine("Stack Overflow prevention. Returning previousResolvers: " + previousResolvers); 147 MIMEResolver[] toRet = previousResolvers; 148 if (toRet == null) { 149 toRet = new MIMEResolver[0]; 150 } 151 return toRet; 152 } 153 } else { 154 creators = new HashSet <Thread >(); 155 resolvers = Union2.createSecond(creators); 156 } 157 158 if (result == null) { 159 result = Lookup.getDefault().lookupResult(MIMEResolver.class); 160 result.addLookupListener( 161 new LookupListener() { 162 public void resultChanged(LookupEvent evt) { 163 synchronized (CachedFileObject.class) { 164 ERR.fine("Clearing cache"); Union2<MIMEResolver[],Set <Thread >> prev = resolvers; 166 if (prev != null && prev.hasFirst()) { 167 previousResolvers = prev.first(); 168 } 169 resolvers = null; 170 lastFo = EMPTY; 171 lastCfo = EMPTY; 172 } 173 } 174 } 175 ); 176 } 177 178 creators.add(Thread.currentThread()); 180 } 181 182 ERR.fine("Computing resolvers"); 184 MIMEResolver[] toRet = result.allInstances().toArray(new MIMEResolver[0]); 185 186 ERR.fine("Resolvers computed"); 188 synchronized (CachedFileObject.class) { 189 if (resolvers != null && resolvers.hasSecond() && resolvers.second() == creators) { 190 resolvers = Union2.createFirst(toRet); 192 previousResolvers = null; 193 ERR.fine("Resolvers assigned"); } else { 195 ERR.fine("Somebody else computes resolvers: " + resolvers); } 197 198 199 return toRet; 200 } 201 } 202 203 public static boolean isAnyResolver() { 204 return getResolvers().length > 0; 205 } 206 207 public void freeCaches() { 208 fixIt = null; 209 mimeType = null; 210 lastModified = null; 211 } 212 213 public String getMIMEType() { 214 return getMIMEType(null); 215 } 216 217 public String getMIMEType(String def) { 218 if (mimeType == null) { 219 mimeType = resolveMIME(def); 220 } 221 222 return mimeType; 223 } 224 225 private String resolveMIME(String def) { 226 String retVal = null; 227 MIMEResolver[] local = getResolvers(); 228 229 try { 230 for (int i = 0; i < local.length; i++) { 231 retVal = local[i].findMIMEType(this); 232 233 if (retVal != null) { 234 return retVal; 235 } 236 } 237 238 if (def != null) { 239 return def; 240 } 241 242 return "content/unknown"; } finally { 244 if (fixIt != null) { 245 fixIt.internalClose(); 246 } 247 248 fixIt = null; 249 } 250 } 251 252 public java.util.Date lastModified() { 253 if (lastModified != null) { 254 return lastModified; 255 } 256 257 return lastModified = fileObj.lastModified(); 258 } 259 260 public InputStream getInputStream() throws java.io.FileNotFoundException { 261 if (fixIt == null) { 262 InputStream is = fileObj.getInputStream(); 263 264 if (!(is instanceof BufferedInputStream )) { 265 is = new BufferedInputStream (is); 266 } 267 268 fixIt = new CachedInputStream(is); 269 } 270 271 fixIt.cacheToStart(); 272 273 return fixIt; 274 } 275 276 public void fileChanged(FileEvent fe) { 277 freeCaches(); 278 } 279 280 public void fileDeleted(FileEvent fe) { 281 freeCaches(); 282 283 } 285 286 public void fileRenamed(FileRenameEvent fe) { 287 freeCaches(); 288 } 289 290 291 public FileObject getParent() { 292 return fileObj.getParent(); 293 } 294 295 @Deprecated public String getPackageNameExt(char separatorChar, char extSepChar) { 297 return fileObj.getPackageNameExt(separatorChar, extSepChar); 298 } 299 300 public FileObject copy(FileObject target, String name, String ext) 301 throws IOException { 302 return fileObj.copy(target, name, ext); 303 } 304 305 protected void fireFileDeletedEvent(Enumeration <FileChangeListener> en, FileEvent fe) { 306 fileObj.fireFileDeletedEvent(en, fe); 307 } 308 309 protected void fireFileFolderCreatedEvent(Enumeration <FileChangeListener> en, FileEvent fe) { 310 fileObj.fireFileFolderCreatedEvent(en, fe); 311 } 312 313 @Deprecated public void setImportant(boolean b) { 315 fileObj.setImportant(b); 316 } 317 318 public boolean isData() { 319 return fileObj.isData(); 320 } 321 322 public Object getAttribute(String attrName) { 323 return fileObj.getAttribute(attrName); 324 } 325 326 public Enumeration <? extends FileObject> getFolders(boolean rec) { 327 return fileObj.getFolders(rec); 328 } 329 330 public void delete(FileLock lock) throws IOException { 331 fileObj.delete(lock); 332 } 333 334 public boolean isRoot() { 335 return fileObj.isRoot(); 336 } 337 338 public Enumeration <? extends FileObject> getData(boolean rec) { 339 return fileObj.getData(rec); 340 } 341 342 public FileObject[] getChildren() { 343 return fileObj.getChildren(); 344 } 345 346 public String getNameExt() { 347 return fileObj.getNameExt(); 348 } 349 350 public boolean isValid() { 351 return fileObj.isValid(); 352 } 353 354 @Deprecated public boolean isReadOnly() { 356 return fileObj.isReadOnly(); 357 } 358 359 public String getExt() { 360 return fileObj.getExt(); 361 } 362 363 public String getName() { 364 return fileObj.getName(); 365 } 366 367 public void removeFileChangeListener(FileChangeListener fcl) { 368 fileObj.removeFileChangeListener(fcl); 369 } 370 371 protected void fireFileRenamedEvent(Enumeration <FileChangeListener> en, FileRenameEvent fe) { 372 fileObj.fireFileRenamedEvent(en, fe); 373 } 374 375 public void refresh(boolean expected) { 376 fileObj.refresh(expected); 377 } 378 379 protected void fireFileAttributeChangedEvent(Enumeration <FileChangeListener> en, FileAttributeEvent fe) { 380 fileObj.fireFileAttributeChangedEvent(en, fe); 381 } 382 383 public long getSize() { 384 return fileObj.getSize(); 385 } 386 387 public Enumeration <String > getAttributes() { 388 return fileObj.getAttributes(); 389 } 390 391 public void rename(FileLock lock, String name, String ext) 392 throws IOException { 393 fileObj.rename(lock, name, ext); 394 } 395 396 protected void fireFileChangedEvent(Enumeration <FileChangeListener> en, FileEvent fe) { 397 fileObj.fireFileChangedEvent(en, fe); 398 } 399 400 public FileObject getFileObject(String name, String ext) { 401 return fileObj.getFileObject(name, ext); 402 } 403 404 public void refresh() { 405 fileObj.refresh(); 406 } 407 408 public FileObject createData(String name, String ext) 409 throws IOException { 410 return fileObj.createData(name, ext); 411 } 412 413 public void addFileChangeListener(FileChangeListener fcl) { 414 fileObj.addFileChangeListener(fcl); 415 } 416 417 protected void fireFileDataCreatedEvent(Enumeration <FileChangeListener> en, FileEvent fe) { 418 fileObj.fireFileDataCreatedEvent(en, fe); 419 } 420 421 public boolean isFolder() { 422 return fileObj.isFolder(); 423 } 424 425 public FileObject createFolder(String name) throws IOException { 426 return fileObj.createFolder(name); 427 } 428 429 public Enumeration <? extends FileObject> getChildren(boolean rec) { 430 return fileObj.getChildren(rec); 431 } 432 433 public void setAttribute(String attrName, Object value) 434 throws IOException { 435 fileObj.setAttribute(attrName, value); 436 } 437 438 @Deprecated public String getPackageName(char separatorChar) { 440 return fileObj.getPackageName(separatorChar); 441 } 442 443 public FileSystem getFileSystem() throws FileStateInvalidException { 444 return fileObj.getFileSystem(); 445 } 446 447 public OutputStream getOutputStream(FileLock lock) 448 throws java.io.IOException { 449 return fileObj.getOutputStream(lock); 450 } 451 452 public boolean existsExt(String ext) { 453 return fileObj.existsExt(ext); 454 } 455 456 public FileObject move(FileLock lock, FileObject target, String name, String ext) 457 throws IOException { 458 return fileObj.move(lock, target, name, ext); 459 } 460 461 public FileLock lock() throws IOException { 462 return fileObj.lock(); 463 } 464 465 public void fileFolderCreated(FileEvent fe) { 466 } 467 468 public void fileDataCreated(FileEvent fe) { 469 } 470 471 public void fileAttributeChanged(FileAttributeEvent fe) { 472 } 473 474 476 public int hashCode() { 477 return fileObj.hashCode(); 478 } 479 480 public boolean equals(java.lang.Object obj) { 481 if (obj instanceof CachedFileObject) { 482 return ((CachedFileObject) obj).fileObj.equals(fileObj); 483 } 484 485 return super.equals(obj); 486 } 487 } 488 489 private static class CachedInputStream extends InputStream { 490 private InputStream inputStream; 491 private byte[] buffer = null; 492 private int len = 0; 493 private int pos = 0; 494 private boolean eof = false; 495 496 CachedInputStream(InputStream is) { 497 inputStream = is; 498 } 499 500 502 public void close() throws java.io.IOException { 503 } 504 505 void internalClose() { 506 try { 507 inputStream.close(); 508 } catch (IOException ioe) { 509 } 510 } 511 512 protected void finalize() { 513 internalClose(); 514 } 515 516 public int read() throws IOException { 517 if (eof) { 518 return -1; 519 } 520 521 int c; 522 int n; 523 524 if (pos < len) { 525 c = buffer[pos++]; 526 c = (c < 0) ? (c + 256) : c; 527 528 return c; 529 } 530 531 int buflen = (len > 0) ? (len * 2) : 256; 532 byte[] buf = new byte[buflen]; 533 534 if (len > 0) { 535 System.arraycopy(buffer, 0, buf, 0, len); 536 } 537 538 n = inputStream.read(buf, len, buflen - len); 539 540 if (n <= 0) { 541 eof = true; 542 543 return -1; 544 } 545 546 buffer = buf; 547 len += n; 548 549 c = buffer[pos++]; 550 c = (c < 0) ? (c + 256) : c; 551 552 return c; 553 } 554 555 void cacheToStart() { 556 pos = 0; 557 eof = false; 558 } 559 560 561 public String toString() { 562 String retVal = super.toString() + '[' + inputStream.toString() + ']' + '\n'; retVal += new String (buffer); 564 565 return retVal; 566 } 567 } 568 } 569 | Popular Tags |