1 19 20 package org.netbeans.modules.java.source.parsing; 21 22 import java.io.ByteArrayInputStream ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.InputStreamReader ; 26 import java.io.OutputStream ; 27 import java.io.OutputStreamWriter ; 28 import java.io.Reader ; 29 import java.io.StringReader ; 30 import java.io.UnsupportedEncodingException ; 31 import java.net.URI ; 32 import java.nio.CharBuffer ; 33 import java.util.Set ; 34 import javax.lang.model.element.Modifier; 35 import javax.lang.model.element.NestingKind; 36 import javax.swing.text.BadLocationException ; 37 import javax.swing.text.Document ; 38 import javax.swing.text.StyledDocument ; 39 import javax.tools.JavaFileObject; 40 import org.netbeans.api.java.lexer.JavaTokenId; 41 import org.netbeans.modules.java.source.parsing.DocumentProvider; 42 import org.netbeans.api.lexer.TokenHierarchy; 43 import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation; 44 import org.openide.ErrorManager; 45 import org.openide.cookies.EditorCookie; 46 import org.openide.filesystems.FileLock; 47 import org.openide.filesystems.FileObject; 48 import org.openide.filesystems.FileStateInvalidException; 49 import org.openide.loaders.DataObject; 50 import org.openide.loaders.DataObjectNotFoundException; 51 import org.openide.text.NbDocument; 52 53 57 public class SourceFileObject implements JavaFileObject, DocumentProvider { 58 59 final FileObject file; 60 private final Kind kind; 61 private URI uri; private String text; 63 private TokenHierarchy tokens; 64 private final JavaFileFilterImplementation filter; 65 66 public static SourceFileObject create (final FileObject file) { 67 try { 68 return new SourceFileObject (file, null, false); 69 } catch (IOException ioe) { 70 ErrorManager.getDefault().notify(ioe); 71 return null; 72 } 73 } 74 75 76 public SourceFileObject (final FileObject file, final JavaFileFilterImplementation filter, final boolean renderNow) throws IOException { 77 assert file != null; 78 this.file = file; 79 this.filter = filter; 80 String ext = this.file.getExt(); 81 if (FileObjects.JAVA.equalsIgnoreCase(ext)) { this.kind = Kind.SOURCE; 83 } 84 else if (FileObjects.CLASS.equalsIgnoreCase(ext)) { this.kind = Kind.CLASS; 86 } 87 else if (FileObjects.HTML.equalsIgnoreCase(ext)) { this.kind = Kind.HTML; 89 } 90 else { 91 this.kind = Kind.OTHER; 92 } 93 if (renderNow) { 94 text = getCharContentImpl().toString(); 95 } 96 } 97 98 99 100 public boolean isNameCompatible (String simplename, JavaFileObject.Kind kind) { 101 assert simplename != null; 102 return this.kind == kind && this.getNameWithoutExtension().equals(simplename); 103 } 104 105 public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { 106 String _text; 107 synchronized (this) { 108 _text = this.text; 109 } 110 if (_text != null) { 111 return CharBuffer.wrap(_text); 112 } 113 else { 114 return getCharContentImpl(); 115 } 116 } 117 118 public TokenHierarchy getTokenHierarchy() throws IOException { 119 if (tokens == null) 120 getCharContentImpl(); 121 122 return tokens; 123 } 124 125 126 public java.io.Writer openWriter() throws IOException { 127 return new OutputStreamWriter (this.openOutputStream(),FileObjects.encodingName); 128 } 129 130 public Reader openReader(boolean ignoreEncodingErrors) throws IOException { 131 String _text; 132 synchronized (this) { 133 _text = text; 134 } 135 if (_text != null) { 136 return new StringReader (_text); 137 } 138 else { 139 final Document doc = getDocument(isOpened()); 140 if (doc == null) { 141 Reader r = new InputStreamReader (this.file.getInputStream(),FileObjects.encodingName); 142 if (filter != null) { 143 r = filter.filterReader(r); 144 } 145 return r; 146 } 147 else { 148 final StringBuilder builder = new StringBuilder (); 149 doc.render(new Runnable () { 150 public void run () { 151 try { 152 builder.append(doc.getText(0, doc.getLength())); 153 } catch (BadLocationException e) { 154 ErrorManager.getDefault().notify(e); 155 } 156 } 157 }); 158 return new StringReader (builder.toString()); 159 } 160 } 161 } 162 163 public java.io.OutputStream openOutputStream() throws IOException { 164 final StyledDocument doc = getDocument(isOpened()); 165 if (doc == null) { 166 return new LckStream (this.file); 167 } 168 else { 169 return new DocumentStream (doc); 170 } 171 } 172 173 public InputStream openInputStream() throws IOException { 174 String _text; 175 synchronized (this) { 176 _text = text; 177 } 178 if (_text != null) { 179 return new ByteArrayInputStream (_text.getBytes()); 180 } 181 else { 182 final Document doc = getDocument(isOpened()); 183 if (doc == null) { 184 return this.file.getInputStream(); 185 } 186 else { 187 final StringBuilder builder = new StringBuilder (); 188 doc.render(new Runnable () { 189 public void run () { 190 try { 191 builder.append(doc.getText(0, doc.getLength())); 192 } catch (BadLocationException e) { 193 ErrorManager.getDefault().notify(e); 194 } 195 } 196 }); 197 return new ByteArrayInputStream (builder.toString().getBytes()); 198 } 199 } 200 } 201 202 public boolean delete() { 203 if (isModified()!=null) { 204 return false; 206 } 207 else { 208 try { 209 FileLock lock = this.file.lock(); 210 try { 211 this.file.delete (lock); 212 return true; 213 } 214 finally { 215 lock.releaseLock(); 216 } 217 } catch (IOException e) { 218 return false; 219 } 220 } 221 } 222 223 224 public JavaFileObject.Kind getKind() { 225 return this.kind; 226 } 227 228 public String getName() { 229 return this.file.getNameExt(); 230 } 231 232 public String getNameWithoutExtension() { 233 return this.file.getName(); 234 } 235 236 public synchronized URI toUri () { 237 if (this.uri == null) { 238 try { 239 this.uri = URI.create(this.file.getURL().toExternalForm()); 240 } catch (FileStateInvalidException e) { 241 ErrorManager.getDefault().notify(e); 242 } 243 } 244 return this.uri; 245 } 246 247 252 public long getLastModified() { 253 if (isModified()==null) { 254 return this.file.lastModified().getTime(); 255 } 256 else { 257 return System.currentTimeMillis(); 258 } 259 } 260 261 public NestingKind getNestingKind() { 262 return null; 263 } 264 265 public Modifier getAccessLevel() { 266 return null; 267 } 268 269 public @Override String toString () { 270 return this.file.getPath(); 271 } 272 273 public @Override boolean equals (Object other) { 274 if (other instanceof SourceFileObject) { 275 SourceFileObject otherSource = (SourceFileObject) other; 276 return this.file.equals (otherSource.file); 277 } 278 else { 279 return false; 280 } 281 } 282 283 public @Override int hashCode () { 284 return this.file.hashCode(); 285 } 286 287 public StyledDocument getDocument() { 288 EditorCookie ec = isOpened(); 289 return ec != null ? getDocument(ec) : null; 290 } 291 292 public void runAtomic(final Runnable r) { 293 assert r != null; 294 final StyledDocument doc = getDocument(); 295 if (doc == null) { 296 throw new IllegalStateException (); 297 } 298 else { 299 NbDocument.runAtomic(doc,r); 300 } 301 } 302 303 @SuppressWarnings ("unchecked") private EditorCookie isModified () { 305 DataObject.Registry regs = DataObject.getRegistry(); 306 Set <DataObject> modified = (Set <DataObject>) regs.getModifiedSet(); 307 for (DataObject dobj : modified) { 308 if (this.file.equals(dobj.getPrimaryFile())) { 309 EditorCookie ec = (EditorCookie) dobj.getCookie(EditorCookie.class); 310 return ec; 311 } 312 } 313 return null; 314 } 315 316 public EditorCookie isOpened () { 317 try { 318 if (this.kind == JavaFileObject.Kind.CLASS) { 319 return null; 320 } 321 DataObject dobj = DataObject.find(this.file); 322 return (EditorCookie) dobj.getCookie(EditorCookie.class); 323 } catch (DataObjectNotFoundException dnf) { 324 return null; 325 } 326 } 327 328 private CharBuffer getCharContentImpl () throws IOException { 329 final Document doc = getDocument(isOpened()); 330 final char[][] result = new char[1][]; 331 final int[] length = new int[1]; 332 if (doc == null) { 333 Reader in = this.openReader (true); 334 int red = 0, rv; 335 try { 336 int len = (int)this.file.getSize(); 337 result[0] = new char [len+1]; 338 while ((rv=in.read(result[0],red,len-red))>0 && (red=red+rv)<len); 339 } finally { 340 in.close(); 341 } 342 int j=0; 343 for (int i=0; i<red;i++) { 344 if (result[0][i] =='\r') { if (i+1>=red || result[0][i+1]!='\n') { result[0][j++] = '\n'; } 348 } 349 else { 350 result[0][j++] = result[0][i]; 351 } 352 } 353 length[0] = j; 354 } 355 else { 356 doc.render(new Runnable () { 357 public void run () { 358 try { 359 int len = doc.getLength(); 360 result[0] = new char[len+1]; 361 doc.getText(0,len).getChars(0,len,result[0],0); 362 length[0] = len; 363 } catch (BadLocationException e) { 364 ErrorManager.getDefault().notify(e); 365 } 366 } 367 }); 368 } 369 result[0][length[0]]='\n'; CharBuffer charBuffer = CharBuffer.wrap (result[0],0,length[0]); 371 tokens = doc == null ? TokenHierarchy.create(charBuffer, true, JavaTokenId.language(), null, null) : TokenHierarchy.get(doc); return charBuffer; 373 } 374 375 private static StyledDocument getDocument (EditorCookie ec) { 376 return ec == null ? null : ec.getDocument(); 377 } 378 379 380 private class LckStream extends OutputStream { 381 382 private final OutputStream delegate; 383 private final FileLock lock; 384 385 public LckStream (final FileObject fo) throws IOException { 386 assert fo != null; 387 this.lock = fo.lock(); 388 try { 389 this.delegate = fo.getOutputStream (this.lock); 390 } finally { 391 if (this.delegate == null) { 392 this.lock.releaseLock(); 393 } 394 } 395 } 396 397 public @Override void write(byte[] b, int off, int len) throws IOException { 398 this.delegate.write(b, off, len); 399 } 400 401 public @Override void write(byte[] b) throws IOException { 402 this.delegate.write(b); 403 } 404 405 public void write(int b) throws IOException { 406 this.delegate.write (b); 407 } 408 409 public @Override void close() throws IOException { 410 try { 411 this.delegate.close(); 412 } finally { 413 this.lock.releaseLock(); 414 synchronized (SourceFileObject.this) { 415 text = null; 416 } 417 } 418 } 419 } 420 421 private class DocumentStream extends OutputStream { 422 423 private static final int BUF_SIZ=2048; 424 425 private final StyledDocument doc; 426 private byte[] data; 427 private int pos; 428 429 public DocumentStream (final StyledDocument doc) { 430 assert doc != null; 431 this.doc = doc; 432 this.data = new byte[BUF_SIZ]; 433 this.pos = 0; 434 } 435 436 public synchronized @Override void write(byte[] b, int off, int len) throws IOException { 437 ensureSize (len); 438 System.arraycopy(b,off,this.data,this.pos,len); 439 this.pos+=len; 440 } 441 442 public synchronized @Override void write(byte[] b) throws IOException { 443 ensureSize (b.length); 444 System.arraycopy(b,0,this.data,this.pos,b.length); 445 this.pos+=b.length; 446 } 447 448 public synchronized void write(int b) throws IOException { 449 ensureSize (1); 450 this.data[this.pos++]=(byte)(b&0xff); 451 } 452 453 private void ensureSize (int delta) { 454 int requiredLength = this.pos + delta; 455 if (this.data.length<requiredLength) { 456 int newSize = this.data.length + BUF_SIZ; 457 while (newSize<requiredLength) { 458 newSize+=BUF_SIZ; 459 } 460 byte[] newData = new byte[newSize]; 461 System.arraycopy(this.data,0,newData,0,this.pos); 462 this.data = newData; 463 } 464 } 465 466 public synchronized @Override void close() throws IOException { 467 try { 468 NbDocument.runAtomic(this.doc, 469 new Runnable () { 470 public void run () { 471 try { 472 doc.remove(0,doc.getLength()); 473 doc.insertString(0,new String (data,0,pos,FileObjects.encodingName),null); 474 } catch (BadLocationException e) { 475 ErrorManager.getDefault().notify(e); 476 } 477 catch (UnsupportedEncodingException ee) { 478 ErrorManager.getDefault().notify (ee); 479 } 480 } 481 }); 482 } finally { 483 synchronized (SourceFileObject.this) { 484 text = null; 485 } 486 } 487 } 488 } 489 } 490 | Popular Tags |