1 19 20 package org.netbeans.modules.xml.retriever.catalog.impl; 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.io.ByteArrayInputStream ; 25 import java.io.ByteArrayOutputStream ; 26 import java.io.File ; 27 import java.io.FileOutputStream ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.InputStreamReader ; 31 import java.io.OutputStream ; 32 import java.util.ArrayList ; 33 import java.util.HashMap ; 34 import java.util.List ; 35 import java.util.Set ; 36 import java.util.WeakHashMap ; 37 import java.util.logging.Logger ; 38 import javax.swing.event.DocumentEvent ; 39 import javax.swing.event.DocumentListener ; 40 import javax.swing.text.BadLocationException ; 41 import javax.swing.text.StyledDocument ; 42 import javax.xml.parsers.DocumentBuilder ; 43 import javax.xml.parsers.DocumentBuilderFactory ; 44 import javax.xml.parsers.ParserConfigurationException ; 45 import javax.xml.transform.Transformer ; 46 import javax.xml.transform.TransformerFactory ; 47 import javax.xml.transform.dom.DOMSource ; 48 import javax.xml.transform.stream.StreamResult ; 49 import org.netbeans.modules.xml.retriever.catalog.Utilities; 50 import org.netbeans.modules.xml.xam.dom.DocumentModel; 51 import org.netbeans.modules.xml.retriever.catalog.CatalogAttribute; 52 import org.netbeans.modules.xml.retriever.catalog.CatalogElement; 53 import org.netbeans.modules.xml.retriever.catalog.CatalogEntry; 54 import org.openide.cookies.EditorCookie; 55 import org.openide.cookies.SaveCookie; 56 import org.openide.filesystems.FileLock; 57 import org.openide.filesystems.FileObject; 58 import org.openide.filesystems.FileUtil; 59 import org.openide.loaders.DataObject; 60 import org.w3c.dom.Document ; 61 import org.w3c.dom.Element ; 62 import org.w3c.dom.NamedNodeMap ; 63 import org.w3c.dom.Node ; 64 import org.w3c.dom.NodeList ; 65 import org.xml.sax.EntityResolver ; 66 import org.xml.sax.InputSource ; 67 import org.xml.sax.SAXException ; 68 69 73 public class CatalogFileWrapperDOMImpl implements EntityResolver , CatalogFileWrapper, DocumentListener { 74 PropertyChangeSupport pcs = new PropertyChangeSupport (this); 75 private Document catDoc = null; 76 private Element catalog = null; 77 private boolean isItMyOwnEvent = false; 78 public static javax.swing.text.Document backendCatalogSwingDocument = null; 79 private static final Logger logger = Utilities.getLogger(); 80 81 private DocumentModel.State currentStateOfCatalog = null; 82 83 public static boolean TEST_ENVIRONMENT = false; 84 85 private FileObject backendCatalogFileObj = null; 86 87 88 boolean rawFileSaveStrategy = false; 89 90 SaveCookie saveCookie = null; 91 92 private CatalogFileWrapperDOMImpl(FileObject backendCatalogFileObj, boolean rawFileSaveStrategy) throws IOException { 93 this.rawFileSaveStrategy = rawFileSaveStrategy; 94 this.backendCatalogFileObj = backendCatalogFileObj; 95 assert(backendCatalogFileObj != null); 96 } 98 99 private synchronized void bootstrap(){ 100 try { 101 this.backendCatalogSwingDocument = getDocument(backendCatalogFileObj); 102 } catch (IOException ex) { 103 throw new IllegalStateException (ex); 104 } 105 assert(backendCatalogFileObj != null); 106 try { 107 sync(); 108 } catch (IOException ex) { 109 throw new IllegalStateException (ex); 110 } 111 if(currentStateOfCatalog == DocumentModel.State.NOT_WELL_FORMED) 112 throw new IllegalStateException ("Catalog File Not wellformed"); 113 } 114 115 private synchronized void tearDown(){ 116 this.backendCatalogSwingDocument = null; 117 catalog = null; 118 catDoc = null; 119 } 120 121 static WeakHashMap <FileObject, CatalogFileWrapper> fo2wrapMap = new WeakHashMap <FileObject, CatalogFileWrapper>(); 122 123 public static synchronized CatalogFileWrapper getInstance(FileObject backendCatalogFileObj, boolean rawFileSaveStrategy) throws IOException { 124 CatalogFileWrapper result = fo2wrapMap.get(backendCatalogFileObj); 125 if(result == null){ 126 result = new CatalogFileWrapperDOMImpl(backendCatalogFileObj, rawFileSaveStrategy); 127 if(result != null){ 128 fo2wrapMap.put(backendCatalogFileObj, result); 129 return result; 130 } 131 } 132 return result; 133 } 134 135 public static synchronized CatalogFileWrapper getInstance(FileObject backendCatalogFileObj) throws IOException { 136 return getInstance(backendCatalogFileObj, false); 137 } 138 139 public synchronized void cleanInstance(){ 140 145 } 146 147 private javax.swing.text.Document getDocument(FileObject backendCatalogFileObj) throws IOException { 148 logger.finer("ENTER FileObject "+backendCatalogFileObj.toString()); 149 DataObject dobj = DataObject.find(backendCatalogFileObj); 150 EditorCookie thisDocumentEditorCookie = (EditorCookie)dobj.getCookie(EditorCookie.class); 151 StyledDocument sd = thisDocumentEditorCookie.openDocument(); 152 logger.finer("RETURN"); 153 return sd; 154 } 155 156 private boolean shouldParse(String docContent){ 157 if((docContent != null) && (docContent.toLowerCase().indexOf("catalog") != -1)) 158 return true; 159 return false; 160 } 161 162 public List <CatalogEntry> getSystems() { 163 return getEntriesByTagName(CatalogElement.system, 164 CatalogAttribute.systemId, CatalogAttribute.uri); 165 } 166 167 public void setSystem(int index, CatalogEntry catEnt) throws IOException { 168 setEntryInCatalogFile(index, catEnt, 169 CatalogAttribute.systemId, CatalogAttribute.uri); 170 } 171 172 public void deleteSystem(int index) throws IOException { 173 deleteEntryFromCatalogFile(index, CatalogElement.system); 174 } 175 176 public void addSystem(CatalogEntry catEnt) throws IOException { 177 addEntryToCatFile(catEnt, 178 CatalogAttribute.systemId, CatalogAttribute.uri); 179 } 180 181 182 public List <CatalogEntry> getDelegateSystems() { 183 return getEntriesByTagName(CatalogElement.delegateSystem, 184 CatalogAttribute.systemIdStartString, CatalogAttribute.catalog); 185 } 186 187 public void setDelegateSystem(int index, CatalogEntry catEnt) throws IOException { 188 setEntryInCatalogFile(index, catEnt, 189 CatalogAttribute.systemIdStartString, CatalogAttribute.catalog); 190 } 191 192 public void deleteDelegateSystem(int index) throws IOException { 193 deleteEntryFromCatalogFile(index, CatalogElement.delegateSystem); 194 } 195 196 public void addDelegateSystem(CatalogEntry catEnt) throws IOException { 197 addEntryToCatFile(catEnt, 198 CatalogAttribute.systemIdStartString, CatalogAttribute.catalog); 199 } 200 201 202 public List <CatalogEntry> getRewriteSystems() { 203 return getEntriesByTagName(CatalogElement.rewriteSystem, 204 CatalogAttribute.systemIdStartString, CatalogAttribute.rewritePrefix); 205 } 206 207 public void setRewriteSystem(int index, CatalogEntry catEnt) throws IOException { 208 setEntryInCatalogFile(index, catEnt, 209 CatalogAttribute.systemIdStartString, CatalogAttribute.rewritePrefix); 210 } 211 212 public void deleteRewriteSystem(int index) throws IOException { 213 deleteEntryFromCatalogFile(index, CatalogElement.rewriteSystem); 214 } 215 216 public void addRewriteSystem(CatalogEntry catEnt) throws IOException { 217 addEntryToCatFile(catEnt, 218 CatalogAttribute.systemIdStartString, CatalogAttribute.rewritePrefix); 219 } 220 221 private void initCatFile() throws IOException { 222 logger.finer("ENTER"); 223 NodeList nl = catDoc.getElementsByTagName(CatalogElement.catalog.toString()); 224 if(nl.getLength() <= 0){ 225 catalog = catDoc.createElement(CatalogElement.catalog.toString()); 227 catalog.setAttribute(CatalogAttribute.prefer.toString(), "system"); 228 catalog.setAttribute(CatalogAttribute.xmlns.toString(),"urn:oasis:names:tc:entity:xmlns:xml:catalog"); 229 catDoc.appendChild(catalog); 230 flush(); 231 } else { 232 catalog = (Element) nl.item(0); 233 } 234 logger.finer("RETURN"); 235 } 236 237 private List <CatalogEntry> getEntriesByTagName(CatalogElement tagName, 238 CatalogAttribute mappingEntityKey, CatalogAttribute mappedEntityKey){ 239 bootstrap(); 240 Object [] obj = { 241 tagName.toString(), mappingEntityKey.toString(), 242 mappedEntityKey.toString() 243 }; 244 logger.entering("CatalogModelWrapperDOMImpl","getEntriesByTagName", obj); 245 246 NodeList nl = catalog.getElementsByTagName(tagName.toString()); 247 int len = nl.getLength(); 248 if(len < 1) 249 return null; 250 List <CatalogEntry> result = new ArrayList <CatalogEntry> (nl.getLength()); 251 for(int i=0; i<len;i++){ 252 String mappingEntity = ""; 253 String mappedEntity = ""; 254 Element elm = (Element) nl.item(i); 255 mappingEntity = elm.getAttribute(mappingEntityKey.toString()); 256 mappedEntity = elm.getAttribute(mappedEntityKey.toString()); 257 String strArry[] = {mappingEntityKey.toString(),mappedEntityKey.toString()}; 258 HashMap <String ,String > extraAttrs = getOtherAttributes(elm, strArry); 259 CatalogEntry catEnt; 260 if(extraAttrs != null) 261 catEnt = new CatalogEntryImpl(tagName, mappingEntity, mappedEntity, extraAttrs); 262 else 263 catEnt = new CatalogEntryImpl(tagName, mappingEntity, mappedEntity); 264 result.add(catEnt); 265 } 266 logger.exiting("CatalogModelWrapperDOMImpl","getEntriesByTagName", result); 267 tearDown(); 268 return result; 269 } 270 271 private void addEntryToCatFile(CatalogEntry catEnt, 272 CatalogAttribute mappingEntityKey, CatalogAttribute mappedEntityKey) throws IOException { 273 bootstrap(); 274 278 279 Element elm = catDoc.createElement(catEnt.getEntryType().toString()); 280 if(mappedEntityKey != null) 281 elm.setAttribute(mappedEntityKey.toString(), catEnt.getTarget()); 282 if(mappingEntityKey != null) 283 elm.setAttribute(mappingEntityKey.toString(), catEnt.getSource()); 284 HashMap <String , String > extraAttribMap = catEnt.getExtraAttributeMap(); 285 if(extraAttribMap != null) 286 addOtherAttributesToElement(elm, extraAttribMap); 287 288 catalog.appendChild(elm); 289 flush(); 290 logger.exiting(this.toString(), "addEntryToCatFile"); 291 tearDown(); 292 } 293 294 private void setEntryInCatalogFile(int index, CatalogEntry catEnt, 295 CatalogAttribute mappingEntityKey, CatalogAttribute mappedEntityKey) throws IOException { 296 bootstrap(); 297 298 Object obj[] = { 299 Integer.valueOf(index), catEnt.toString(), mappingEntityKey.toString(), mappedEntityKey.toString() 300 }; 301 logger.entering("CatalogModelWrapperDOMImpl", "setEntryInCatalogFile", obj); 302 303 Element elm = catDoc.createElement(catEnt.getEntryType().toString()); 304 elm.setAttribute(mappedEntityKey.toString(), catEnt.getTarget()); 305 elm.setAttribute(mappingEntityKey.toString(), catEnt.getSource()); 306 HashMap <String , String > extraAttribMap = catEnt.getExtraAttributeMap(); 307 if(extraAttribMap != null) 308 addOtherAttributesToElement(elm, extraAttribMap); 309 310 NodeList nl = catalog.getElementsByTagName(catEnt.getEntryType().toString()); 311 int len = nl.getLength(); 312 if((index >= len) || (index < 0)) 313 throw new IndexOutOfBoundsException ("Error: Catalog entry does not exists"); 314 315 Node oldNode = nl.item(index); 316 317 catalog.replaceChild(elm, oldNode); 318 319 flush(); 320 logger.exiting(this.toString(), "setEntryInCatalogFile"); 321 tearDown(); 322 } 323 324 private void deleteEntryFromCatalogFile(int index, CatalogElement tagName) throws IOException { 325 logger.entering(this.toString(),"deleteEntryFromCatalogFile"); 326 bootstrap(); 327 NodeList nl = catalog.getElementsByTagName(tagName.toString()); 328 int len = nl.getLength(); 329 if((index >= len) || (index < 0)) 330 throw new IndexOutOfBoundsException ("Error: Catalog entry does not exists"); 331 332 Node oldNode = nl.item(index); 333 334 catalog.removeChild(oldNode); 335 336 flush(); 337 logger.exiting(this.toString(), "deleteEntryFromCatalogFile"); 338 tearDown(); 339 } 340 341 private void addOtherAttributesToElement(Element elm, HashMap <String ,String > extraAttribMap) { 342 if(extraAttribMap == null) 343 return; 344 Set <String > keys = extraAttribMap.keySet(); 345 if(keys == null) 346 return; 347 for(String key: keys){ 348 String value = (String ) extraAttribMap.get(key); 349 if(value != null){ 350 elm.setAttribute(key, value); 351 } 352 } 353 } 354 355 private HashMap <String ,String > getOtherAttributes(Element elm, String [] strArry) { 356 HashMap <String , String > result = new HashMap <String ,String >(); 357 NamedNodeMap attrs = elm.getAttributes(); 358 for(int i = 0; i<attrs.getLength();i++){ 359 String key = attrs.item(i).getNodeName(); 360 boolean isMainAttrib = false; 361 for(String str: strArry){ 362 if(str.equals(key)){ 363 isMainAttrib = true; 364 break; 365 } 366 } 367 if(!isMainAttrib){ 368 String value = attrs.item(i).getNodeValue(); 369 if((key != null) && (value != null)) 370 result.put(key,value); 371 } 372 } 373 if(result.isEmpty()) 374 return null; 375 return result; 376 } 377 378 public synchronized void sync() throws IOException { 379 logger.finer("ENTER"); 380 DocumentBuilderFactory dBuilderFact = DocumentBuilderFactory.newInstance(); 381 DocumentBuilder dBuilder = null; 383 try { 384 dBuilder = dBuilderFact.newDocumentBuilder(); 385 } catch (ParserConfigurationException ex) { 386 assignStateAndFirePropChangeEvent(DocumentModel.State.NOT_WELL_FORMED); 387 throw new IOException (ex.getMessage()); 388 } 389 String docContent = null; 390 try { 391 392 docContent = backendCatalogSwingDocument.getText(0, backendCatalogSwingDocument.getLength()); 393 } catch (BadLocationException ex) { 394 assignStateAndFirePropChangeEvent(DocumentModel.State.NOT_WELL_FORMED); 395 throw new IOException (ex.getMessage()); 396 } 397 logger.finer("Trying to sync this data to model:"+docContent); 398 if(shouldParse(docContent)){ 399 InputStream catIS = new ByteArrayInputStream (docContent.getBytes()); 400 try { 401 catDoc = dBuilder.parse(catIS); 403 logger.finer("Just synced this data :"+docContent); 404 } catch (SAXException ex) { 405 assignStateAndFirePropChangeEvent(DocumentModel.State.NOT_WELL_FORMED); 406 throw new IOException (ex.getMessage()); 407 } 408 } else{ 409 catDoc = dBuilder.newDocument(); 410 } 411 if(catDoc == null){ 412 assignStateAndFirePropChangeEvent(DocumentModel.State.NOT_WELL_FORMED); 413 throw new IllegalStateException ("Catalog File Not wellformed"); 414 } 415 assignStateAndFirePropChangeEvent(DocumentModel.State.VALID); 416 initCatFile(); 417 logger.finer("RETURN"); 418 419 } 420 421 private void assignStateAndFirePropChangeEvent(DocumentModel.State currentStateOfCatalog){ 422 DocumentModel.State prevState = this.currentStateOfCatalog; 423 this.currentStateOfCatalog = currentStateOfCatalog; 424 pcs.firePropertyChange("CatalogWraperObject",prevState, currentStateOfCatalog); 425 } 426 427 public boolean isValidState(){ 428 if(currentStateOfCatalog == DocumentModel.State.VALID) 429 return true; 430 return false; 431 } 432 433 public synchronized void flush() throws IOException { 434 logger.finer("ENTER"); 435 isItMyOwnEvent = true; 436 try { 437 TransformerFactory trFactory = TransformerFactory.newInstance(); 438 Transformer transformer = trFactory.newTransformer(); 439 DOMSource domSource = new DOMSource (catDoc); 440 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 441 StreamResult streamResult = new StreamResult (baos); 442 transformer.setOutputProperty("indent","yes"); 443 transformer.transform(domSource, streamResult); 444 String fileContent = new String (baos.toByteArray()); 445 String prevContent = backendCatalogSwingDocument.getText(0, backendCatalogSwingDocument.getLength()); 446 if(fileContent.equals(prevContent)){ 447 isItMyOwnEvent = false; 448 return; 449 } 450 backendCatalogSwingDocument.remove(0, backendCatalogSwingDocument.getLength()); 451 backendCatalogSwingDocument.insertString(0, fileContent, null); 452 logger.finer("Just Flushed this data :"+backendCatalogSwingDocument.getText(0,backendCatalogSwingDocument.getLength())); 453 save(fileContent, prevContent); 454 } catch(Exception ex){ 455 throw new IOException (ex.getMessage()); 456 } finally{ 457 isItMyOwnEvent = false; 458 } 459 logger.finer("RETURN"); 460 } 461 462 public void insertUpdate(DocumentEvent e) { 463 logger.entering("CatalogModelWrapperDOMImpl","insertUpdate",Boolean.valueOf(isItMyOwnEvent)); 465 if(!isItMyOwnEvent){ 466 try { 467 sync(); 468 } catch (IOException ex) { 469 } 472 return; 473 } 474 } 475 476 void showStackTrace(){ 477 try{ 478 throw new Exception (); 479 }catch (Exception e){ 480 e.printStackTrace(); 481 } 482 } 483 484 public void removeUpdate(DocumentEvent e) { 485 showStackTrace(); 486 logger.entering("CatalogModelWrapperDOMImpl","removeUpdate",Boolean.valueOf(isItMyOwnEvent)); 487 insertUpdate(e); 488 } 489 490 public void changedUpdate(DocumentEvent e) { 491 logger.entering("CatalogModelWrapperDOMImpl","changedUpdate",Boolean.valueOf(isItMyOwnEvent)); 492 } 494 495 public void addPropertyChangeListener(PropertyChangeListener l) { 496 pcs.addPropertyChangeListener(l); 497 } 498 499 public void removePropertyChangeListener(PropertyChangeListener l) { 500 pcs.removePropertyChangeListener(l); 501 } 502 503 504 public InputStream getCatalogAsStream() throws IOException { 505 try { 506 String docContent = backendCatalogSwingDocument.getText(0, backendCatalogSwingDocument.getLength()); 507 InputStream bis = new ByteArrayInputStream (docContent.getBytes()); 508 logger.finer("In getCatalogAsStream gona return:"+docContent); 509 return bis; 510 } catch (BadLocationException ex) { 511 throw new IOException (ex.getMessage()); 512 } 513 } 514 515 public InputSource resolveEntity(String publicId, String systemId) throws SAXException , IOException { 516 logger.finest("ENTRY PublicID:"+publicId+" SystemID:"+systemId); 517 InputSource isrc = new InputSource (); 518 InputStreamReader isr = new InputStreamReader (org.apache.xml.resolver.apps.resolver.class.getResourceAsStream("/org/apache/xml/resolver/etc/catalog.dtd")); 519 isrc.setCharacterStream(isr); 520 if((systemId != null) && systemId.equals("urn:oasis:names:tc:entity:xmlns:xml:catalog")){ 521 logger.finest("RETURN the DTD"); 522 return isrc; 523 } 524 if((publicId != null) && publicId.equals("urn:oasis:names:tc:entity:xmlns:xml:catalog")){ 525 logger.finest("RETURN the DTD"); 526 return isrc; 527 } 528 logger.finest("RETURN null"); 530 return null; 531 } 532 533 private void save(String fileContent, String previousFileContent) { 534 if(TEST_ENVIRONMENT) 539 saveByRawStreamByFile(fileContent, previousFileContent); 540 else 541 saveBySaveCookie(); 542 } 544 545 boolean saveBySaveCookie(){ 546 try { 547 DataObject dobj = DataObject.find(backendCatalogFileObj); 548 SaveCookie saveCookie = (SaveCookie) dobj.getCookie(SaveCookie.class); 549 assert(saveCookie != null); 550 saveCookie.save(); 551 } catch (IOException ex) { 552 return false; 553 } 554 return true; 555 } 556 557 boolean saveByRawStreamByFO(String fileContent, String previousFileContent){ 558 OutputStream os =null; 559 FileLock lock = null; 560 boolean noException = true; 561 try { 562 lock = backendCatalogFileObj.lock(); 563 os = backendCatalogFileObj.getOutputStream(lock); 564 os.write(fileContent.getBytes()); 565 os.flush(); 566 os.close(); 567 lock.releaseLock(); 568 os = null; 569 } catch (IOException ex) { 570 ex.printStackTrace(); 571 noException = false; 572 } finally { 573 if(lock != null) 574 lock.releaseLock(); 575 if(os != null){ 576 try { 577 os.close(); 578 } catch (IOException ex) { 579 } 580 } 581 return noException; 582 } 583 } 584 585 586 587 boolean saveByRawStreamByFile(String fileContent, String previousFileContent){ 588 OutputStream os =null; 589 try { 590 File catFile = FileUtil.toFile(backendCatalogFileObj); 591 os = new FileOutputStream (catFile); 592 os.write(fileContent.getBytes()); 593 os.flush(); 594 os.close(); 595 os = null; 596 } catch (IOException ex) { 597 ex.printStackTrace(); 598 } finally { 599 if(os != null){ 600 try { 601 os.close(); 602 return false; 603 } catch (IOException ex) { 604 } 605 } 606 } 607 return true; 608 } 609 610 611 612 void saveByDocumentEditorCookie(){ 613 try { 614 DataObject dobj = DataObject.find(backendCatalogFileObj); 615 EditorCookie thisDocumentEditorCookie = (EditorCookie)dobj.getCookie(EditorCookie.class); 616 thisDocumentEditorCookie.saveDocument(); 617 } catch (IOException ex) { 618 } 619 } 620 621 private boolean unsuccessfulSave(String fileContent, String previousFileContent) { 622 try { 623 if(backendCatalogSwingDocument.getText(0, backendCatalogSwingDocument.getLength()).length() != fileContent.length()){ 624 return true; 625 } 626 } catch (BadLocationException ex) { 627 } 628 return false; 629 } 630 631 public void close() { 632 } 635 636 public DocumentModel.State getCatalogState() { 637 bootstrap(); 638 tearDown(); 639 return currentStateOfCatalog; 640 } 641 642 protected void finalize() throws Throwable { 643 try { 644 DataObject dobj = DataObject.find(backendCatalogFileObj); 645 EditorCookie thisDocumentEditorCookie = (EditorCookie)dobj.getCookie(EditorCookie.class); 646 backendCatalogSwingDocument.removeDocumentListener(this); 647 thisDocumentEditorCookie.close(); 648 } finally { 649 super.finalize(); 650 } 651 } 652 653 public void addNextCatalog(CatalogEntry catEnt) throws IOException { 654 addEntryToCatFile(catEnt, CatalogAttribute.catalog, null); 655 } 656 657 public void deleteNextCatalog(int index) throws IOException { 658 deleteEntryFromCatalogFile(index, CatalogElement.nextCatalog); 659 } 660 661 public List <CatalogEntry> getNextCatalogs() { 662 return getEntriesByTagName(CatalogElement.nextCatalog, 663 CatalogAttribute.catalog, CatalogAttribute.catalog); 664 } 665 666 } 667 | Popular Tags |