1 19 20 package org.netbeans.upgrade.systemoptions; 21 22 import java.io.BufferedInputStream ; 23 import java.io.ByteArrayInputStream ; 24 import java.io.ByteArrayOutputStream ; 25 import java.io.CharArrayWriter ; 26 import java.io.IOException ; 27 import java.io.InputStream ; 28 import java.io.InputStreamReader ; 29 import java.io.ObjectInput ; 30 import java.io.ObjectInputStream ; 31 import java.io.OutputStream ; 32 import java.io.PrintWriter ; 33 import java.io.Reader ; 34 import java.io.StringWriter ; 35 import java.lang.reflect.Method ; 36 import java.util.HashSet ; 37 import java.util.Set ; 38 import java.util.Stack ; 39 import org.openide.ErrorManager; 40 import org.openide.filesystems.FileObject; 41 import org.openide.util.Lookup; 43 import org.openide.util.SharedClassObject; 44 import org.xml.sax.Attributes ; 45 import org.xml.sax.SAXException ; 46 import org.xml.sax.XMLReader ; 47 48 51 public class SettingsRecognizer extends org.xml.sax.helpers.DefaultHandler { 52 public static final String INSTANCE_DTD_ID = "-//NetBeans//DTD Session settings 1.0//EN"; static final ErrorManager err = ErrorManager.getDefault().getInstance(SettingsRecognizer.class.getName()); 55 private static final String ELM_SETTING = "settings"; private static final String ATR_SETTING_VERSION = "version"; 58 private static final String ELM_MODULE = "module"; private static final String ATR_MODULE_NAME = "name"; private static final String ATR_MODULE_SPEC = "spec"; private static final String ATR_MODULE_IMPL = "impl"; 63 private static final String ELM_INSTANCE = "instance"; private static final String ATR_INSTANCE_CLASS = "class"; private static final String ATR_INSTANCE_METHOD = "method"; 67 private static final String ELM_INSTANCEOF = "instanceof"; private static final String ATR_INSTANCEOF_CLASS = "class"; 70 private static final String ELM_SERIALDATA = "serialdata"; private static final String ATR_SERIALDATA_CLASS = "class"; 73 75 private boolean header; 76 private Stack <String > stack; 77 78 private String version; 79 private String instanceClass; 80 private String instanceMethod; 81 private Set <String > instanceOf = new HashSet <String >(); 82 83 private byte[] serialdata; 84 private CharArrayWriter chaos = null; 85 86 private String codeName; 87 private String codeNameBase; 88 private int codeNameRelease; 89 private String moduleImpl; 91 92 private final FileObject source; 93 94 98 public SettingsRecognizer(boolean header, FileObject source) { 99 this.header = header; 100 this.source = source; 101 } 102 103 public boolean isAllRead() { 104 return !header; 105 } 106 107 public void setAllRead(boolean all) { 108 if (!header) return; 109 header = all; 110 } 111 112 public String getSettingsVerison() { 113 return version; 114 } 115 116 public String getCodeName() { 117 return codeName; 118 } 119 120 public String getCodeNameBase() { 121 return codeNameBase; 122 } 123 124 public int getCodeNameRelease() { 125 return codeNameRelease; 126 } 127 128 131 132 public String getModuleImpl() { 133 return moduleImpl; 134 } 135 136 137 public Set getInstanceOf() { 138 return instanceOf; 139 } 140 141 142 public String getMethodName() { 143 return instanceMethod; 144 } 145 146 147 public InputStream getSerializedInstance() { 148 if (serialdata == null) return null; 149 return new ByteArrayInputStream (serialdata); 150 } 151 152 public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) 153 throws SAXException { 154 if (INSTANCE_DTD_ID.equals(publicId)) { 155 return new org.xml.sax.InputSource (new ByteArrayInputStream (new byte[0])); 156 } else { 157 return null; } 159 } 160 161 public void characters(char[] values, int start, int length) throws SAXException { 162 if (header) return; 163 String element = stack.peek(); 164 if (ELM_SERIALDATA.equals(element)) { 165 if (chaos == null) chaos = new CharArrayWriter (length); 167 chaos.write(values, start, length); 168 } 169 } 170 171 public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException { 172 stack.push(qName); 173 if (ELM_SETTING.equals(qName)) { 174 version = attribs.getValue(ATR_SETTING_VERSION); 175 } else if (ELM_MODULE.equals(qName)) { 176 codeName = attribs.getValue(ATR_MODULE_NAME); 177 resolveModuleElm(codeName); 178 moduleImpl = attribs.getValue(ATR_MODULE_IMPL); 179 try { 180 String spec = attribs.getValue(ATR_MODULE_SPEC); 181 } catch (NumberFormatException nfe) { 183 throw new SAXException (nfe); 184 } 185 } else if (ELM_INSTANCEOF.equals(qName)) { 186 instanceOf.add(org.openide.util.Utilities.translate( 187 attribs.getValue(ATR_INSTANCEOF_CLASS))); 188 } else if (ELM_INSTANCE.equals(qName)) { 189 instanceClass = attribs.getValue(ATR_INSTANCE_CLASS); 190 if (instanceClass == null) { 191 System.err.println("Hint: NPE is caused by broken settings file: " + source ); } 193 instanceClass = org.openide.util.Utilities.translate(instanceClass); 194 instanceMethod = attribs.getValue(ATR_INSTANCE_METHOD); 195 } else if (ELM_SERIALDATA.equals(qName)) { 196 instanceClass = attribs.getValue(ATR_SERIALDATA_CLASS); 197 instanceClass = org.openide.util.Utilities.translate(instanceClass); 198 if (header) throw new StopSAXException(); 199 } 200 } 201 202 203 private void resolveModuleElm(String codeName) { 204 if (codeName != null) { 205 int slash = codeName.indexOf("/"); if (slash == -1) { 207 codeNameBase = codeName; 208 codeNameRelease = -1; 209 } else { 210 codeNameBase = codeName.substring(0, slash); 211 try { 212 codeNameRelease = Integer.parseInt(codeName.substring(slash + 1)); 213 } catch (NumberFormatException ex) { 214 ErrorManager emgr = ErrorManager.getDefault(); 215 emgr.annotate(ex, "Content: \n" + getFileContent(source)); emgr.annotate(ex, "Source: " + source); emgr.notify(ErrorManager.INFORMATIONAL, ex); 218 codeNameRelease = -1; 219 } 220 } 221 } else { 222 codeNameBase = null; 223 codeNameRelease = -1; 224 } 225 } 226 227 public void endElement(String uri, String localName, String qName) throws SAXException { 228 String element = stack.pop(); 230 if (ELM_SERIALDATA.equals(element)) { 231 if (chaos != null) { 232 ByteArrayOutputStream baos = new ByteArrayOutputStream (chaos.size() >> 1); 233 try { 234 chars2Bytes(baos, chaos.toCharArray(), 0, chaos.size()); 235 serialdata = baos.toByteArray(); 236 } catch (IOException ex) { 237 ErrorManager.getDefault().notify( 238 ErrorManager.WARNING, ex 239 ); 240 } finally { 241 chaos = null; try { 243 baos.close(); 244 } catch (IOException ex) { 245 } 247 } 248 } 249 } 250 } 251 252 256 private Object readSerial(InputStream is) throws IOException , ClassNotFoundException { 257 if (is == null) return null; 258 try { 259 ObjectInput oi = new ObjectInputStream (is); 260 try { 261 Object o = oi.readObject(); 262 return o; 263 } finally { 264 oi.close(); 265 } 266 } catch (IOException ex) { 267 ErrorManager emgr = ErrorManager.getDefault(); 268 emgr.annotate(ex, "Content: \n" + getFileContent(source)); emgr.annotate(ex, "Source: " + source); emgr.annotate(ex, "Cannot read class: " + instanceClass); throw ex; 272 } catch (ClassNotFoundException ex) { 273 ErrorManager emgr = ErrorManager.getDefault(); 274 emgr.annotate(ex, "Content: \n" + getFileContent(source)); emgr.annotate(ex, "Source: " + source); throw ex; 277 } 278 } 279 280 285 public Object instanceCreate() throws java.io.IOException , ClassNotFoundException { 286 Object inst = null; 287 288 inst = readSerial(getSerializedInstance()); 290 291 if (inst == null) { 293 if (instanceMethod != null) { 294 inst = createFromMethod(instanceClass, instanceMethod); 295 } else { 296 Class <?> clazz = instanceClass(); 298 if (SharedClassObject.class.isAssignableFrom(clazz)) { 299 inst = SharedClassObject.findObject(clazz.asSubclass(SharedClassObject.class), false); 300 if (null != inst) { 301 try { 303 Method method = SharedClassObject.class.getDeclaredMethod("reset", new Class [0]); method.setAccessible(true); 305 method.invoke(inst, new Object [0]); 306 } catch (Exception e) { 307 ErrorManager.getDefault().notify(e); 308 } 309 } else { 310 inst = SharedClassObject.findObject(clazz.asSubclass(SharedClassObject.class), true); 311 } 312 } else { 313 try { 314 inst = clazz.newInstance(); 315 } catch (Exception ex) { 316 IOException ioe = new IOException (); 317 ErrorManager emgr = ErrorManager.getDefault(); 318 emgr.annotate(ioe, ex); 319 emgr.annotate(ioe, "Content: \n" + getFileContent(source)); emgr.annotate(ioe, "Class: " + clazz); emgr.annotate(ioe, "Source: " + source); throw ioe; 323 } 324 } 325 } 326 } 327 328 return inst; 329 } 330 331 333 private static String getFileContent(FileObject fo) { 334 try { 335 InputStreamReader isr = new InputStreamReader (fo.getInputStream()); 336 char[] cbuf = new char[1024]; 337 int length; 338 StringBuffer sbuf = new StringBuffer (1024); 339 while (true) { 340 length = isr.read(cbuf); 341 if (length > 0) { 342 sbuf.append(cbuf, 0, length); 343 } else { 344 return sbuf.toString(); 345 } 346 } 347 } catch (Exception ex) { 348 StringWriter sw = new StringWriter (); 349 ex.printStackTrace(new PrintWriter (sw)); 350 return sw.toString(); 351 } 352 } 353 354 355 private Object createFromMethod(String srcClazz, String srcMethod) 356 throws ClassNotFoundException , IOException { 357 int dotIndex = instanceMethod.lastIndexOf('.'); 358 String targetClass; 359 String targetMethod; 360 if (dotIndex > 0) { 361 targetClass = srcMethod.substring(0, dotIndex); 362 targetMethod = srcMethod.substring(dotIndex + 1); 363 } else { 364 targetClass = srcClazz; 365 targetMethod = srcMethod; 366 } 367 368 Class <?> clazz = loadClass(targetClass); 369 370 try { 371 Object instance; 372 try { 373 Method method = clazz.getMethod(targetMethod, new Class []{FileObject.class}); 374 method.setAccessible(true); 375 instance = method.invoke(null, source); 376 } catch (NoSuchMethodException ex) { 377 Method method = clazz.getMethod(targetMethod); 378 method.setAccessible(true); 379 instance = method.invoke(null, new Object [0]); 380 } 381 if (instance == null) { 382 throw new IOException ("Null return not permitted from " + targetClass + "." + targetMethod); } 385 return instance; 386 } catch (Exception ex) { 387 IOException ioe = new IOException ("Error reading " + source + ": " + ex); ErrorManager emgr = ErrorManager.getDefault(); 389 emgr.annotate(ioe, "Class: " + clazz); emgr.annotate(ioe, "Method: " + srcMethod); emgr.annotate(ioe, ex); 392 emgr.annotate(ioe, "Content:\n" + getFileContent(source)); throw ioe; 394 } 395 } 396 397 405 public Class instanceClass() throws java.io.IOException , ClassNotFoundException { 406 if (instanceClass == null) { 407 throw new ClassNotFoundException (source + 408 ": missing 'class' attribute in 'instance' element"); } 410 411 return loadClass(instanceClass); 412 } 413 414 415 private Class loadClass(String clazz) throws ClassNotFoundException { 416 return ((ClassLoader )Lookup.getDefault().lookup(ClassLoader .class)).loadClass(clazz); 417 } 418 419 420 public String instanceName() { 421 if (instanceClass == null) { 422 return ""; } else { 424 return instanceClass; 425 } 426 } 427 428 private int tr(char c) { 429 if (c >= '0' && c <= '9') return c - '0'; 430 if (c >= 'A' && c <= 'F') return c - 'A' + 10; 431 if (c >= 'a' && c <= 'f') return c - 'a' + 10; 432 return -1; 433 } 434 435 438 private void chars2Bytes(OutputStream os, char[] chars, int off, int length) 439 throws IOException { 440 byte rbyte; 441 int read; 442 443 for (int i = off; i < length; ) { 444 read = tr(chars[i++]); 445 if (read >= 0) rbyte = (byte) (read << 4); else continue; 447 448 while (i < length) { 449 read = tr(chars[i++]); 450 if (read >= 0) { 451 rbyte += (byte) read; 452 os.write(rbyte); 453 break; 454 } 455 } 456 } 457 } 458 459 460 public void parse() throws IOException { 461 InputStream in = null; 462 463 try { 464 if (header) { 465 if (err.isLoggable(err.INFORMATIONAL) && source.getSize() < 12000) { 466 byte[] arr = new byte[(int)source.getSize()]; 468 InputStream temp = source.getInputStream(); 469 int len = temp.read(arr); 470 if (len != arr.length) { 471 throw new IOException ("Could not read " + arr.length + " bytes from " + source + " just " + len); } 473 474 err.log("Parsing:" + new String (arr)); 475 476 temp.close(); 477 478 in = new ByteArrayInputStream (arr); 479 } else { 480 in = new BufferedInputStream (source.getInputStream()); 481 } 482 Set <String > iofs = quickParse(new BufferedInputStream (in)); 483 if (iofs != null) { 484 instanceOf = iofs; 485 return; 486 } 487 } 488 } catch (IOException ioe) { 489 } finally { 491 if (in != null) in.close(); 492 } 493 stack = new Stack <String >(); 494 try { 495 in = source.getInputStream(); 496 XMLReader reader = org.openide.xml.XMLUtil.createXMLReader(); 497 reader.setContentHandler(this); 498 reader.setErrorHandler(this); 499 reader.setEntityResolver(this); 500 reader.parse(new org.xml.sax.InputSource (new BufferedInputStream (in))); 501 } catch (SettingsRecognizer.StopSAXException ex) { 502 } catch (SAXException ex) { 504 IOException ioe = new IOException (source.toString()); ErrorManager emgr = ErrorManager.getDefault(); 506 emgr.annotate(ioe, ex); 507 if (ex.getException() != null) { 508 emgr.annotate(ioe, ex.getException()); 509 } 510 emgr.annotate(ioe, "Content: \n" + getFileContent(source)); emgr.annotate(ioe, "Source: " + source); throw ioe; 513 } finally { 514 stack = null; 515 try { 516 if (in != null) { 517 in.close(); 518 } 519 } catch (IOException ex) { 520 } 522 } 523 } 524 525 526 public void parse(Reader source) throws IOException { 527 stack = new Stack <String >(); 528 529 try { 530 XMLReader reader = org.openide.xml.XMLUtil.createXMLReader(); 531 reader.setContentHandler(this); 532 reader.setErrorHandler(this); 533 reader.setEntityResolver(this); 534 reader.parse(new org.xml.sax.InputSource (source)); 535 } catch (SettingsRecognizer.StopSAXException ex) { 536 } catch (SAXException ex) { 538 IOException ioe = new IOException (source.toString()); ErrorManager emgr = ErrorManager.getDefault(); 540 emgr.annotate(ioe, ex); 541 if (ex.getException() != null) { 542 emgr.annotate(ioe, ex.getException()); 543 } 544 throw ioe; 545 } finally { 546 stack = null; 547 } 548 } 549 550 private static final byte[] MODULE_SETTINGS_INTRO = "<?xml version=\"1.0\"?> <!DOCTYPE settings PUBLIC \"-//NetBeans//DTD Session settings 1.0//EN\" \"http://www.netbeans.org/dtds/sessionsettings-1_0.dtd\"> <settings version=\"".getBytes(); private static final byte[] MODULE_SETTINGS_INTRO_END = "> <".getBytes(); private static final byte[] MODULE_SETTINGS_MODULE_NAME = "odule name=\"".getBytes(); private static final byte[] MODULE_SETTINGS_MODULE_SPEC = "spec=\"".getBytes(); private static final byte[] MODULE_SETTINGS_MODULE_IMPL = "impl=\"".getBytes(); private static final byte[] MODULE_SETTINGS_TAG_END = "> <".getBytes(); private static final byte[] MODULE_SETTINGS_INSTANCE = "nstance".getBytes(); private static final byte[] MODULE_SETTINGS_INSTANCE_CLZ = "class=\"".getBytes(); private static final byte[] MODULE_SETTINGS_INSTANCE_MTD = "method=\"".getBytes(); private static final byte[] MODULE_SETTINGS_OF = "f class=\"".getBytes(); private static final byte[] MODULE_SETTINGS_SERIAL = "erialdata class=\"".getBytes(); private static final byte[] MODULE_SETTINGS_END = "settings>".getBytes(); 565 570 private Set <String > quickParse(InputStream is) throws IOException { 571 Set <String > iofs = new HashSet <String >(); 573 if (!expect(is, MODULE_SETTINGS_INTRO)) { 574 err.log("Could not read intro "+source); return null; 576 } 577 version = readTo(is, '"'); 578 if (version == null) { 579 err.log("Could not read version "+source); return null; 581 } 582 if (!expect(is, MODULE_SETTINGS_INTRO_END)) { 583 err.log("Could not read stuff after cnb "+source); return null; 585 } 586 int c; 588 PARSE: 589 while (true) { 590 c = is.read(); 591 switch (c) { 592 case 'm': 593 if (!expect(is, MODULE_SETTINGS_MODULE_NAME)) { 595 err.log("Could not read up to <module name=\" "+source); return null; 597 } 598 String codeName = readTo(is, '"'); 599 if (codeName == null) { 600 err.log("Could not read module name value "+source); return null; 602 } 603 codeName = codeName.intern(); 604 resolveModuleElm(codeName); 605 c = is.read(); 606 if (c == '/') { 607 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 608 err.log("Could not read up to end of module tag "+source); return null; 610 } 611 break; 612 } else if (c != ' ') { 613 err.log("Could not space after module name "+source); return null; 615 } 616 if (!expect(is, MODULE_SETTINGS_MODULE_SPEC)) { 618 err.log("Could not read up to spec=\" "+source); return null; 620 } 621 String mspec = readTo(is, '"'); 622 if (mspec == null) { 623 err.log("Could not read module spec value "+source); return null; 625 } 626 try { 627 } catch (NumberFormatException nfe) { 629 return null; 630 } 631 c = is.read(); 632 if (c == '/') { 633 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 634 err.log("Could not read up to end of <module name spec/> tag "+source); return null; 636 } 637 break; 638 } else if (c != ' ') { 639 err.log("Could not read space after module name "+source); return null; 641 } 642 if (!expect(is, MODULE_SETTINGS_MODULE_IMPL)) { 644 err.log("Could not read up to impl=\" "+source); return null; 646 } 647 moduleImpl = readTo(is, '"'); 648 if (moduleImpl == null) { 649 err.log("Could not read module impl value "+source); return null; 651 } 652 moduleImpl = moduleImpl.intern(); 653 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 655 err.log("Could not read up to /> < "+source); return null; 657 } 658 break; 659 case 'i': 660 if (!expect(is, MODULE_SETTINGS_INSTANCE)) { 662 err.log("Could not read up to instance "+source); return null; 664 } 665 c = is.read(); 667 if (c == 'o') { 668 if (!expect(is, MODULE_SETTINGS_OF)) { 669 err.log("Could not read up to instance"); return null; 671 } 672 String iof = readTo(is, '"'); 673 if (iof == null) { 674 err.log("Could not read instanceof value "+source); return null; 676 } 677 iof = org.openide.util.Utilities.translate(iof).intern(); 678 iofs.add(iof); 679 if (is.read() != '/') { 680 err.log("No / at end of <instanceof> " + iof+" "+source); return null; 682 } 683 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 684 err.log("Could not read up to next tag after <instanceof> " + iof+" "+source); return null; 686 } 687 } else if (c == ' ') { 688 if (!expect(is, MODULE_SETTINGS_INSTANCE_CLZ)) { 690 err.log("Could not read up to class=\" "+source); return null; 692 } 693 instanceClass = readTo(is, '"'); 694 if (instanceClass == null) { 695 err.log("Could not read instance class value "+source); return null; 697 } 698 instanceClass = org.openide.util.Utilities.translate(instanceClass).intern(); 699 c = is.read(); 700 if (c == '/') { 701 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 702 err.log("Could not read up to end of instance tag "+source); return null; 704 } 705 break; 706 } else if (c != ' ') { 707 err.log("Could not space after instance class "+source); return null; 709 } 710 if (!expect(is, MODULE_SETTINGS_INSTANCE_MTD)) { 712 err.log("Could not read up to method=\" "+source); return null; 714 } 715 instanceMethod = readTo(is, '"'); 716 if (instanceMethod == null) { 717 err.log("Could not read method value "+source); return null; 719 } 720 instanceMethod = instanceMethod.intern(); 721 c = is.read(); 722 if (c == '/') { 723 if (!expect(is, MODULE_SETTINGS_TAG_END)) { 724 err.log("Could not read up to end of instance tag "+source); return null; 726 } 727 break; 728 } 729 err.log("Strange stuff after method attribute "+source); return null; 731 } else { 732 err.log("Could not read after to instance "+source); return null; 734 } 735 break; 736 case 's': 737 if (!expect(is, MODULE_SETTINGS_SERIAL)) { 739 err.log("Could not read up to <serialdata class=\" "+source); return null; 741 } 742 instanceClass = readTo(is, '"'); 743 if (instanceClass == null) { 744 err.log("Could not read serialdata class value "+source); return null; 746 } 747 instanceClass = org.openide.util.Utilities.translate(instanceClass).intern(); 748 c = is.read(); 750 if (c != '>') { 751 err.log("Could not read up to end of serialdata tag "+source); return null; 753 } 754 break PARSE; 755 case '/': 756 if (!expect(is, MODULE_SETTINGS_END)) { 759 err.log("Could not read up to end of settings tag "+source); return null; 761 } 762 break PARSE; 763 default: 764 err.log("Strange stuff after <" + (char)c+" "+source); return null; 766 } 767 } 768 if (instanceClass != null && !iofs.isEmpty()) { 769 return iofs; 770 } 771 return null; 772 } 773 774 778 private boolean expect(InputStream is, byte[] stuff) throws IOException { 779 int len = stuff.length; 780 boolean inWhitespace = false; 781 for (int i = 0; i < len; ) { 782 int c = is.read(); 783 if (c == 10 || c == 13 || c == ' ' || c == '\t') { 784 if (inWhitespace) { 786 continue; 787 } else { 788 inWhitespace = true; 789 c = ' '; 790 } 791 } else { 792 inWhitespace = false; 793 } 794 if (c != stuff[i++]) { 795 return false; 796 } 797 } 798 if (stuff[len - 1] == 10) { 799 if (!is.markSupported()) throw new IOException ("Mark not supported"); is.mark(1); 803 int c = is.read(); 804 if (c != -1 && c != 10 && c != 13) { 805 is.reset(); 807 } 808 } 809 return true; 810 } 811 816 private String readTo(InputStream is, char delim) throws IOException { 817 if (delim == 10) { 818 throw new IOException ("Not implemented"); } 822 CharArrayWriter caw = new CharArrayWriter (100); 823 boolean inNewline = false; 824 while (true) { 825 int c = is.read(); 826 if (c == -1) return null; 827 if (c > 126) return null; 828 if (c == 10 || c == 13) { 829 if (inNewline) { 831 continue; 832 } else { 833 inNewline = true; 834 c = 10; 835 } 836 } else if (c < 32 && c != 9) { 837 return null; 839 } else { 840 inNewline = false; 841 } 842 if (c == delim) { 843 return caw.toString(); 844 } else { 845 caw.write(c); 846 } 847 } 848 } 849 850 final static class StopSAXException extends SAXException { 851 public StopSAXException() { 852 super("Parser stopped"); } 854 } 855 856 } | Popular Tags |