1 19 package org.netbeans.spi.xml.cookies; 20 21 import java.io.*; 22 import java.net.*; 23 import java.util.*; 24 import java.security.ProtectionDomain ; 25 import java.security.CodeSource ; 26 27 import javax.xml.parsers.SAXParser ; 28 import javax.xml.parsers.SAXParserFactory ; 29 import javax.swing.text.Document ; 30 31 import org.openide.cookies.*; 32 import org.openide.util.*; 33 import org.openide.filesystems.FileStateInvalidException; 34 import org.openide.ErrorManager; 35 36 import org.xml.sax.*; 37 import org.xml.sax.helpers.DefaultHandler ; 38 39 import org.netbeans.api.xml.cookies.*; 40 import org.netbeans.api.xml.services.*; 41 import org.netbeans.api.xml.parsers.*; 42 43 44 53 class SharedXMLSupport { 54 55 private CookieObserver console; 57 58 private final InputSource inputSource; 60 61 private final int mode; 63 64 private Locator locator; 66 67 private int fatalErrors; 69 70 private int errors; 72 73 81 private boolean bogusSchemaRequest; 82 83 private boolean reportBogusSchemaRequest = 86 Boolean.getBoolean("netbeans.xml.reportBogusSchemaLocation"); 88 92 public SharedXMLSupport(InputSource inputSource) { 93 this(inputSource, CheckXMLSupport.DOCUMENT_MODE); 94 } 95 96 101 public SharedXMLSupport(InputSource inputSource, int mode) { 102 103 if (inputSource == null) throw new NullPointerException (); 104 if (mode < CheckXMLSupport.CHECK_ENTITY_MODE || mode > CheckXMLSupport.DOCUMENT_MODE) { 105 throw new IllegalArgumentException (); 106 } 107 108 this.inputSource = inputSource; 109 this.mode = mode; 110 } 111 112 boolean checkXML(CookieObserver l) { 114 try { 115 console = l; 116 117 parse(false); 118 119 return fatalErrors == 0; 120 } finally { 121 console = null; 122 locator = null; 123 } 124 } 125 126 boolean validateXML(CookieObserver l) { 128 try { 129 console = l; 130 131 if (mode != CheckXMLSupport.DOCUMENT_MODE) { 132 sendMessage(Util.THIS.getString("MSG_not_a_doc")); 133 return false; 134 } else { 135 parse(true); 136 return errors == 0 && fatalErrors == 0; 137 } 138 } finally { 139 console = null; 140 locator = null; 141 } 142 } 143 144 145 146 149 private void parse (boolean validate) { 150 151 fatalErrors = 0; 152 errors = 0; 153 154 String checkedFile = inputSource.getSystemId(); 155 sendMessage(Util.THIS.getString("MSG_checking", checkedFile)); 156 157 Handler handler = new Handler (); 158 159 160 InputSource input = null; 161 162 try { 163 XMLReader parser = createParser(validate); 165 if (parser == null) { 166 fatalErrors++; 167 console.receive(new CookieMessage( 168 Util.THIS.getString("MSG_cannot_create_parser"), 169 CookieMessage.FATAL_ERROR_LEVEL 170 )); 171 return; 172 } 173 174 if (validate) { 175 input=ShareableInputSource.create(createInputSource()); 177 String [] schemaLocations=getSchemaLocations(input); 178 try { 179 ((ShareableInputSource)input).reset(); 180 }catch(IOException e) { 181 input=createInputSource(); 184 } 185 if (schemaLocations!=null && schemaLocations.length>0) { 186 boolean first=true; 187 StringBuffer sb = new StringBuffer (); 188 for (int i=0;i<schemaLocations.length;i++) { 189 sb.append(first?schemaLocations[i]:" "+schemaLocations[i]); 190 first=false; 191 } 192 parser.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", sb.toString()); } 194 } else input = createInputSource(); 195 196 parser.setErrorHandler(handler); 197 parser.setContentHandler(handler); 198 199 if ( Util.THIS.isLoggable()) { 200 Util.THIS.debug(checkedFile + ":" + parserDescription(parser)); 201 } 202 203 if (mode == CheckXMLSupport.CHECK_ENTITY_MODE) { 205 new SAXEntityParser(parser, true).parse(input); 206 } else if (mode == CheckXMLSupport.CHECK_PARAMETER_ENTITY_MODE) { 207 new SAXEntityParser(parser, false).parse(input); 208 } else { 209 parser.parse (input); 210 } 211 212 } catch (SAXException ex) { 213 214 217 } catch (FileStateInvalidException ex) { 218 219 handler.fatalError(new SAXParseException(ex.getLocalizedMessage(), locator, ex)); 221 222 } catch (IOException ex) { 223 224 handler.fatalError(new SAXParseException (ex.getLocalizedMessage(), locator, ex)); 227 228 } catch (RuntimeException ex) { 229 230 handler.runtimeError(ex); 231 } finally { 232 if (input instanceof ShareableInputSource) 233 try { 234 ((ShareableInputSource)input).closeAll(); 235 } catch (IOException ex) {} 236 } 237 238 } 239 240 245 protected EntityResolver createEntityResolver() { 246 UserCatalog catalog = UserCatalog.getDefault(); 247 return catalog == null ? null : catalog.getEntityResolver(); 248 } 249 250 255 protected InputSource createInputSource() throws IOException { 256 return inputSource; 257 } 258 259 265 protected XMLReader createParser(boolean validate) { 266 267 XMLReader ret = null; 268 final String XERCES_FEATURE_PREFIX = "http://apache.org/xml/features/"; final String XERCES_PROPERTY_PREFIX = "http://apache.org/xml/properties/"; 271 273 SAXParserFactory factory = SAXParserFactory.newInstance(); 274 factory.setNamespaceAware(true); 275 factory.setValidating(validate); 276 277 if (validate) { 279 try { 280 factory.setFeature(XERCES_FEATURE_PREFIX + "validation/schema", validate); } catch (Exception ex) { 282 sendMessage(Util.THIS.getString("MSG_parser_no_schema")); 283 } 284 } 285 286 try { 287 SAXParser parser = factory.newSAXParser(); 288 ret = parser.getXMLReader(); 289 } catch (Exception ex) { 290 sendMessage(Util.THIS.getString("MSG_parser_err_1")); 291 return null; 292 } 293 294 295 if (ret != null) { 296 EntityResolver res = createEntityResolver(); 297 if (res != null) ret.setEntityResolver(new VerboseEntityResolver(res)); 298 } 299 300 return ret; 301 302 } 303 304 307 private String parserDescription(XMLReader parser) { 308 309 311 Class klass = parser.getClass(); 312 try { 313 ProtectionDomain domain = klass.getProtectionDomain(); 314 CodeSource source = domain.getCodeSource(); 315 316 if (source == null && (klass.getClassLoader() == null || klass.getClassLoader().equals(Object .class.getClassLoader()))) { 317 return Util.THIS.getString("MSG_platform_parser"); 318 } else if (source == null) { 319 return Util.THIS.getString("MSG_unknown_parser", klass.getName()); 320 } else { 321 URL location = source.getLocation(); 322 return Util.THIS.getString("MSG_parser_plug", location.toExternalForm()); 323 } 324 325 } catch (SecurityException ex) { 326 return Util.THIS.getString("MSG_unknown_parser", klass.getName()); 327 } 328 329 } 330 331 333 334 private class Handler extends DefaultHandler { 335 336 public void warning (SAXParseException ex) { 337 338 340 String msg = ex.getLocalizedMessage(); 341 if (bogusSchemaRequest) { 342 bogusSchemaRequest = false; 343 if (msg != null && msg.indexOf("schema_reference.4") != -1) { if (reportBogusSchemaRequest) { 345 reportBogusSchemaRequest = false; 346 } else { 347 return; 348 } 349 } 350 } 351 352 CookieMessage message = new CookieMessage( 353 msg, 354 CookieMessage.WARNING_LEVEL, 355 new DefaultXMLProcessorDetail(ex) 356 ); 357 if (console != null) console.receive(message); 358 } 359 360 363 public void error (SAXParseException ex) throws SAXException { 364 if ( Util.THIS.isLoggable() ) Util.THIS.debug ("Just diagnostic exception", ex); if (errors++ == getMaxErrorCount()) { 366 String msg = Util.THIS.getString("MSG_too_many_errs"); 367 sendMessage(msg); 368 throw ex; } else { 370 CookieMessage message = new CookieMessage( 371 ex.getLocalizedMessage(), 372 CookieMessage.ERROR_LEVEL, 373 new DefaultXMLProcessorDetail(ex) 374 ); 375 if (console != null) console.receive(message); 376 } 377 } 378 379 382 private void runtimeError (RuntimeException ex) { 383 Util.THIS.debug("Parser runtime exception", ex ); 384 385 String msg = Util.THIS.getString("EX_parser_ierr", ex.getMessage()); 387 fatalError(new SAXParseException (msg, SharedXMLSupport.this.locator, ex)); 388 } 389 390 public void fatalError (SAXParseException ex) { 391 if ( Util.THIS.isLoggable() ) Util.THIS.debug("Just diagnostic exception", ex); fatalErrors++; 393 CookieMessage message = new CookieMessage( 394 ex.getLocalizedMessage(), 395 CookieMessage.FATAL_ERROR_LEVEL, 396 new DefaultXMLProcessorDetail(ex) 397 ); 398 if (console != null) console.receive(message); 399 } 400 401 public void setDocumentLocator(Locator locator) { 402 SharedXMLSupport.this.locator = locator; 403 } 404 405 private int getMaxErrorCount() { 406 return 20; } 408 409 } 410 411 412 415 private class VerboseEntityResolver implements EntityResolver { 416 417 private final EntityResolver peer; 418 419 public VerboseEntityResolver(EntityResolver res) { 420 if (res == null) throw new NullPointerException (); 421 peer = res; 422 } 423 424 public InputSource resolveEntity(String pid, String sid) throws SAXException, IOException { 425 426 InputSource result = peer.resolveEntity(pid, sid); 427 428 430 if (result == null) { 431 bogusSchemaRequest = pid == null && sid == null; 432 if (bogusSchemaRequest) return null; 433 434 String warning; 435 String pidLabel = pid != null ? pid : Util.THIS.getString("MSG_no_pid"); 436 try { 437 String file = new URL(sid).getFile(); 438 if (file != null) { 439 warning = Util.THIS.getString("MSG_resolver_1", pidLabel, sid); 440 } else { warning = Util.THIS.getString("MSG_resolver_2", pidLabel, sid); 442 } 443 } catch (MalformedURLException ex) { 444 warning = Util.THIS.getString("MSG_resolver_3", pidLabel, sid); 445 } 446 sendMessage(warning); 447 } 448 return result; 449 } 450 451 } 452 453 private void sendMessage(String message) { 454 if (console != null) { 455 console.receive(new CookieMessage(message)); 456 } 457 } 458 459 private String [] getSchemaLocations(InputSource is) { 460 EntityResolver res = createEntityResolver(); 461 if (res==null) return null; 462 NsHandler nsHandler = getNamespaces(is); 463 String [] namespaces = nsHandler.getNamespaces(); 464 List loc = new ArrayList(); 465 for (int i=0;i<namespaces.length;i++) { 466 String ns = namespaces[i]; 467 if (nsHandler.mapping.containsKey(ns)) { 468 loc.add(ns + " " + nsHandler.mapping.get(ns)); } else { 470 try { 471 javax.xml.transform.Source src = ((javax.xml.transform.URIResolver )res).resolve(ns, null); 472 if (src!=null) loc.add(ns+" "+src.getSystemId()); } catch (Exception ex) {} 474 } 475 } 476 String [] schemaLocations = new String [loc.size()]; 477 loc.toArray(schemaLocations); 478 return schemaLocations; 479 } 480 481 private NsHandler getNamespaces(InputSource is) { 482 NsHandler handler = new NsHandler(); 483 try { 484 XMLReader xmlReader = org.openide.xml.XMLUtil.createXMLReader(false, true); 485 xmlReader.setContentHandler(handler); 486 487 UserCatalog userCatalog = UserCatalog.getDefault(); 492 if (userCatalog != null) { 493 EntityResolver resolver = userCatalog.getEntityResolver(); 494 if (resolver != null) { 495 xmlReader.setEntityResolver(resolver); 496 } 497 } 498 xmlReader.parse(is); 499 } catch (IOException ex) { 500 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 501 } catch (SAXException ex) { 502 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 503 } 504 return handler; 505 } 506 507 private static class NsHandler extends org.xml.sax.helpers.DefaultHandler { 508 Set namespaces; 509 private Map mapping; 510 511 NsHandler() { 512 namespaces=new HashSet(); 513 mapping = new HashMap(); 514 } 515 516 public void startElement(String uri, String localName, String rawName, Attributes atts) throws SAXException { 517 if (atts.getLength()>0) { String locations = atts.getValue("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"); if (locations != null) { 521 StringTokenizer tokenizer = new StringTokenizer(locations); 522 if ((tokenizer.countTokens() % 2) == 0) { 523 while (tokenizer.hasMoreElements()) { 524 String nsURI = tokenizer.nextToken(); 525 String nsLocation = tokenizer.nextToken(); 526 mapping.put(nsURI, nsLocation); 527 } 528 } 529 } 530 } 531 } 532 533 public void startPrefixMapping(String prefix, String uri) throws SAXException { 534 if ("http://www.w3.org/2001/XMLSchema-instance".equals(uri)) { return; } 537 namespaces.add(uri); 538 } 539 540 String [] getNamespaces() { 541 String [] ns = new String [namespaces.size()]; 542 namespaces.toArray(ns); 543 return ns; 544 } 545 546 } 547 548 } 549 | Popular Tags |