1 19 20 package org.openide.loaders; 21 22 23 import java.io.*; 24 import java.lang.ref.*; 25 import java.lang.reflect.*; 26 import java.net.URL ; 27 import java.util.*; 28 import java.util.logging.*; 29 import javax.swing.Action ; 30 import javax.xml.parsers.DocumentBuilder ; 31 import org.openide.actions.OpenAction; 32 import org.openide.cookies.*; 33 import org.openide.filesystems.*; 34 import org.openide.nodes.*; 35 import org.openide.text.DataEditorSupport; 36 import org.openide.util.*; 37 import org.openide.util.actions.SystemAction; 38 import org.openide.util.lookup.AbstractLookup; 39 import org.openide.windows.CloneableOpenSupport; 40 import org.openide.xml.*; 41 import org.w3c.dom.Document ; 42 import org.w3c.dom.DocumentType ; 43 import org.xml.sax.*; 44 import org.xml.sax.ext.LexicalHandler ; 45 import org.xml.sax.helpers.DefaultHandler ; 46 47 63 public class XMLDataObject extends MultiDataObject { 64 65 static final long serialVersionUID = 8757854986453256578L; 66 67 70 @Deprecated 71 public static final String XMLINFO_DTD_PUBLIC_ID_FORTE = "-//Forte for Java//DTD xmlinfo//EN"; 74 @Deprecated 75 public static final String XMLINFO_DTD_PUBLIC_ID = "-//NetBeans IDE//DTD xmlinfo//EN"; 77 78 public static final String MIME = "text/xml"; 81 82 public static final int STATUS_NOT = 0; 83 84 public static final int STATUS_OK = 1; 85 86 public static final int STATUS_WARNING = 2; 87 88 public static final int STATUS_ERROR = 3; 89 90 91 public static final String PROP_DOCUMENT = "document"; 93 96 @Deprecated 97 public static final String PROP_INFO = "info"; 99 100 private static ErrorPrinter errorHandler = new ErrorPrinter(); 101 102 105 private static XMLEntityResolverChain chainingEntityResolver; 106 107 108 private static HashMap<String , Info> infos = new HashMap<String , Info>(); 109 private static Object emgrLock = new Object (); 111 112 113 114 115 116 120 121 122 private DelDoc doc; 123 124 125 126 private int status; 129 132 @Deprecated 133 private EditorCookie editor = null; 134 135 139 private InfoParser infoParser; 140 141 142 private static final Logger ERR = Logger.getLogger(XMLDataObject.class.getName()); 143 144 145 154 public XMLDataObject (FileObject fo, MultiFileLoader loader) 155 throws DataObjectExistsException { 156 super (fo, loader); 157 158 fo.addFileChangeListener (FileUtil.weakFileChangeListener (getIP (), fo)); 159 160 status = STATUS_NOT; 161 162 169 CookieSet.Factory factory = new CookieSet.Factory() { 170 public <T extends Node.Cookie> T createCookie(Class <T> klass) { 171 if (klass.isAssignableFrom(EditorCookie.class) 172 || klass.isAssignableFrom(OpenCookie.class) 173 || klass.isAssignableFrom(CloseCookie.class) 174 || klass.isAssignableFrom(PrintCookie.class) ) { 175 176 if (editor == null) editor = createEditorCookie(); if (editor == null) return null; 179 return klass.isAssignableFrom(editor.getClass()) ? (T)editor : null; 180 } else { 181 return null; 182 } 183 } 184 }; 185 186 CookieSet cookies = getCookieSet(); 187 cookies.add(EditorCookie.class, factory); 190 cookies.add(OpenCookie.class, factory); 191 cookies.add(CloseCookie.class, factory); 192 cookies.add(PrintCookie.class, factory); 193 194 } 197 198 201 private final InfoParser getIP () { 202 synchronized (emgrLock) { 203 if (infoParser == null) { 204 infoParser = new InfoParser (); 205 } 206 } 207 return infoParser; 208 } 209 210 211 212 219 protected Node createNodeDelegate () { XMLNode xn = new XMLNode (this); 221 xn.setShortDescription (NbBundle.getMessage ( 223 XMLDataObject.class, "HINT_XMLDataObject")); return xn; 225 } 226 227 231 @Deprecated 232 protected void updateIconBase (String res) { 233 } 235 236 240 protected void handleDelete() throws IOException { 241 242 getIP ().waitFinished(); super.handleDelete(); 244 } 245 246 public HelpCtx getHelpCtx () { 247 try { 250 if (getPrimaryFile ().getFileSystem ().isDefault ()) { 251 if (getCookie (InstanceCookie.class)!=null) { 252 return HelpCtx.DEFAULT_HELP; 253 } 254 } 255 } catch (FileStateInvalidException fsie) { 256 } 258 return new HelpCtx (XMLDataObject.class); 259 } 260 261 270 public <T extends Node.Cookie> T getCookie(Class <T> cls) { 271 getIP ().waitFinished(); 272 273 Object cake = getIP().lookupCookie(cls); 274 275 if (ERR.isLoggable(Level.FINE)) { 276 ERR.fine("Query for " + cls + " for " + this); ERR.fine("Gives a cake " + cake + " for " + this); } 279 280 if (cake instanceof InstanceCookie) { 281 cake = ofCookie ((InstanceCookie)cake, cls); 282 } 283 284 if (ERR.isLoggable(Level.FINE)) { 285 ERR.fine("After ofCookie: " + cake + " for " + this); } 287 288 if (cake == null) { 289 cake = super.getCookie (cls); 290 } 291 292 if (ERR.isLoggable(Level.FINE)) { 293 ERR.fine("getCookie returns " + cake + " for " + this); } 295 296 return cls.cast(cake); 297 } 298 299 307 private InstanceCookie ofCookie (InstanceCookie ic, Class cls) { 308 if (ic instanceof InstanceCookie.Of) { 309 return ic; 310 } else if (! cls.isAssignableFrom (ICDel.class)) { 311 return ic; 316 } else { 317 ICDel d = new ICDel (this, ic); 318 return d; 319 } 320 } 321 322 private void notifyEx(Exception e) { 323 Exceptions.attachLocalizedMessage(e, 324 "Cannot resolve following class in xmlinfo."); Exceptions.printStackTrace(e); 326 } 327 328 333 @Deprecated 334 protected EditorCookie createEditorCookie () { 335 return new XMLEditorSupport (this); 336 } 337 338 private final void addSaveCookie (SaveCookie save) { 340 getCookieSet ().add (save); 341 } 342 private final void removeSaveCookie (SaveCookie save) { 343 getCookieSet ().remove (save); 344 } 345 346 354 private static class XMLEditorSupport extends DataEditorSupport implements OpenCookie, EditorCookie.Observable, PrintCookie, CloseCookie { 355 public XMLEditorSupport (XMLDataObject obj) { 356 super (obj, new XMLEditorEnv (obj)); 357 setMIMEType ("text/xml"); } 359 class Save implements SaveCookie { 360 public void save () throws IOException { 361 saveDocument (); 362 getDataObject ().setModified (false); 363 } 364 } 365 protected boolean notifyModified () { 366 if (! super.notifyModified ()) { 367 return false; 368 } 369 if (getDataObject ().getCookie (SaveCookie.class) == null) { 370 ((XMLDataObject) getDataObject ()).addSaveCookie (new Save ()); 371 getDataObject ().setModified (true); 372 } 373 return true; 374 } 375 protected void notifyUnmodified () { 376 super.notifyUnmodified (); 377 SaveCookie save = (SaveCookie) getDataObject ().getCookie (SaveCookie.class); 378 if (save != null) { 379 ((XMLDataObject) getDataObject ()).removeSaveCookie (save); 380 getDataObject ().setModified (false); 381 } 382 } 383 384 private static class XMLEditorEnv extends DataEditorSupport.Env { 387 private static final long serialVersionUID = 6593415381104273008L; 388 389 public XMLEditorEnv (DataObject obj) { 390 super (obj); 391 } 392 protected FileObject getFile () { 393 return getDataObject ().getPrimaryFile (); 394 } 395 protected FileLock takeLock () throws IOException { 396 return ((XMLDataObject) getDataObject ()).getPrimaryEntry ().takeLock (); 397 } 398 public CloneableOpenSupport findCloneableOpenSupport () { 399 return (CloneableOpenSupport) getDataObject ().getCookie (EditorCookie.class); 402 } 403 } 404 } 405 406 413 public final Document getDocument () throws IOException, SAXException { 414 if (ERR.isLoggable(Level.FINE)) ERR.fine("getDocument" + " for " + this); 415 synchronized (this) { 416 DelDoc d = doc; 417 if (d == null) { 418 d = new DelDoc (); 419 doc = d; 420 } 421 return d.getProxyDocument(); 422 } 423 } 424 425 427 final void clearDocument () { 428 if (ERR.isLoggable(Level.FINE)) ERR.fine("clearDocument" + " for " + this); 429 doc = null; 431 firePropertyChange (PROP_DOCUMENT, null, null); 432 } 433 434 437 public final int getStatus () { 438 return status; 439 } 440 441 444 @Deprecated 445 public final Info getInfo () { 446 return null; 447 } 448 449 451 @Deprecated 452 public final synchronized void setInfo (Info ii) throws IOException { 453 } 454 455 461 final Document parsePrimaryFile () throws IOException, SAXException { 462 if (ERR.isLoggable(Level.FINE)) ERR.fine("parsePrimaryFile" + " for " + this); 463 String loc = getPrimaryFile().getURL().toExternalForm(); 464 try { 465 return XMLUtil.parse(new InputSource(loc), false, true, errorHandler, getSystemResolver()); 466 } catch (IOException e) { 467 InputStream is = getPrimaryFile().getInputStream(); 471 try { 472 return XMLUtil.parse(new InputSource(is), false, true, errorHandler, getSystemResolver()); 473 } finally { 474 is.close(); 475 } 476 } 477 } 478 479 480 482 490 @Deprecated 491 public static Document parse (URL url) throws IOException, SAXException { 492 return parse (url, errorHandler, false); 493 } 494 495 504 @Deprecated 505 public static Document parse (URL url, boolean validate) throws IOException, SAXException { 506 return parse (url, errorHandler, validate); 507 } 508 509 518 @Deprecated 519 public static Document parse (URL url, ErrorHandler eh) throws IOException, SAXException { 520 return parse (url, eh, false); 521 } 522 523 537 @Deprecated 538 public static Document parse (URL url, ErrorHandler eh, boolean validate) throws IOException, SAXException { 539 540 DocumentBuilder builder = XMLDataObjectImpl.makeBuilder(validate); 541 builder.setErrorHandler(eh); 542 builder.setEntityResolver(getChainingEntityResolver()); 543 544 return builder.parse (new InputSource(url.toExternalForm())); 545 546 } 547 548 558 @Deprecated 559 public static Parser createParser () { 560 return createParser (false); 561 } 562 563 564 574 @Deprecated 575 public static Parser createParser (boolean validate) { 576 577 Parser parser = XMLDataObjectImpl.makeParser(validate); 578 parser.setEntityResolver(getChainingEntityResolver()); 579 return parser; 580 581 } 582 583 584 599 @Deprecated 600 public static Document createDocument() { 601 602 deprecated(); 603 604 try { 605 return XMLDataObjectImpl.makeBuilder(false).newDocument(); 606 } catch (IOException ex) { 607 return null; 608 } catch (SAXException ex) { 609 return null; 610 } 611 } 612 613 624 @Deprecated 625 public static void write (Document doc, Writer writer) throws IOException { 626 627 deprecated(); 628 629 631 633 final String FAILURE = "org.openide.xml.XMLUtilImpl.write() invocation failed."; 635 try { 636 Class clzz = Class.forName("org.openide.xml.XMLUtilImpl"); 638 Method impl = clzz.getDeclaredMethod("write", new Class [] { Document .class, Object .class, String .class 640 }); 641 impl.setAccessible(true); 642 impl.invoke(null, new Object [] {doc, writer, null}); 643 644 } catch (IllegalAccessException ex) { 645 throw new IOException(FAILURE); 646 } catch (IllegalArgumentException ex) { 647 throw new IOException(FAILURE); 648 } catch (NoSuchMethodException ex) { 649 throw new IOException(FAILURE); 650 } catch (ClassNotFoundException ex) { 651 throw new IOException(FAILURE); 652 } catch (InvocationTargetException ex) { 653 Throwable t = ex.getTargetException(); 654 if (t instanceof IOException) { 655 throw (IOException) t; 656 } else if (t instanceof RuntimeException ) { 657 throw (RuntimeException ) t; 658 } else if (t instanceof Error ) { 659 throw (Error ) t; 660 } 661 throw new IOException(FAILURE); 662 } 663 } 664 665 676 @Deprecated 677 public static void write(Document doc, OutputStream out, String enc) throws IOException { 678 XMLUtil.write(doc, out, enc); 679 } 680 681 682 687 @Deprecated 688 public static InputSource createInputSource(URL url) throws IOException { 689 return new InputSource(url.toExternalForm()); 690 } 691 692 709 @Deprecated 710 public static void registerCatalogEntry (String publicId, String uri) { 711 712 if (publicId == null) 713 throw new IllegalArgumentException ("null public ID is not allowed."); 715 XMLDataObjectImpl.registerCatalogEntry(publicId, uri); 716 717 } 718 719 742 @Deprecated 743 public static void registerCatalogEntry (String publicId, String resourceName, ClassLoader loader) { 744 if (publicId == null) 745 throw new IllegalArgumentException ("null public ID is not allowed."); 747 XMLDataObjectImpl.registerCatalogEntry(publicId, "nbres:/" + resourceName); } 749 750 765 @Deprecated 766 public static final boolean addEntityResolver(EntityResolver resolver) { 767 return getChainingEntityResolver().addEntityResolver(resolver); 769 } 770 771 781 @Deprecated 782 public static final EntityResolver removeEntityResolver(EntityResolver resolver) { 783 return getChainingEntityResolver().removeEntityResolver(resolver); 784 } 785 786 787 788 private static synchronized XMLEntityResolverChain getChainingEntityResolver() { 789 790 if (chainingEntityResolver == null) { 791 chainingEntityResolver = new XMLEntityResolverChain(); 792 chainingEntityResolver.addEntityResolver(getSystemResolver()); 793 } 794 795 return chainingEntityResolver; 796 797 } 798 799 800 private static EntityResolver getSystemResolver() { 801 return EntityCatalog.getDefault(); 802 } 803 804 814 @Deprecated 815 public static void registerInfo (String publicId, Info info) { synchronized (infos) { 817 if (info == null) { 818 infos.remove(publicId); 819 } else { 820 infos.put(publicId, info); 821 } 822 } 823 } 824 825 833 @Deprecated 834 public static Info getRegisteredInfo(String publicId) { synchronized (infos) { 836 Info ret = (Info) infos.get(publicId); 837 return ret == null ? null : (Info)ret.clone (); 838 } 839 } 840 841 844 private static void deprecated() { 845 StringWriter wr = new StringWriter(); 846 PrintWriter pr = new PrintWriter(wr); 847 new Exception ("").printStackTrace(pr); pr.flush(); 849 String stack = wr.toString().trim(); 850 851 int start = stack.indexOf("\n"); int end = stack.indexOf("\n", start + 1); while (stack.indexOf("XMLDataObject", start + 1 )>0) { start = end; 855 end = stack.indexOf("\n", start + 1); } 857 858 String line = stack.substring(start + 1, end).trim(); 859 860 System.out.println("Warning: deprecated method called " + line); } 862 863 866 static class ErrorPrinter implements ErrorHandler { 867 868 private void message(final String level, final SAXParseException e) { 869 870 if (!LOG.isLoggable(Level.FINE)) { 871 return; 872 } 873 874 final String msg = NbBundle.getMessage( 875 XMLDataObject.class, 876 "PROP_XmlMessage", new Object [] { 878 level, 879 e.getMessage(), 880 e.getSystemId() == null ? "" : e.getSystemId(), "" + e.getLineNumber(), "" + e.getColumnNumber() } 884 ); 885 886 LOG.fine(msg); 887 } 888 889 public void error(SAXParseException e) { 890 message (NbBundle.getMessage(XMLDataObject.class, "PROP_XmlError"), e); } 892 893 public void warning(SAXParseException e) { 894 message (NbBundle.getMessage(XMLDataObject.class, "PROP_XmlWarning"), e); } 896 897 public void fatalError(SAXParseException e) { 898 message (NbBundle.getMessage(XMLDataObject.class, "PROP_XmlFatalError"), e); } 900 } 902 903 905 private static class StopSaxException extends SAXException { 907 public StopSaxException() { super("STOP"); } } 909 910 912 private static final StopSaxException STOP = new StopSaxException(); 913 914 915 private static XMLReader sharedParserImpl = null; 916 917 static { 918 try { 919 sharedParserImpl = XMLUtil.createXMLReader(); 920 sharedParserImpl.setEntityResolver(new EmptyEntityResolver()); 921 } catch (SAXException ex) { 922 Exceptions.attachLocalizedMessage(ex, 923 "System does not contain JAXP 1.1 compliant parser!"); Logger.getLogger(XMLDataObject.class.getName()).log(Level.WARNING, null, ex); 925 } 926 927 928 try { 931 final Properties props = System.getProperties(); 932 final String SAX2_KEY = "org.xml.sax.driver"; if (props.getProperty(SAX2_KEY) == null) { 934 props.put(SAX2_KEY, sharedParserImpl.getClass().getName()); 935 } 936 } catch (RuntimeException ex) { 937 } 939 } 940 941 942 private static final String NULL = ""; 944 947 private static class NullHandler extends DefaultHandler implements LexicalHandler { 948 949 static final NullHandler INSTANCE = new NullHandler(); 950 951 NullHandler() {} 952 953 955 public void startDTD(String root, String pID, String sID) throws SAXException { 956 } 957 958 public void endDTD() throws SAXException { 959 } 960 961 public void startEntity(String name) throws SAXException { 962 } 963 964 public void endEntity(String name) throws SAXException { 965 } 966 967 public void startCDATA() throws SAXException { 968 } 969 970 public void endCDATA() throws SAXException { 971 } 972 973 public void comment(char[] ch, int start, int length) throws SAXException { 974 } 975 } 976 977 984 private final class InfoParser extends DefaultHandler 985 implements FileChangeListener, LexicalHandler , LookupListener { 986 987 988 private String parsedId; 989 990 992 private Lookup lookup; 993 994 995 private Lookup.Result result; 996 997 private ThreadLocal <Class <?>> QUERY = new ThreadLocal <Class <?>> (); 998 999 InfoParser() {} 1000 1001 1003 1005 public String getPublicId () { 1006 String id = waitFinished (); 1007 return id == NULL ? null : id; 1008 } 1009 1010 1016 public Object lookupCookie(final Class <?> clazz) { 1017 if (QUERY.get () == clazz) { 1018 if (ERR.isLoggable(Level.FINE)) ERR.fine("Cyclic deps on queried class: " + clazz + " for " + XMLDataObject.this); return new InstanceCookie () { 1022 public Class <?> instanceClass () { 1023 return clazz; 1024 } 1025 1026 public Object instanceCreate () throws IOException { 1027 throw new IOException ("Cyclic reference, sorry: " + clazz); 1028 } 1029 1030 public String instanceName () { 1031 return clazz.getName (); 1032 } 1033 }; 1034 } 1035 1036 Class <?> previous = QUERY.get (); 1037 try { 1038 QUERY.set (clazz); 1039 if (ERR.isLoggable(Level.FINE)) ERR.fine("Will do query for class: " + clazz + " for " + XMLDataObject.this); 1041 Lookup l; 1042 for (;;) { 1043 String id = waitFinished(); 1044 synchronized (this) { 1045 if (lookup != null) { 1046 l = lookup; 1047 } else { 1048 l = null; 1049 } 1050 } 1051 if (ERR.isLoggable(Level.FINE)) ERR.fine("Lookup is " + l + " for id: " + id); 1053 if (l == null) { 1054 l = updateLookup(null, id); 1055 if (ERR.isLoggable(Level.FINE)) ERR.fine("Updating lookup: " + l); } 1057 1058 if (ERR.isLoggable(Level.FINE)) ERR.fine("Wait lookup is over: " + l + XMLDataObject.this); if (l != null) { 1060 break; 1061 } 1062 if (parsedId == null) { 1063 l = Lookup.EMPTY; 1064 break; 1065 } 1066 } 1067 1068 Lookup.Result r = result; 1069 if (r != null) { 1070 if (ERR.isLoggable(Level.FINE)) ERR.fine("Querying the result: " + r); r.allItems (); 1073 } else { 1074 if (ERR.isLoggable(Level.FINE)) ERR.fine("No result for lookup: " + lookup); } 1076 Object ret = l.lookup (clazz); 1077 if (ERR.isLoggable(Level.FINE)) ERR.fine("Returning value: " + ret + " for " + XMLDataObject.this); return ret; 1079 } finally { 1080 QUERY.set (previous); 1081 } 1082 } 1083 1084 1089 public String waitFinished () { 1090 return waitFinished (null); 1091 } 1092 1093 1097 private String waitFinished (String ignorePreviousId) { 1098 if (sharedParserImpl == null) { 1099 ERR.fine("No sharedParserImpl, exiting"); return NULL; 1101 } 1102 1103 XMLReader parser = sharedParserImpl; 1104 FileObject myFileObject = getPrimaryFile(); 1105 String newID = null; 1106 1107 if (ERR.isLoggable(Level.FINE)) ERR.fine("Going to read parsedId for " + XMLDataObject.this); 1108 1109 String previousID; 1110 synchronized (this) { 1111 previousID = parsedId; 1112 } 1113 1114 if (previousID != null) { 1115 if (ERR.isLoggable(Level.FINE)) { 1116 ERR.fine("Has already been parsed: " + parsedId + " for " + XMLDataObject.this); } 1118 return previousID; 1120 } 1121 1122 URL url = null; 1123 InputStream in = null; 1124 try { 1125 url = myFileObject.getURL(); 1126 } catch (IOException ex) { 1127 warning(ex, "I/O exception while retrieving xml FileObject URL."); return NULL; } 1130 1131 synchronized (this) { 1132 try { 1133 if (!myFileObject.isValid()) { 1134 if (ERR.isLoggable(Level.FINE)) { 1135 ERR.fine("Invalid file object: " + myFileObject); } 1137 return NULL; 1138 } 1139 1140 parsedId = NULL; 1141 if (ERR.isLoggable(Level.FINE)) ERR.fine("parsedId set to NULL for " + XMLDataObject.this); try { 1143 in = myFileObject.getInputStream(); 1144 } catch (IOException ex) { 1145 warning(ex, "I/O exception while openning xml."); return NULL; } 1148 try { 1149 1150 synchronized (sharedParserImpl) { 1155 1156 configureParser(parser, false, this); 1157 parser.setContentHandler(this); 1158 parser.setErrorHandler(this); 1159 1160 InputSource input = new InputSource(url.toExternalForm()); 1161 input.setByteStream(in); 1162 parser.parse (input); 1163 } 1164 if (ERR.isLoggable(Level.FINE)) { 1165 ERR.fine("Parse finished for " + XMLDataObject.this); } 1167 } catch (StopSaxException stopped) { 1168 newID = parsedId; 1169 ERR.fine("Parsing successfully stopped: " + parsedId + " for " + XMLDataObject.this); } catch (SAXException checkStop) { 1171 if (STOP.getMessage ().equals (checkStop.getMessage ())) { 1173 newID = parsedId; 1174 ERR.fine("Parsing stopped with STOP message: " + parsedId + " for " + XMLDataObject.this); } else { 1176 String msg = "Thread:" + Thread.currentThread().getName(); ERR.warning("DocListener should not throw SAXException but STOP one.\n" + msg); ERR.log(Level.WARNING, null, checkStop); 1179 Exception ex = checkStop.getException(); 1180 if (ex != null) { 1181 ERR.log(Level.WARNING, null, ex); 1182 } 1183 } 1184 } catch (FileNotFoundException ex) { 1185 ERR.log(Level.WARNING, null, ex); 1187 } catch (IOException ex) { 1188 ERR.log(Level.WARNING, null, ex); 1191 } finally { 1192 1193 if (Boolean.getBoolean("netbeans.profile.memory")) { parser.setContentHandler(NullHandler.INSTANCE); 1199 parser.setErrorHandler(NullHandler.INSTANCE); 1200 try { 1201 parser.setProperty("http://xml.org/sax/properties/lexical-handler", NullHandler.INSTANCE); } catch (SAXException ignoreIt) { 1203 } 1204 1205 try { 1206 parser.parse((InputSource)null); 1208 } catch (Exception ignoreIt) { 1209 } 1210 } 1211 1212 parser = null; 1213 } 1214 1215 } finally { 1216 try { 1217 if (in != null) in.close(); 1218 } catch (IOException ex) { 1219 ERR.log(Level.WARNING, null, ex); 1220 } 1221 } 1222 1223 } 1224 1225 if (ignorePreviousId != null && newID.equals (ignorePreviousId)) { 1226 if (ERR.isLoggable(Level.FINE)) ERR.fine("No update to ID: " + ignorePreviousId + " for " + XMLDataObject.this); return newID; 1229 } 1230 1231 if (ERR.isLoggable(Level.FINE)) ERR.fine("New id: " + newID + " for " + XMLDataObject.this); 1236 if (newID != null) { 1237 updateLookup (previousID, newID); 1238 } 1239 1240 return newID; 1241 } 1242 1243 1244 1246 private Lookup updateLookup (String previousID, String id) { 1247 synchronized (this) { 1248 if (previousID != null && previousID.equals (id) && lookup != null) { 1249 ERR.fine("No need to update lookup: " + id + " for " + XMLDataObject.this); return lookup; 1251 } 1252 } 1253 1254 1255 Lookup newLookup; 1256 1257 Info info = getRegisteredInfo (id); 1260 if (info != null) { 1261 newLookup = createInfoLookup (XMLDataObject.this, info); 1263 if (ERR.isLoggable(Level.FINE)) ERR.fine("Lookup from info: " + newLookup + " for " + XMLDataObject.this); } else { 1265 newLookup = Environment.findForOne (XMLDataObject.this); 1267 if (ERR.isLoggable(Level.FINE)) ERR.fine("Lookup from env: " + newLookup + " for " + XMLDataObject.this); if (newLookup == null) { 1269 newLookup = Lookup.EMPTY; 1270 } 1271 } 1272 1273 synchronized (this) { 1274 Lookup.Result prevRes = result; 1276 1277 lookup = newLookup; 1278 if (ERR.isLoggable(Level.FINE)) ERR.fine("Shared lookup updated: " + lookup + " for " + XMLDataObject.this); result = lookup.lookupResult(Node.Cookie.class); 1280 result.addLookupListener (this); 1281 1282 if (prevRes != null) { 1283 prevRes.removeLookupListener (this); 1284 if (ERR.isLoggable(Level.FINE)) ERR.fine("Firing property change for " + XMLDataObject.this); XMLDataObject.this.firePropertyChange (DataObject.PROP_COOKIE, null, null); 1286 if (ERR.isLoggable(Level.FINE)) ERR.fine("Firing done for " + XMLDataObject.this); } 1288 1289 return newLookup; 1290 } 1291 } 1292 1293 1294 1297 private void configureParser(XMLReader parser, boolean validation, LexicalHandler lex) { 1298 1299 try { 1300 parser.setFeature("http://xml.org/sax/features/validation", validation); } catch (SAXException sex) { 1302 ERR.fine("Warning: XML parser does not support validation feature."); } 1304 1305 try { 1306 parser.setProperty("http://xml.org/sax/properties/lexical-handler", lex); } catch (SAXException sex) { 1308 ERR.fine("Warning: XML parser does not support lexical-handler feature."); } 1311 } 1312 1313 1314 1315 1317 public void warning (Throwable ex) { 1318 warning(ex, null); 1319 } 1320 1321 public void warning (Throwable ex, String annotation) { 1322 ERR.log(Level.WARNING, annotation, ex); 1323 } 1324 1325 1327 public void startDTD(String root, String pID, String sID) throws SAXException { 1328 parsedId = pID == null ? NULL : pID; 1329 ERR.fine("Parsed to " + parsedId); stop(); 1331 } 1332 1333 public void endDTD() throws SAXException { 1334 stop(); 1335 } 1336 1337 public void startEntity(String name) throws SAXException { 1338 } 1339 1340 public void endEntity(String name) throws SAXException { 1341 } 1342 1343 public void startCDATA() throws SAXException { 1344 } 1345 1346 public void endCDATA() throws SAXException { 1347 } 1348 1349 public void comment(char[] ch, int start, int length) throws SAXException { 1350 } 1351 1352 1354 public void error(final SAXParseException p1) throws org.xml.sax.SAXException { 1356 stop(); 1357 } 1358 1359 public void fatalError(final SAXParseException p1) throws org.xml.sax.SAXException { 1360 stop(); 1361 } 1362 1363 public void endDocument() throws SAXException { 1364 stop(); 1365 } 1366 1367 public void startElement(String uri, String lName, String qName, Attributes atts) throws SAXException { 1368 stop(); 1370 } 1371 1372 private void stop() throws SAXException { 1373 throw STOP; 1374 } 1375 1376 1377 1380 public void fileFolderCreated (FileEvent fe) { 1381 } 1383 1384 public void fileDataCreated (FileEvent fe) { 1385 } 1388 1389 private void fileCreated(FileObject fo) { 1390 } 1397 1398 1401 public void fileChanged (FileEvent fe) { 1402 if (getPrimaryFile ().equals (fe.getFile ())) { 1403 clearDocument (); 1406 String prevId = parsedId; 1407 parsedId = null; 1408 ERR.fine("cleared parsedId"); waitFinished (prevId); 1411 } 1412 } 1413 1414 public void fileDeleted (FileEvent fe) { 1415 } 1416 1417 public void fileRenamed (FileRenameEvent fe) { 1418 } 1423 1424 public void fileAttributeChanged (FileAttributeEvent fe) { 1425 } 1427 1428 1430 public void resultChanged(LookupEvent lookupEvent) { 1431 XMLDataObject.this.firePropertyChange (DataObject.PROP_COOKIE, null, null); 1432 1433 Node n = XMLDataObject.this.getNodeDelegateOrNull (); 1434 if (n instanceof XMLNode) { 1435 ((XMLNode)n).update (); 1436 } 1437 } 1438 1439 } 1441 1442 1443 private static class EmptyEntityResolver implements EntityResolver { 1444 EmptyEntityResolver() {} 1445 public InputSource resolveEntity(String publicId, String systemID) { 1446 InputSource ret = new InputSource(new StringReader("")); ret.setSystemId("StringReader"); return ret; 1449 } 1450 } 1451 1452 1453 1454 1456 1457 1459 static final class Loader extends MultiFileLoader { 1460 static final long serialVersionUID =3917883920409453930L; 1461 1462 public Loader () { 1463 super ("org.openide.loaders.XMLDataObject"); } 1467 protected String actionsContext () { 1468 return "Loaders/text/xml/Actions"; } 1470 1471 1474 protected String defaultDisplayName () { 1475 return NbBundle.getMessage (XMLDataObject.class, "PROP_XmlLoader_Name"); 1476 } 1477 1478 1484 protected FileObject findPrimaryFile (FileObject fo) { 1485 String mime = fo.getMIMEType (); 1486 if (mime.endsWith("/xml") || mime.endsWith("+xml")) { return fo; 1488 } 1489 return null; 1491 } 1492 1493 1501 protected MultiDataObject createMultiObject (FileObject primaryFile) 1502 throws DataObjectExistsException { 1503 return new XMLDataObject (primaryFile, this); 1504 } 1505 1506 1511 protected MultiDataObject.Entry createPrimaryEntry (MultiDataObject obj, FileObject primaryFile) { 1512 return new FileEntry (obj, primaryFile); 1513 } 1514 1515 1521 protected MultiDataObject.Entry createSecondaryEntry (MultiDataObject obj, FileObject secondaryFile) { 1522 return new FileEntry (obj, secondaryFile); 1524 } 1525 } 1526 1527 1529 1531 1537 @Deprecated 1538 public static interface Processor extends Node.Cookie { 1539 1544 public void attachTo (XMLDataObject xmlDO); 1545 } 1546 1547 1548 1551 @Deprecated 1552 public static final class Info implements Cloneable { 1553 List<Class <?>> processors; 1554 String iconBase; 1555 1556 1557 public Info () { 1558 processors = new ArrayList<Class <?>> (); 1559 iconBase = null; 1560 } 1561 1562 public Object clone () { 1563 Info ii = new Info(); 1564 for (Class <?> proc: processors) { 1565 ii.processors.add (proc); 1566 } 1567 ii.iconBase = iconBase; 1568 return ii; 1569 } 1570 1571 1579 public synchronized void addProcessorClass(Class <?> proc) { 1580 if (!Processor.class.isAssignableFrom (proc)) { 1581 Constructor[] arr = proc.getConstructors(); 1582 for (int i = 0; i < arr.length; i++) { 1583 Class [] params = arr[i].getParameterTypes(); 1584 if (params.length == 1) { 1585 if ( 1586 params[0] == DataObject.class || 1587 params[0] == XMLDataObject.class 1588 ) { 1589 arr = null; 1590 break; 1591 } 1592 } 1593 } 1594 1595 if (arr != null) { 1596 throw new IllegalArgumentException (); 1598 } 1599 } 1600 1601 processors.add (proc); 1602 } 1603 1604 1607 public boolean removeProcessorClass(Class <?> proc) { 1608 return processors.remove (proc); 1609 } 1610 1611 public Iterator<Class <?>> processorClasses() { 1612 return processors.iterator(); 1613 } 1614 1615 1616 public void setIconBase (String base) { 1617 iconBase = base; 1618 } 1619 1620 1621 public String getIconBase () { 1622 return iconBase; 1623 } 1624 1625 1626 public void write (Writer writer) throws IOException { 1627 throw new IOException ("Not supported anymore"); } 1629 1630 public boolean equals (Object obj) { 1631 if (obj == null) return false; 1632 if (obj instanceof Info == false) return false; 1633 1634 Info i = (Info) obj; 1635 1636 return ((iconBase != null && iconBase.equals(i.iconBase)) || (i.iconBase == iconBase)) 1637 && processors.equals(i.processors); 1638 } 1639 } 1641 1642 1646 static Lookup createInfoLookup (XMLDataObject obj, Info info) { 1647 return new InfoLkp (obj, info); 1648 } 1649 1650 1651 1654 private static final class InfoLkp extends AbstractLookup { 1655 public final Info info; 1656 1657 public InfoLkp (XMLDataObject obj, Info info) { 1658 this.info = info; 1659 1660 Iterator<Class <?>> it = info.processorClasses (); 1661 ArrayList<InfoPair> arr = new ArrayList<InfoPair> (info.processors.size ()); 1662 while (it.hasNext ()) { 1663 Class <?> c = it.next (); 1664 arr.add (new InfoPair (obj, c)); 1665 } 1666 1667 setPairs (arr); 1668 } 1669 1670 1674 private static final class InfoPair extends AbstractLookup.Pair { 1675 1676 private Class <?> clazz; 1677 1678 private Object obj; 1679 1680 1681 protected InfoPair (XMLDataObject obj, Class <?> c) { 1682 this.obj = obj; 1683 this.clazz = c; 1684 } 1685 1686 1689 protected boolean instanceOf (Class c) { 1690 Class <?> temp = clazz; 1691 if (temp == null) { 1692 return c.isInstance (obj); 1693 } else { 1694 return c.isAssignableFrom (temp); 1695 } 1696 } 1697 1698 1705 protected boolean creatorOf (Object obj) { 1706 return this.obj == obj; 1707 } 1708 1709 1712 public synchronized Object getInstance () { 1713 if (clazz == null) { 1714 return obj; 1716 } 1717 1718 XMLDataObject xmlDataObject = (XMLDataObject)obj; 1721 obj = null; 1722 1723 Class next = clazz; 1726 clazz = null; 1727 1728 try { 1729 if (Processor.class.isAssignableFrom (next)) { 1730 obj = next.newInstance (); 1733 Processor proc = (Processor) obj; 1734 proc.attachTo (xmlDataObject); 1735 return obj; 1736 } else { 1737 1741 Constructor[] arr = next.getConstructors(); 1742 for (int i = 0; i < arr.length; i++) { 1743 Class [] params = arr[i].getParameterTypes(); 1744 if (params.length == 1) { 1745 if ( 1746 params[0] == DataObject.class || 1747 params[0] == XMLDataObject.class 1748 ) { 1749 obj = arr[i].newInstance( 1750 new Object [] { xmlDataObject } 1751 ); 1752 return obj; 1753 } 1754 } 1755 } 1756 } 1757 throw new InternalError ("XMLDataObject processor class " + next + " invalid"); } catch (InvocationTargetException e) { 1759 xmlDataObject.notifyEx (e); 1760 } catch (InstantiationException e) { 1761 xmlDataObject.notifyEx(e); 1762 } catch (IllegalAccessException e) { 1763 xmlDataObject.notifyEx(e); 1764 } 1765 1766 return obj; 1767 } 1768 1769 1772 public Class getType () { 1773 Class temp = clazz; 1774 return temp != null ? temp : obj.getClass (); 1775 } 1776 1777 1782 public String getId () { 1783 return "Info[" + getType ().getName (); } 1785 1786 1788 public String getDisplayName () { 1789 return getType ().getName (); 1790 } 1791 } 1792 } 1793 1794 1795 1797 private Node findNode () { 1798 Node n = (Node)getIP ().lookupCookie (Node.class); 1799 1800 if (n == null) { 1801 return new PlainDataNode(); 1802 } else { 1803 return n; 1804 } 1805 } 1806 1807 private final class PlainDataNode extends DataNode { 1808 public PlainDataNode() { 1809 super(XMLDataObject.this, Children.LEAF); 1810 setIconBaseWithExtension("org/openide/loaders/xmlObject.gif"); } 1812 public Action getPreferredAction() { 1813 return SystemAction.get(OpenAction.class); 1814 } 1815 } 1816 1817 1818 1821 private final class XMLNode extends FilterNode { 1822 public XMLNode (XMLDataObject obj) { 1823 this (obj.findNode ()); 1824 } 1825 private XMLNode (Node del) { 1826 super (del, new FilterNode.Children (del)); 1827 } 1829 private void update () { 1830 changeOriginal (XMLDataObject.this.findNode (), true); 1831 } 1832 1833 } 1834 1835 1837 private static class ICDel extends Object implements InstanceCookie.Of { 1838 1840 private XMLDataObject obj; 1841 1842 private InstanceCookie ic; 1843 1844 public ICDel (XMLDataObject obj, InstanceCookie ic) { 1845 this.obj = obj; 1846 this.ic = ic; 1847 } 1848 1849 1850 public String instanceName () { 1851 return ic.instanceName (); 1852 } 1853 1854 public Class <?> instanceClass () 1855 throws java.io.IOException , ClassNotFoundException { 1856 return ic.instanceClass (); 1857 } 1858 1859 public Object instanceCreate () 1860 throws java.io.IOException , ClassNotFoundException { 1861 return ic.instanceCreate (); 1862 } 1863 1864 public boolean instanceOf (Class cls2) { 1865 if (ic instanceof InstanceCookie.Of) { 1866 return ((InstanceCookie.Of) ic).instanceOf (cls2); 1867 } else { 1868 try { 1869 return cls2.isAssignableFrom (instanceClass ()); 1870 } catch (IOException ioe) { 1871 return false; 1873 } catch (ClassNotFoundException cnfe) { 1874 return false; 1876 } 1877 } 1878 } 1879 1880 public int hashCode () { 1881 return 2 * obj.hashCode () + ic.hashCode (); 1882 } 1883 1884 public boolean equals (Object obj) { 1885 if (obj instanceof ICDel) { 1886 ICDel d = (ICDel)obj; 1887 return d.obj == obj && d.ic == ic; 1888 } 1889 return false; 1890 } 1891 } 1893 1896 private final class DelDoc implements InvocationHandler { 1897 1898 private Reference<Document > xmlDocument; 1899 private final Document proxyDocument; 1900 1901 DelDoc() { 1902 proxyDocument = (Document )Proxy.newProxyInstance( 1903 DelDoc.class.getClassLoader(), new Class [] {Document .class}, this); 1904 } 1905 1906 1912 private final Document getDocumentImpl (boolean force) { 1913 synchronized (this) { 1914 Document doc = xmlDocument == null ? null : xmlDocument.get (); 1915 if (doc != null) { 1916 return doc; 1917 } 1918 1919 if (!force) { 1920 return null; 1921 } 1922 1923 status = STATUS_OK; 1924 try { 1925 Document d = parsePrimaryFile (); 1926 xmlDocument = new SoftReference<Document > (d); 1927 return d; 1928 } catch (SAXException e) { 1929 ERR.log(Level.WARNING, null, e); 1930 } catch (IOException e) { 1931 ERR.log(Level.WARNING, null, e); 1932 } 1933 1934 status = STATUS_ERROR; 1935 Document d = XMLUtil.createDocument("brokenDocument", null, null, null); 1937 xmlDocument = new SoftReference<Document > (d); 1938 1939 firePropertyChange (PROP_DOCUMENT, null, null); 1941 1942 return d; 1943 } 1944 } 1945 1946 1952 public Document getProxyDocument() { 1953 return proxyDocument; 1954 } 1955 1956 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 1957 if (method.getName().equals("getDoctype") && args == null) { return Proxy.newProxyInstance(DelDoc.class.getClassLoader(), new Class [] {DocumentType .class}, this); 1959 } else if (method.getName().equals("getPublicId") && args == null) { Document d = getDocumentImpl(false); 1961 if (d != null) { 1962 DocumentType doctype = d.getDoctype(); 1963 return doctype == null ? null : doctype.getPublicId(); 1964 } else { 1965 return getIP().getPublicId(); 1966 } 1967 } else { 1968 return method.invoke(getDocumentImpl(true), args); 1969 } 1970 } 1971 1972 } 1973 1974} 1975 | Popular Tags |