1 19 20 package org.netbeans.core.filesystems; 21 22 import java.lang.ref.WeakReference ; 23 import java.util.logging.Level ; 24 import java.util.logging.Logger ; 25 import org.openide.filesystems.FileObject; 26 import org.openide.util.NbBundle; 27 import org.openide.xml.XMLUtil; 28 import org.xml.sax.Attributes ; 29 import org.xml.sax.SAXException ; 30 import org.xml.sax.SAXParseException ; 31 import org.xml.sax.XMLReader ; 32 import org.xml.sax.ext.LexicalHandler ; 33 34 40 final class XMLMIMEComponent extends DefaultParser implements MIMEComponent { 41 42 private short parseState = INIT; 43 44 private final Smell template = new Smell(); 46 47 private static final LocalSniffingParser local = new LocalSniffingParser(); 49 50 52 public boolean acceptFileObject(FileObject fo) { 53 54 57 SniffingParser sniffer = local.getParser(); 58 Smell print = sniffer.sniff(fo); 59 return template.match(print); 63 } 64 65 public String toString() { 66 return template.toString(); 67 } 68 69 71 72 private static final short INIT = 0; 74 private static final short IN_ROOT = 1; 75 private static final short IN_DOCTYPE = 2; 76 private static final short IN_ELEMENT = 3; 77 78 private static final String ROOT = "xml-rule"; private static final String PI = "pi"; private static final String ELEMENT = "element"; private static final String DOCTYPE = "doctype"; private static final String PUBLIC_ID = "public-id"; private static final String ID = "id"; private static final String ATTR = "attr"; private static final String NAME = "name"; private static final String VALUE = "text"; private static final String NS = "ns"; private static final String TARGET = "target"; 91 92 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 93 94 String s; 95 96 switch (parseState) { 97 98 case INIT: 99 if (ROOT.equals(qName) == false) error(); 100 parseState = IN_ROOT; 101 break; 102 103 case IN_ROOT: 104 if (PI.equals(qName)) { 105 s = atts.getValue(TARGET); if (s == null) error(); 106 template.addPI(s); 107 108 110 } else if (DOCTYPE.equals(qName)) { 111 s = atts.getValue(PUBLIC_ID); 112 if (s == null) { 113 parseState = IN_DOCTYPE; 114 break; 115 } else { 116 template.addDoctype(s); 117 } 118 119 } else if (ELEMENT.equals(qName)) { 120 121 s = atts.getValue(NAME); 122 if (s == null) { 123 s = atts.getValue(NS); 124 if (s != null) template.addElementNS(s); 125 } else { 126 template.addElementName(s); 127 s = atts.getValue(NS); 128 if (s != null) template.addElementNS(s); 129 } 130 131 parseState = IN_ELEMENT; 132 133 } else { 134 error(); 135 } 136 break; 137 138 case IN_DOCTYPE: 139 if (PUBLIC_ID.equals(qName) == false) error(); 140 s = atts.getValue(ID); if (s == null) error(); 141 template.addDoctype(s); 142 break; 143 144 case IN_ELEMENT: 145 if (ATTR.equals(qName)) { 146 s = atts.getValue(NAME); if (s == null) error(); 147 template.addElementAtt(s, atts.getValue(VALUE)); 148 149 } else if (NS.equals(qName)) { 150 s = atts.getValue(NAME); if (s == null) error(); 151 template.addElementNS(s); 152 153 } else { 154 error(); 155 } 156 157 } 158 } 159 160 public void endElement(String namespaceURI, String localName, String qName) { 161 162 switch (parseState) { 163 case IN_ELEMENT: 164 if (ELEMENT.equals(qName)) parseState = IN_ROOT; 165 break; 166 167 case IN_DOCTYPE: 168 if (DOCTYPE.equals(qName)) parseState = IN_ROOT; 169 break; 170 } 171 } 172 173 175 176 180 private static class LocalSniffingParser extends ThreadLocal <WeakReference <SniffingParser>> { 181 LocalSniffingParser() {} 182 183 private WeakReference <SniffingParser> wref = null; 184 185 protected WeakReference <SniffingParser> initialValue() { 186 SniffingParser parser = new SniffingParser(); 187 wref = new WeakReference <SniffingParser>(parser); 188 return wref; 189 } 190 191 public SniffingParser getParser() { 192 WeakReference <SniffingParser> cache = get(); 193 SniffingParser cached = cache.get(); 194 if (cached == null) { 195 cached = new SniffingParser(); 196 wref = new WeakReference <SniffingParser>(cached); 197 super.set(wref); 198 } 199 return cached; 200 } 201 202 public void set(WeakReference <SniffingParser> data) { 203 } 205 } 206 207 208 211 private static class SniffingParser extends DefaultParser implements LexicalHandler { 212 213 SniffingParser() { 214 super(null); 215 } 216 217 private FileObject lastFileObject = null; 219 220 private Smell print = null; 221 222 private static final SAXException STOP = new SAXException ("STOP"); 225 228 protected Smell sniff(FileObject fo) { 229 230 if (fo == null) return null; 231 232 if (fo.equals(lastFileObject)) return print; 233 234 if (fo.isValid() == false) return null; 235 236 if (fo.getSize() == 0) return null; 237 238 print = new Smell(); 239 parse(fo); 240 if (this.state == ERROR) { 241 return null; 242 } 243 244 lastFileObject = fo; 245 return print; 246 } 247 248 protected XMLReader createXMLReader() { 249 XMLReader parser = null; 250 251 try { 252 parser = XMLUtil.createXMLReader(false, true); 253 try { 254 parser.setProperty("http://xml.org/sax/properties/lexical-handler", this); } catch (SAXException sex) { 256 Logger.getLogger(XMLMIMEComponent.class.getName()).fine(NbBundle.getMessage(XMLMIMEComponent.class, "W-003")); } 258 } catch (SAXException ex) { 259 Logger.getLogger(XMLMIMEComponent.class.getName()).log(Level.WARNING, null, ex); 260 } 261 return parser; 262 } 263 264 protected boolean isStopException(Exception e) { 265 return STOP.getMessage().equals(e.getMessage()); 266 } 267 268 269 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { 270 if (namespaceURI != null) { 271 print.addElementNS(namespaceURI); 272 } 273 if ("".equals(localName)) localName = null; print.addElementName(localName != null ? localName : qName); 275 for (int i = 0; i<atts.getLength(); i++) { 276 print.addElementAtt(atts.getQName(i), atts.getValue(i)); 277 } 278 throw STOP; 279 } 280 281 public void processingInstruction(String target, String data) throws SAXException { 282 print.addPI(target); 283 } 284 285 287 public void startDTD(String root, String pID, String sID) throws SAXException { 288 print.addDoctype(pID); 289 } 290 291 public void endDTD() {} 292 293 public void startEntity(String name) {} 294 295 public void endEntity(String name) {} 296 297 public void startCDATA() {} 298 299 public void endCDATA() {} 300 301 public void comment(char[] ch, int start, int length) {} 302 303 public void error(SAXParseException exception) throws SAXException { 304 Logger.getLogger(XMLMIMEComponent.class.getName()).warning(exception.getMessage()); 306 this.state = ERROR; 307 throw STOP; 308 } 309 310 public void fatalError(SAXParseException exception) throws SAXException { 311 312 Logger emgr = Logger.getLogger("org.netbeans.core.filesystems.XMLMIMEComponent"); if (emgr.isLoggable(Level.FINE)) { 316 emgr.fine("[while parsing " + fo + "] " + exception.getSystemId() + ":" + exception.getLineNumber() + ":" + exception.getColumnNumber() + ": " + exception.getMessage()); } 318 319 this.state = ERROR; 320 throw STOP; 321 } 322 323 324 } 325 326 328 331 private static class Smell { 332 Smell() {} 333 334 private String [] doctypes = null; 335 private String [] pis = null; 336 337 private String root = null; 338 private String [] nss = null; 339 340 private String [] attns = null; 341 private String [] attvs = null; 342 343 public String toString() { 344 StringBuffer buf = new StringBuffer (); 345 int i = 0; 346 buf.append("xml-check("); 347 348 if (doctypes != null) { 349 buf.append("doctypes:"); 350 for (i = 0; i<doctypes.length; i++) 351 buf.append(doctypes[i]).append(", "); 352 } 353 354 if (pis != null) { 355 buf.append("PIs:"); 356 for (i = 0; i<pis.length; i++) 357 buf.append(pis[i]).append(", "); 358 } 359 360 if (root != null) { 361 buf.append("root:").append(root); 362 } 363 364 if (nss != null) { 365 buf.append("root-namespaces:"); 366 for (i = 0; i<nss.length; i++) 367 buf.append(nss[i]).append(", "); 368 } 369 370 if (attns != null) { 371 buf.append("attributes:"); 372 for (i = 0; i<attns.length; i++) 373 buf.append(attns[i]).append("='").append(attvs[i]).append("'"); 374 } 375 376 buf.append(')'); 377 return buf.toString(); 378 379 } 380 381 private void addDoctype(String s) { 382 if (doctypes == null) { 383 doctypes = new String [] { s }; 384 } else { 385 doctypes = Util.addString(doctypes, s); 386 } 387 } 388 389 private void addPI(String s) { 390 if (pis == null) { 391 pis = new String [] { s }; 392 } else { 393 pis = Util.addString(pis, s); 394 } 395 } 396 397 private void addElementNS(String s) { 398 if (nss == null) { 399 nss = new String [] { s }; 400 } else { 401 nss = Util.addString(nss, s); 402 } 403 } 404 405 private void addElementName(String name) { 406 root = name; 407 } 408 409 private void addElementAtt(String name, String value) { 410 if (attns == null) { 411 attns = new String [] {name}; 412 attvs = new String [] {value}; 413 } else { 414 attns = Util.addString(attns, name); 415 attvs = Util.addString(attvs, value); 416 } 417 418 } 419 420 424 public boolean match(Smell t) { 425 426 if (t == null) return false; 427 428 430 if (doctypes != null && t.doctypes != null) { 431 if (Util.contains(doctypes, t.doctypes[0])) return true; 432 } 433 434 436 if (root != null && root.equals(t.root)) { 437 if (nss == null) { 438 if (attMatch(t)) return true; 439 } else { 440 if (t.nss != null && Util.contains(nss, t.nss[0])) { 441 if (attMatch(t)) return true; 442 } 443 } 444 } else { 445 if (root == null && nss != null && t.nss != null && Util.contains(nss, t.nss[0])) { 446 if (attMatch(t)) return true; 447 } 448 } 449 450 452 if (pis != null && t.pis!=null) { 453 for (int i = 0; i<pis.length; i++) { 454 for (int j = 0; j<t.pis.length; j++) { 455 if (pis[i].equals(t.pis[j])) return true; 456 } 457 } 458 } 459 460 return false; 461 } 462 463 464 private boolean attMatch(Smell t) { 465 466 if (attns == null) return true; 467 if (t.attns == null) return false; 468 469 for (int i = 0 ; i<attns.length; i++) { 471 int match = Util.indexOf(t.attns, attns[i]); 472 if (match == -1) { 473 return false; 474 } 475 476 478 if (attvs[i] != null && (!attvs[i].equals(t.attvs[match]))) { 479 return false; 480 } 481 } 482 483 return true; 484 485 } 486 487 } 488 } 489 | Popular Tags |