1 19 20 package org.netbeans.core.xml; 21 22 import java.io.IOException ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.BufferedInputStream ; 25 import java.io.InputStream ; 26 27 import org.xml.sax.InputSource ; 28 import org.xml.sax.SAXException ; 29 import org.w3c.dom.DocumentType ; 30 31 32 import org.openide.filesystems.FileObject; 33 import org.openide.filesystems.Repository; 34 import org.openide.loaders.*; 35 import org.openide.cookies.InstanceCookie; 36 import org.openide.util.Lookup; 37 import org.openide.util.lookup.*; 38 import org.openide.xml.EntityCatalog; 39 import org.openide.filesystems.FileChangeListener; 40 import org.openide.filesystems.FileRenameEvent; 41 import org.openide.filesystems.FileEvent; 42 import org.openide.filesystems.FileAttributeEvent; 43 import java.net.URL ; 44 import java.util.logging.Level ; 45 import java.util.logging.Logger ; 46 import org.openide.util.Exceptions; 47 48 49 66 public final class FileEntityResolver extends EntityCatalog implements Environment.Provider { 67 private static final String ENTITY_PREFIX = "/xml/entities"; private static final String LOOKUP_PREFIX = "/xml/lookups"; 70 static final Logger ERR = Logger.getLogger(FileEntityResolver.class.getName()); 71 72 74 public FileEntityResolver() { 75 } 76 77 79 public InputSource resolveEntity(String publicID, String systemID) throws IOException , SAXException { 80 if (publicID == null) { 81 return null; 82 } 83 84 85 String id = convertPublicId (publicID); 86 87 StringBuffer sb = new StringBuffer (200); 88 sb.append (ENTITY_PREFIX); 89 sb.append (id); 90 91 FileObject fo = Repository.getDefault ().getDefaultFileSystem ().findResource (sb.toString ()); 92 if (fo != null) { 93 94 96 InputSource in = new InputSource (fo.getInputStream ()); 97 try { 98 Object myPublicID = fo.getAttribute("hint.originalPublicID"); if (myPublicID instanceof String ) { 100 in.setPublicId((String )myPublicID); 101 } 102 URL url = fo.getURL(); 103 in.setSystemId(url.toString()); } catch (IOException ex) { 105 } 107 return in; 108 } else { 109 return null; 110 } 111 } 112 113 116 public Lookup getEnvironment(DataObject obj) { 117 if (obj instanceof XMLDataObject) { 118 XMLDataObject xml = (XMLDataObject)obj; 119 120 String id = null; 121 try { 122 DocumentType domDTD = xml.getDocument ().getDoctype (); 123 if (domDTD != null) id = domDTD.getPublicId (); 124 } catch (IOException ex) { 125 Exceptions.printStackTrace(ex); 126 return null; 127 } catch (org.xml.sax.SAXException ex) { 128 Exceptions.printStackTrace(ex); 129 return null; 130 } 131 132 if (id == null) { 133 return null; 134 } 135 136 id = convertPublicId (id); 137 138 return new Lkp (id, xml); 139 } else if (obj instanceof InstanceDataObject) { 140 return getEnvForIDO((InstanceDataObject) obj); 141 } 142 return null; 143 } 144 145 private Lookup getEnvForIDO(InstanceDataObject ido) { 146 FileEntityResolver.DTDParser parser = new DTDParser(ido.getPrimaryFile()); 147 parser.parse(); 148 String id = parser.getPublicId(); 149 if (id == null) return null; 150 id = convertPublicId (id); 151 return new Lkp (id, ido); 152 } 153 154 160 private static Lookup findLookup (DataObject obj, DataObject source) { 161 if (source == null) { 162 return null; 163 } 164 165 try { 166 InstanceCookie cookie = source.getCookie (InstanceCookie.class); 167 168 if (cookie != null) { 169 Object inst = cookie.instanceCreate (); 170 if (inst instanceof Environment.Provider) { 171 return ((Environment.Provider)inst).getEnvironment (obj); 172 } 173 174 if (!(obj instanceof XMLDataObject)) return null; 175 176 if (inst instanceof XMLDataObject.Processor) { 177 XMLDataObject.Info info = new XMLDataObject.Info (); 179 info.addProcessorClass (inst.getClass ()); 180 inst = info; 181 } 182 183 if (inst instanceof XMLDataObject.Info) { 184 return createInfoLookup ((XMLDataObject)obj, ((XMLDataObject.Info)inst)); 185 } 186 187 } 188 } catch (IOException ex) { 189 Exceptions.printStackTrace(ex); 190 } catch (ClassNotFoundException ex) { 191 Exceptions.printStackTrace(ex); 192 } 193 194 return null; 195 } 196 197 198 200 private static java.lang.reflect.Method method; 201 private static Lookup createInfoLookup (XMLDataObject obj, XMLDataObject.Info info) { 202 synchronized (FileEntityResolver.class) { 204 if (method == null) { 205 try { 206 java.lang.reflect.Method m = XMLDataObject.class.getDeclaredMethod ("createInfoLookup", new Class [] { XMLDataObject.class, 208 XMLDataObject.Info.class 209 }); 210 m.setAccessible (true); 211 method = m; 212 } catch (Exception ex) { 213 Exceptions.printStackTrace(ex); 214 return null; 215 } 216 } 217 } 218 try { 219 return (Lookup)method.invoke (null, new Object [] { obj, info }); 220 } catch (Exception ex) { 221 Exceptions.printStackTrace(ex); 222 return null; 223 } 224 } 225 226 234 private static String convertPublicId (String publicID) { 235 char[] arr = publicID.toCharArray (); 236 237 238 int numberofslashes = 0; 239 int state = 0; 240 int write = 0; 241 OUT: for (int i = 0; i < arr.length; i++) { 242 char ch = arr[i]; 243 244 switch (state) { 245 case 0: 246 if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') { 248 continue; 250 } 251 state = 1; 253 case 1: 255 if (ch == '/') { 257 state = 2; 258 if (++numberofslashes == 3) { 259 break OUT; 261 } 262 arr[write++] = '/'; 263 continue; 264 } 265 break; 266 case 2: 267 if (ch == '/') { 269 continue; 271 } 272 state = 1; 273 break; 274 } 275 276 if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') { 278 arr[write++] = ch; 279 } else { 280 arr[write++] = '_'; 281 } 282 } 283 284 return new String (arr, 0, write); 285 } 286 287 288 293 private static FileObject findObject (String id, FileObject[] last) { 294 StringBuffer sb = new StringBuffer (200); 295 sb.append (LOOKUP_PREFIX); 296 sb.append (id); 297 int len = sb.length (); 298 sb.append (".instance"); 301 FileObject root = Repository.getDefault ().getDefaultFileSystem ().getRoot (); 302 303 String toSearch1 = sb.toString (); 304 int indx = searchFolder (root, toSearch1, last); 305 if (indx == -1) { 306 return null; 308 } 309 310 FileObject fo = last[0].getFileObject (toSearch1.substring (indx)); 311 312 if (fo == null) { 313 sb.setLength (len); 315 sb.append (".xml"); 317 fo = last[0].getFileObject (sb.toString ().substring (indx)); 318 } 319 320 return fo; 321 } 322 323 329 private static int searchFolder (FileObject fo, String resourceName, FileObject[] last) { 330 int pos = 0; 331 332 for (;;) { 333 int next = resourceName.indexOf('/', pos); 334 if (next == -1) { 335 last[0] = fo; 337 return pos; 338 } 339 340 if (next == pos) { 341 pos++; 342 continue; 343 } 344 345 FileObject nf = fo.getFileObject(resourceName.substring (pos, next)); 346 if (nf == null) { 347 last[0] = fo; 349 return -1; 350 } 351 352 pos = next + 1; 354 fo = nf; 355 } 356 } 357 358 private static class StopSaxException extends SAXException { 360 public StopSaxException() { super("STOP"); } } 362 363 private static final StopSaxException STOP = new StopSaxException(); 364 365 369 private static class DTDParser extends org.xml.sax.helpers.DefaultHandler 370 implements org.xml.sax.ext.LexicalHandler { 371 372 private String publicId = null; 373 private FileObject src; 374 375 public DTDParser(FileObject src) { 376 this.src = src; 377 } 378 379 public String getPublicId() { 380 return publicId; 381 } 382 383 public void parse() { 384 InputStream in = null; 385 try { 386 org.xml.sax.XMLReader reader = org.openide.xml.XMLUtil.createXMLReader(false, false); 387 reader.setContentHandler(this); 388 reader.setEntityResolver(this); 389 in = new BufferedInputStream (src.getInputStream()); 390 InputSource is = new InputSource (in); 391 try { 392 reader.setFeature("http://xml.org/sax/features/validation", false); } catch (SAXException sex) { 394 ERR.warning( 395 "XML parser does not support validation feature."); } 397 try { 398 reader.setProperty("http://xml.org/sax/properties/lexical-handler", this); } catch (SAXException sex) { 400 ERR.warning( 401 "XML parser does not support lexical-handler feature."); } 403 reader.parse(is); 404 } catch (StopSaxException ex) { 405 ERR.log(Level.FINE, null, ex); 406 } catch (Exception ex) { if ("org.openide.util.lookup.AbstractLookup$ISE".equals (ex.getClass ().getName ())) { throw (IllegalStateException )ex; 410 } 411 412 try { 413 if (src.getFileSystem() == Repository.getDefault().getDefaultFileSystem()) { 416 ERR.log(Level.WARNING, "Parsing " + src, ex); } 418 } catch (org.openide.filesystems.FileStateInvalidException fie) { 419 } 421 } finally { 422 try { 423 if (in != null) { 424 in.close(); 425 } 426 } catch (IOException exc) { 427 ERR.log(Level.WARNING, "Closing stream for " + src, exc); 428 } 429 } 430 } 431 432 public InputSource resolveEntity(String publicId, String systemID) { 433 InputSource ret = new InputSource (new java.io.StringReader ("")); ret.setSystemId("StringReader"); return ret; 436 } 437 438 public void endDTD() throws org.xml.sax.SAXException { 439 throw STOP; 440 } 441 442 public void startDTD(String name, String publicId, String systemId) throws org.xml.sax.SAXException { 443 this.publicId = publicId; 444 } 445 446 public void startEntity(String str) throws org.xml.sax.SAXException {} 447 public void endEntity(String str) throws org.xml.sax.SAXException {} 448 public void comment(char[] values, int param, int param2) throws org.xml.sax.SAXException {} 449 public void startCDATA() throws org.xml.sax.SAXException {} 450 public void endCDATA() throws org.xml.sax.SAXException {} 451 452 } 453 454 455 457 private static final class Lkp extends ProxyLookup 458 implements PropertyChangeListener , FileChangeListener { 459 460 private String id; 461 462 private DataObject xml; 463 464 465 private volatile FileObject folder; 466 467 private volatile DataObject obj; 468 469 470 public Lkp (String id, DataObject xml) { 471 super (new Lookup[0]); 472 this.id = id; 473 this.xml = xml; 474 } 475 476 478 protected void beforeLookup (Template t) { 479 if (ERR.isLoggable(Level.FINE)) { 480 ERR.fine("beforeLookup: " + t.getType() + " for " + xml); } 482 483 if (folder == null && obj == null) { 484 update (); 485 } 486 } 487 488 490 private void update () { 491 if (ERR.isLoggable(Level.FINE)) ERR.fine("update: " + id + " for " + xml); FileObject[] last = new FileObject[1]; 493 FileObject fo = findObject (id, last); 494 if (ERR.isLoggable(Level.FINE)) ERR.fine("fo: " + fo + " for " + xml); DataObject o = null; 496 497 if (fo != null) { 498 try { 499 o = DataObject.find (fo); 500 if (ERR.isLoggable(Level.FINE)) ERR.fine("object found: " + o + " for " + xml); } catch (org.openide.loaders.DataObjectNotFoundException ex) { 502 Exceptions.printStackTrace(ex); 503 } 504 } 505 506 if (o == obj) { 507 if (ERR.isLoggable(Level.FINE)) ERR.fine("same data object" + " for " + xml); Lookup l = findLookup (xml, o); 511 if (o != null && l != null) { 512 if (ERR.isLoggable(Level.FINE)) ERR.fine("updating lookups" + " for " + xml); setLookups (new Lookup[] { l }); 515 if (ERR.isLoggable(Level.FINE)) ERR.fine("updating lookups done" + " for " + xml); return; 518 } 519 } else { 520 Lookup l = findLookup(xml, o); 522 523 if (o != null && l != null) { 524 if (ERR.isLoggable(Level.FINE)) ERR.fine("change the lookup"); o.addPropertyChangeListener ( 527 org.openide.util.WeakListeners.propertyChange (this, o) 528 ); 529 setLookups (new Lookup[] { l }); 531 if (ERR.isLoggable(Level.FINE)) ERR.fine("change in lookup done" + " for " + xml); obj = o; 534 if (ERR.isLoggable(Level.FINE)) ERR.fine("data object updated to " + obj + " for " + xml); return; 536 } else { 537 obj = o; 538 if (ERR.isLoggable(Level.FINE)) ERR.fine("data object updated to " + obj + " for " + xml); } 540 } 541 542 if (ERR.isLoggable(Level.FINE)) ERR.fine("delegating to nobody for " + obj + " for " + xml); setLookups (new Lookup[0]); 545 546 if (folder != last[0]) { 549 folder = last[0]; 550 last[0].addFileChangeListener ( 551 org.openide.filesystems.FileUtil.weakFileChangeListener (this, last[0]) 552 ); 553 } 554 } 555 556 559 public void fileDeleted(FileEvent fe) { 560 update (); 561 } 562 563 569 public void fileFolderCreated(FileEvent fe) { 570 update (); 571 } 572 573 579 public void fileDataCreated(FileEvent fe) { 580 update (); 581 } 582 583 587 public void fileAttributeChanged(FileAttributeEvent fe) { 588 } 589 590 public void propertyChange(java.beans.PropertyChangeEvent ev) { 591 String name = ev.getPropertyName(); 592 593 if ( 594 DataObject.PROP_COOKIE.equals(name) || 595 DataObject.PROP_NAME.equals(name) || 596 DataObject.PROP_VALID.equals(name) || 597 DataObject.PROP_PRIMARY_FILE.equals(name) 598 ) { 599 update (); 600 } 601 } 602 603 607 public void fileRenamed(FileRenameEvent fe) { 608 update (); 609 } 610 611 614 public void fileChanged(FileEvent fe) { 615 } 616 617 } 618 } 619 | Popular Tags |