1 19 20 package org.netbeans.core.startup; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.BufferedInputStream ; 25 import java.io.ByteArrayInputStream ; 26 import java.io.ByteArrayOutputStream ; 27 import java.io.CharArrayWriter ; 28 import java.io.File ; 29 import java.io.FileNotFoundException ; 30 import java.io.IOException ; 31 import java.io.InputStream ; 32 import java.io.ObjectOutput ; 33 import java.io.OutputStream ; 34 import java.io.OutputStreamWriter ; 35 import java.io.Writer ; 36 import java.util.Arrays ; 37 import java.util.Collections ; 38 import java.util.HashMap ; 39 import java.util.HashSet ; 40 import java.util.Iterator ; 41 import java.util.List ; 42 import java.util.Map ; 43 import java.util.Set ; 44 import java.util.TreeMap ; 45 import java.util.logging.Level ; 46 import org.netbeans.DuplicateException; 47 import org.netbeans.Events; 48 import org.netbeans.InvalidException; 49 import org.netbeans.Module; 50 import org.netbeans.ModuleManager; 51 import org.netbeans.Util; 52 import org.openide.filesystems.FileAttributeEvent; 53 import org.openide.filesystems.FileChangeListener; 54 import org.openide.filesystems.FileEvent; 55 import org.openide.filesystems.FileLock; 56 import org.openide.filesystems.FileObject; 57 import org.openide.filesystems.FileRenameEvent; 58 import org.openide.filesystems.FileSystem; 59 import org.openide.filesystems.FileUtil; 60 import org.openide.modules.Dependency; 61 import org.openide.modules.InstalledFileLocator; 62 import org.openide.modules.ModuleInstall; 63 import org.openide.modules.SpecificationVersion; 64 import org.openide.util.RequestProcessor; 65 import org.openide.util.Utilities; 66 import org.openide.util.WeakSet; 67 import org.openide.util.io.NbObjectInputStream; 68 import org.openide.util.io.NbObjectOutputStream; 69 import org.openide.xml.EntityCatalog; 70 import org.openide.xml.XMLUtil; 71 import org.xml.sax.Attributes ; 72 import org.xml.sax.EntityResolver ; 73 import org.xml.sax.ErrorHandler ; 74 import org.xml.sax.InputSource ; 75 import org.xml.sax.SAXException ; 76 import org.xml.sax.SAXParseException ; 77 import org.xml.sax.XMLReader ; 78 import org.xml.sax.helpers.DefaultHandler ; 79 80 86 final class ModuleList { 87 88 89 public static final String PUBLIC_ID = "-//NetBeans//DTD Module Status 1.0//EN"; public static final String SYSTEM_ID = "http://www.netbeans.org/dtds/module-status-1_0.dtd"; 92 95 private static final boolean VALIDATE_XML = true; 96 97 98 private final ModuleManager mgr; 99 100 private final FileObject folder; 101 102 private final Events ev; 103 104 private final Map <String ,DiskStatus> statuses = new HashMap <String ,DiskStatus>(100); 105 106 private boolean triggered = false; 107 108 private final Listener listener = new Listener (); 109 110 private final Map <String ,byte[]> compatibilitySers = new HashMap <String ,byte[]>(100); 111 112 private final Set <FileSystem.AtomicAction> myAtomicActions = Collections.<FileSystem.AtomicAction>synchronizedSet(new WeakSet<FileSystem.AtomicAction>(100)); 113 114 119 public ModuleList(ModuleManager mgr, FileObject folder, Events ev) { 120 this.mgr = mgr; 121 this.folder = folder; 122 this.ev = ev; 123 Util.err.fine("ModuleList created, storage in " + folder); 124 } 125 126 134 public Set readInitial() { 135 ev.log(Events.START_READ); 136 final Set <Module> read = new HashSet <Module>(); 137 try { 138 folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 139 public void run() throws IOException { 140 FileObject[] children = folder.getChildren(); 141 ev.log( Events.MODULES_FILE_SCANNED, children.length ); 142 143 XMLReader reader = null; 144 145 for (int i = 0; i < children.length; i++) { 146 if (children[i].hasExt("ser")) { } else if (children[i].hasExt("xml")) { try { 151 String nameDashes = children[i].getName(); char[] badChars = {'.', '/', '>', '='}; 153 for (int j = 0; j < 4; j++) { 154 if (nameDashes.indexOf(badChars[j]) != -1) { 155 throw new IllegalArgumentException ("Bad name: " + nameDashes); } 157 } 158 String name = nameDashes.replace('-', '.').intern(); Dependency.create(Dependency.TYPE_MODULE, name); 162 163 Map <String ,Object > props; 165 InputStream is = children[i].getInputStream(); 166 try { 167 props = readStatus(new BufferedInputStream (is)); 168 if (props == null) { 169 Util.err.warning("Note - failed to parse " + children[i] + " the quick way, falling back on XMLReader"); 170 is.close(); 171 is = children[i].getInputStream(); 172 InputSource src = new InputSource (is); 173 src.setSystemId(children[i].getURL().toExternalForm()); 175 if (reader == null) { 176 try { 177 reader = XMLUtil.createXMLReader(); 178 } catch(SAXException e) { 179 throw (IllegalStateException ) new IllegalStateException (e.toString()).initCause(e); 180 } 181 reader.setEntityResolver(listener); 182 reader.setErrorHandler(listener); 183 } 184 props = readStatus(src,reader); 185 } 186 } finally { 187 is.close(); 188 } 189 if (! name.equals(props.get("name"))) throw new IOException ("Code name mismatch: " + name + " vs. " + props.get("name")); String jar = (String )props.get("jar"); File jarFile; 192 try { 193 jarFile = findJarByName(jar, name); 194 } catch (FileNotFoundException fnfe) { 195 ev.log(Events.MISSING_JAR_FILE, new File (fnfe.getMessage())); 197 try { 198 children[i].delete(); 199 } catch (IOException ioe) { 200 Util.err.log(Level.WARNING, null, ioe); 201 } 202 continue; 203 } 204 205 ModuleHistory history = new ModuleHistory(jar); Integer prevReleaseI = (Integer )props.get("release"); int prevRelease = (prevReleaseI == null ? -1 : prevReleaseI.intValue()); 208 SpecificationVersion prevSpec = (SpecificationVersion)props.get("specversion"); history.upgrade(prevRelease, prevSpec); 210 Boolean reloadableB = (Boolean )props.get("reloadable"); boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); 212 Boolean enabledB = (Boolean )props.get("enabled"); boolean enabled = (enabledB != null ? enabledB.booleanValue() : false); 214 Boolean autoloadB = (Boolean )props.get("autoload"); boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); 216 Boolean eagerB = (Boolean )props.get("eager"); boolean eager = (eagerB != null ? eagerB.booleanValue() : false); 218 String installer = (String )props.get("installer"); if (installer != null) { 220 if (! installer.equals(nameDashes + ".ser")) throw new IOException ("Incorrect installer ser name: " + installer); FileObject installerSer = folder.getFileObject(nameDashes, "ser"); if (installerSer == null) throw new IOException ("No such install ser: " + installer + "; I see only: " + Arrays.asList(children)); byte[] buf = new byte[(int)installerSer.getSize()]; 226 InputStream is2 = installerSer.getInputStream(); 227 try { 228 is2.read(buf); 229 } finally { 230 is2.close(); 231 } 232 history.setInstallerState(buf); 233 props.put("installerState", buf); } 236 Module m = mgr.create(jarFile, history, reloadable, autoload, eager); 237 read.add(m); 238 DiskStatus status = new DiskStatus(); 239 status.module = m; 240 status.file = children[i]; 241 status.pendingInstall = enabled; 243 status.diskProps = props; 247 statuses.put(name, status); 248 } catch (Exception e) { 249 Util.err.log(Level.WARNING, "Error encountered while reading " + children[i], e); 250 } 251 } else { 252 Util.err.fine("Strange file encountered in modules folder: " + children[i]); 253 } 254 ev.log( Events.MODULES_FILE_PROCESSED, children[i] ); 255 } 256 if (Util.err.isLoggable(Level.FINE)) { 257 Util.err.fine("read initial XML files: statuses=" + statuses); 258 } 259 ev.log(Events.FINISH_READ, read); 260 folder.addFileChangeListener(FileUtil.weakFileChangeListener (listener, folder)); 262 }}); 263 } catch (IOException ioe) { 264 Util.err.log(Level.WARNING, null, ioe); 265 } 266 return read; 267 } 268 269 277 private File findJarByName(String jar, String name) throws IOException { 278 File f = new File (jar); 279 if (f.isAbsolute()) { 280 if (!f.isFile()) throw new FileNotFoundException (f.getAbsolutePath()); 281 return f; 282 } else { 283 f = InstalledFileLocator.getDefault().locate(jar, name, false); 284 if (f != null) { 285 return f; 286 } else { 287 throw new FileNotFoundException (jar); 288 } 289 } 290 } 291 292 299 public void trigger(Set <Module> boot) { 300 ev.log(Events.PERF_START, "ModuleList.trigger"); if (triggered) throw new IllegalStateException ("Duplicate call to trigger()"); Set <Module> maybeEnable = new HashSet <Module>(boot); 303 for (DiskStatus status: statuses.values()) { 304 if (status.pendingInstall) { 305 status.pendingInstall = false; 307 Module m = status.module; 308 if (m.isEnabled() || m.isAutoload() || m.isEager()) throw new IllegalStateException (); 309 maybeEnable.add(m); 310 } 311 } 312 ev.log(Events.PERF_TICK, "modules to enable prepared"); 314 if (! maybeEnable.isEmpty()) { 315 ev.log(Events.START_AUTO_RESTORE, maybeEnable); 316 installNew(maybeEnable); 317 ev.log(Events.FINISH_AUTO_RESTORE, maybeEnable); 318 } 319 Util.err.fine("ModuleList.trigger: enabled new modules, flushing changes..."); 320 triggered = true; 321 flushInitial(); 322 ev.log(Events.PERF_END, "ModuleList.trigger"); } 324 private void installNew(Set <Module> modules) { 326 if (modules.isEmpty()) { 327 return; 328 } 329 ev.log(Events.PERF_START, "ModuleList.installNew"); Iterator <Module> it = modules.iterator(); 332 while (it.hasNext()) { 333 Module m = it.next(); 334 if (m.isAutoload() || m.isEager()) { 335 it.remove(); 336 } else if (m.isEnabled()) { 337 Util.err.fine("#17295 fix active for " + m.getCodeNameBase()); 344 it.remove(); 345 } else if (!m.isValid()) { 346 Util.err.fine("#17471 fix active for " + m.getCodeNameBase()); 351 it.remove(); 352 } 353 } 354 List <Module> toEnable = mgr.simulateEnable(modules); 355 for (Module m: toEnable) { 356 if (m.isAutoload() || m.isEager()) { 357 continue; 358 } 359 if (! modules.contains(m)) { 361 modules.add(m); 362 } 363 } 364 Set <Module> missing = new HashSet <Module>(modules); 365 missing.removeAll(toEnable); 366 if (! missing.isEmpty()) { 367 Util.transitiveClosureModuleDependencies(mgr, missing); 369 it = missing.iterator(); 370 while (it.hasNext()) { 371 Module m = it.next(); 372 if (m.getProblems().isEmpty()) { 373 it.remove(); 374 } 375 } 376 ev.log(Events.FAILED_INSTALL_NEW, missing); 377 modules.removeAll(missing); 378 } 379 try { 380 mgr.enable(modules); 381 } catch (InvalidException ie) { 382 Util.err.log(Level.WARNING, null, ie); 383 Module bad = ie.getModule(); 384 if (bad == null) throw new IllegalStateException (); 385 ev.log(Events.FAILED_INSTALL_NEW_UNEXPECTED, bad, ie); 386 modules.remove(bad); 387 installNew(modules); 390 } 391 ev.log(Events.PERF_END, "ModuleList.installNew"); } 393 394 412 void installPrepare(Module m, ModuleInstall inst) { 413 if (! (m.getHistory() instanceof ModuleHistory)) { 414 Util.err.fine(m + " had strange history " + m.getHistory() + ", ignoring..."); 415 return; 416 } 417 ModuleHistory hist = (ModuleHistory)m.getHistory(); 418 byte[] compatSer = compatibilitySers.get(inst.getClass().getName()); 420 if (compatSer != null) { 421 Util.err.fine("Had some old-style state for " + m); 422 if (isReallyExternalizable(inst.getClass())) { 423 try { 427 ByteArrayOutputStream baos = new ByteArrayOutputStream (1000); 428 new NbObjectOutputStream(baos).writeObject(inst); 429 baos.close(); 430 if (Utilities.compareObjects(compatSer, baos.toByteArray())) { 431 Util.err.fine("Old-style state for " + m + " was gratuitous"); 432 } else { 434 Util.err.fine("Old-style state for " + m + " was useful, loading it..."); 435 hist.setInstallerState(new byte[0]); 439 InputStream is = new ByteArrayInputStream (compatSer); 441 Object o = new NbObjectInputStream(is).readObject(); 442 if (o != inst) throw new ClassCastException ("Stored " + o + " but expecting " + inst); } 444 } catch (Exception e) { 445 Util.err.log(Level.WARNING, null, e); 446 hist.setInstallerState(new byte[0]); 448 } catch (LinkageError le) { 449 Util.err.log(Level.WARNING, null, le); 450 hist.setInstallerState(new byte[0]); 452 } 453 } else { 454 Util.err.fine(m + " did not want to store install state"); 455 } 457 } else if (hist.getInstallerState() != null) { 458 Util.err.fine("Loading install state for " + m); 460 try { 461 InputStream is = new ByteArrayInputStream (hist.getInstallerState()); 462 Object o = new NbObjectInputStream(is).readObject(); 471 if (o != inst) throw new ClassCastException ("Stored " + o + " but expecting " + inst); } catch (Exception e) { 477 Util.err.log(Level.WARNING, null, e); 479 } catch (LinkageError le) { 482 Util.err.log(Level.WARNING, null, le); 483 } 484 } else { 485 if (isReallyExternalizable(inst.getClass())) { 488 Util.err.fine("Checking pre-install state of " + m); 489 Util.err.warning("Warning: use of writeExternal (or writeReplace) in " + inst.getClass().getName() + " is deprecated; use normal settings instead"); 490 try { 491 ByteArrayOutputStream baos = new ByteArrayOutputStream (1000); 492 new NbObjectOutputStream(baos).writeObject(inst); 493 baos.close(); 494 hist.setInstallerState(baos.toByteArray()); 499 } catch (Exception e) { 500 Util.err.log(Level.WARNING, null, e); 501 hist.setInstallerState(new byte[0]); 503 } catch (LinkageError le) { 504 Util.err.log(Level.WARNING, null, le); 505 hist.setInstallerState(new byte[0]); 506 } 507 } else { 508 Util.err.fine(m + " did not want to store install state"); 511 } 512 } 513 } 514 517 private static boolean isReallyExternalizable(Class clazz) { 518 Class <?> c; 519 for (c = clazz; c != ModuleInstall.class && c != Object .class; c = c.getSuperclass()) { 520 try { 521 c.getDeclaredMethod("writeExternal", ObjectOutput .class); return true; 526 } catch (NoSuchMethodException nsme) { 527 } 529 try { 530 c.getDeclaredMethod("writeReplace"); return true; 534 } catch (NoSuchMethodException nsme) { 535 } 537 } 538 if (c == Object .class) throw new IllegalArgumentException ("Class " + clazz + " was not a ModuleInstall"); return false; 542 } 543 544 551 void installPostpare(Module m, ModuleInstall inst) { 552 if (! (m.getHistory() instanceof ModuleHistory)) { 553 Util.err.fine(m + " had strange history " + m.getHistory() + ", ignoring..."); 554 return; 555 } 556 ModuleHistory hist = (ModuleHistory)m.getHistory(); 557 if (hist.getInstallerState() != null) { 558 try { 559 ByteArrayOutputStream baos = new ByteArrayOutputStream (1000); 560 new NbObjectOutputStream(baos).writeObject(inst); 561 baos.close(); 562 byte[] old = hist.getInstallerState(); 563 byte[] nue = baos.toByteArray(); 564 if (Utilities.compareObjects(old, nue)) { 565 Util.err.fine(m + " did not change installer state (" + old.length + " bytes), not writing anything"); 567 } else { 568 Util.err.fine(m + " changed installer state after loading"); 570 hist.setInstallerState(nue); 571 } 572 } catch (Exception e) { 573 Util.err.log(Level.WARNING, null, e); 574 } catch (LinkageError le) { 577 Util.err.log(Level.WARNING, null, le); 578 } 579 } else { 580 Util.err.fine(m + " has no saved state"); 582 } 583 } 584 585 595 private Map <String ,Object > readStatus(InputSource is, XMLReader reader) throws IOException , SAXException { 596 if (reader == null) { 597 reader = XMLUtil.createXMLReader(VALIDATE_XML); 598 reader.setEntityResolver(listener); 599 reader.setErrorHandler(listener); 600 } 601 final Map <String ,Object > m = new HashMap <String ,Object >(); 602 603 DefaultHandler handler = new DefaultHandler () { 604 private String modName; 605 private String paramName; 606 private StringBuffer data = new StringBuffer (); 607 608 public void startElement(String uri, 609 String localname, 610 String qname, 611 Attributes attrs) throws SAXException { 612 if ("module".equals(qname) ) { modName = attrs.getValue("name"); if( modName == null ) 615 throw new SAXException ("No module name"); m.put("name", modName.intern()); } 618 else if (modName != null && "param".equals(qname)) { paramName = attrs.getValue("name"); 620 if( paramName == null ) { 621 throw new SAXException ("No param name"); } 623 paramName = paramName.intern(); 624 data.setLength(0); 625 } 626 } 627 628 public void characters(char[] ch, int start, int len) { 629 if(modName != null && paramName != null) 630 data.append( ch, start, len ); 631 } 632 633 public void endElement (String uri, String localname, String qname) 634 throws SAXException 635 { 636 if ("param".equals(qname)) { if (modName != null && paramName != null) { 638 if (data.length() == 0) 639 throw new SAXException ("No text contents in " + paramName + " of " + modName); 641 try { 642 m.put(paramName, processStatusParam(paramName, data.toString())); 643 } catch (NumberFormatException nfe) { 644 throw (SAXException ) new SAXException (nfe.toString()).initCause(nfe); 646 } 647 648 data.setLength(0); 649 paramName = null; 650 } 651 } 652 else if ("module".equals(qname)) { modName = null; 654 } 655 } 656 }; 657 658 reader.setContentHandler(handler); 659 reader.parse(is); 660 661 sanityCheckStatus(m); 662 663 return m; 664 } 665 666 671 private Object processStatusParam(String k, String v) throws NumberFormatException { 672 if (k == "release") { return new Integer (v); 674 } else if (k == "enabled" || k == "autoload" || k == "eager" || k == "reloadable" ) { 679 return Boolean.valueOf(v); 680 } else if (k == "specversion") { return new SpecificationVersion(v); 682 } else { 683 if (v.length() < 100) v = v.intern(); 686 return v; 687 } 688 } 689 690 692 private void sanityCheckStatus(Map <String ,Object > m) throws IOException { 693 if (m.get("jar") == null) throw new IOException ("Must define jar param"); if (m.get("autoload") != null && ((Boolean )m.get("autoload")).booleanValue() && m.get("enabled") != null) throw new IOException ("Autoloads cannot specify enablement"); if (m.get("eager") != null && ((Boolean )m.get("eager")).booleanValue() && m.get("enabled") != null) throw new IOException ("Eager modules cannot specify enablement"); String origin = (String )m.remove("origin"); if (origin != null) { 706 String jar = (String )m.get("jar"); String newjar; 708 if (origin.equals("user") || origin.equals("installation")) { newjar = "modules/" + jar; } else if (origin.equals("user/autoload") || origin.equals("installation/autoload")) { newjar = "modules/autoload/" + jar; } else if (origin.equals("user/eager") || origin.equals("installation/eager")) { newjar = "modules/eager/" + jar; } else if (origin.equals("adhoc")) { newjar = jar; 716 } else { 717 throw new IOException ("Unrecognized origin " + origin + " for " + jar); } 719 Util.err.warning("Upgrading 'jar' param from " + jar + " to " + newjar + " and removing 'origin' " + origin); 720 m.put("jar", newjar); } 722 } 723 724 private static final byte[] MODULE_XML_INTRO = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Module Status 1.0//EN\"\n \"http://www.netbeans.org/dtds/module-status-1_0.dtd\">\n<module name=\"".getBytes(); private static final byte[] MODULE_XML_INTRO_END = ">\n".getBytes(); private static final byte[] MODULE_XML_DIV2 = " <param name=\"".getBytes(); private static final byte[] MODULE_XML_DIV3 = "/param>\n".getBytes(); private static final byte[] MODULE_XML_END = "/module>\n".getBytes(); 737 private Map <String , Object > readStatus(InputStream is) throws IOException { 738 Map <String ,Object > m = new HashMap <String ,Object >(15); 739 if (!expect(is, MODULE_XML_INTRO)) { 740 Util.err.fine("Could not read intro"); 741 return null; 742 } 743 String name = readTo(is, '"'); 744 if (name == null) { 745 Util.err.fine("Could not read code name base"); 746 return null; 747 } 748 m.put("name", name.intern()); if (!expect(is, MODULE_XML_INTRO_END)) { 750 Util.err.fine("Could not read stuff after cnb"); 751 return null; 752 } 753 PARSE: 755 while (true) { 756 int c = is.read(); 757 switch (c) { 758 case ' ': 759 if (!expect(is, MODULE_XML_DIV2)) { 761 Util.err.fine("Could not read up to param"); 762 return null; 763 } 764 String k = readTo(is, '"'); 765 if (k == null) { 766 Util.err.fine("Could not read param"); 767 return null; 768 } 769 k = k.intern(); 770 if (is.read() != '>') { 771 Util.err.fine("No > at end of <param> " + k); 772 return null; 773 } 774 String v = readTo(is, '<'); 775 if (v == null) { 776 Util.err.fine("Could not read value of " + k); 777 return null; 778 } 779 if (!expect(is, MODULE_XML_DIV3)) { 780 Util.err.fine("Could not read end of param " + k); 781 return null; 782 } 783 try { 784 m.put(k, processStatusParam(k, v)); 785 } catch (NumberFormatException nfe) { 786 Util.err.fine("Number misparse: " + nfe); 787 return null; 788 } 789 break; 790 case '<': 791 if (!expect(is, MODULE_XML_END)) { 793 Util.err.fine("Strange ending"); 794 return null; 795 } 796 if (is.read() != -1) { 797 Util.err.fine("Trailing garbage"); 798 return null; 799 } 800 break PARSE; 802 default: 803 Util.err.fine("Strange stuff after <param>s: " + c); 804 return null; 805 } 806 } 807 sanityCheckStatus(m); 808 return m; 809 } 810 811 815 private boolean expect(InputStream is, byte[] stuff) throws IOException { 816 int len = stuff.length; 817 boolean inNewline = false; 818 for (int i = 0; i < len; ) { 819 int c = is.read(); 820 if (c == 10 || c == 13) { 821 if (inNewline) { 823 continue; 824 } else { 825 inNewline = true; 826 c = 10; 827 } 828 } else { 829 inNewline = false; 830 } 831 if (c != stuff[i++]) { 832 return false; 833 } 834 } 835 if (stuff[len - 1] == 10) { 836 if (!is.markSupported()) throw new IOException ("Mark not supported"); is.mark(1); 840 int c = is.read(); 841 if (c != -1 && c != 10 && c != 13) { 842 is.reset(); 844 } 845 } 846 return true; 847 } 848 853 private String readTo(InputStream is, char delim) throws IOException { 854 if (delim == 10) { 855 throw new IOException ("Not implemented"); } 859 CharArrayWriter caw = new CharArrayWriter (100); 860 boolean inNewline = false; 861 while (true) { 862 int c = is.read(); 863 if (c == -1) return null; 864 if (c > 126) return null; 865 if (c == 10 || c == 13) { 866 if (inNewline) { 868 continue; 869 } else { 870 inNewline = true; 871 c = 10; 872 } 873 } else if (c < 32 && c != 9) { 874 return null; 876 } else { 877 inNewline = false; 878 } 879 if (c == delim) { 880 return caw.toString(); 881 } else { 882 caw.write(c); 883 } 884 } 885 } 886 887 891 private void writeStatus(Map <String , Object > m, OutputStream os) throws IOException { 892 String codeName = (String )m.get("name"); if (codeName == null) 894 throw new IllegalArgumentException ("no code name present"); 896 Writer w = new OutputStreamWriter (os, "UTF-8"); w.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); w.write("<!DOCTYPE module PUBLIC \""); w.write(PUBLIC_ID); 900 w.write("\"\n \""); w.write(SYSTEM_ID); 902 w.write("\">\n"); w.write("<module name=\""); w.write(XMLUtil.toAttributeValue(codeName)); w.write("\">\n"); 907 for (Map.Entry <String , Object > entry: new TreeMap <String , Object >(m).entrySet()) { 910 String name = entry.getKey(); 911 if (name.equals("installerState") || name.equals("name")) { continue; 914 } 915 916 Object val = entry.getValue(); 917 918 w.write(" <param name=\""); w.write(XMLUtil.toAttributeValue(name)); w.write("\">"); w.write(XMLUtil.toElementContent(val.toString())); 922 w.write("</param>\n"); } 924 925 w.write("</module>\n"); w.flush(); 927 } 928 929 937 private DiskStatus writeOut(Module m, DiskStatus old) throws IOException { 938 final DiskStatus nue; 939 if (old == null) { 940 nue = new DiskStatus(); 941 nue.module = m; 942 nue.diskProps = computeProperties(m); 943 } else { 944 nue = old; 945 } 946 FileSystem.AtomicAction aa = new FileSystem.AtomicAction() { 947 public void run() throws IOException { 948 if (nue.file == null) { 949 nue.file = folder.createData(((String )nue.diskProps.get("name")).replace('.', '-'), "xml"); } else { 951 if (nue.dirty) { 953 throw new IOException ("Will not clobber external changes in " + nue.file); } 957 } 958 Util.err.fine("ModuleList: (re)writing " + nue.file); 959 FileLock lock = nue.file.lock(); 960 try { 961 OutputStream os = nue.file.getOutputStream(lock); 962 try { 963 writeStatus(nue.diskProps, os); 964 } finally { 965 os.close(); 966 } 967 } finally { 968 lock.releaseLock(); 969 } 970 byte[] data = (byte[])nue.diskProps.get("installerState"); if (data != null) { 974 String installerName = (String )nue.diskProps.get("installer"); FileObject ser = folder.getFileObject(installerName); 976 if (ser == null) { 977 int idx = installerName.lastIndexOf('.'); ser = folder.createData(installerName.substring(0, idx), installerName.substring(idx + 1)); 980 } 981 lock = ser.lock(); 983 try { 984 OutputStream os = ser.getOutputStream(lock); 985 try { 986 os.write(data); 987 } finally { 988 os.close(); 989 } 990 } finally { 991 lock.releaseLock(); 992 } 993 } else { 994 1000 } 1001 } 1002 }; 1003 myAtomicActions.add(aa); 1004 folder.getFileSystem().runAtomicAction(aa); 1005 return nue; 1006 } 1007 1008 1010 private void deleteFromDisk(final Module m, final DiskStatus status) throws IOException { 1011 final String nameDashes = m.getCodeNameBase().replace('.', '-'); FileSystem.AtomicAction aa = new FileSystem.AtomicAction() { 1014 public void run() throws IOException { 1015 FileObject xml = folder.getFileObject(nameDashes, "xml"); if (xml == null) { 1017 Util.err.fine("ModuleList: " + m + "'s XML already gone from disk"); 1019 return; 1020 } 1021 if (status.dirty) { 1023 throw new IOException ("Unapproved external change to " + xml); } 1027 Util.err.fine("ModuleList: deleting " + xml); 1028 1034 xml.delete(); 1035 FileObject ser = folder.getFileObject(nameDashes, "ser"); if (ser != null) { 1037 Util.err.fine("(and also " + ser + ")"); 1038 ser.delete(); 1039 } 1040 } 1041 }; 1042 myAtomicActions.add(aa); 1043 folder.getFileSystem().runAtomicAction(aa); 1044 } 1045 1046 1067 private void flushInitial() { 1068 Util.err.fine("Flushing initial module list..."); 1069 Iterator it = mgr.getModules().iterator(); 1072 while (it.hasNext()) { 1073 Module m = (Module)it.next(); 1074 DiskStatus status = statuses.get(m.getCodeNameBase()); 1075 if (status != null) { 1076 moduleChanged(m, status); 1077 m.addPropertyChangeListener(listener); 1078 } 1079 } 1080 moduleListChanged(); 1082 mgr.addPropertyChangeListener(listener); 1084 } 1085 1086 1093 private void moduleListChanged() { 1094 synchronized (statuses) { 1095 if (Util.err.isLoggable(Level.FINE)) { 1096 Util.err.fine("ModuleList: moduleListChanged; statuses=" + statuses); 1097 } 1098 for (Module m : mgr.getModules()) { 1100 if (m.isFixed() || m.getAllJars().isEmpty()) { 1101 continue; 1103 } 1104 final String name = m.getCodeNameBase(); 1105 if (statuses.get(name) == null) { 1106 Util.err.fine("moduleListChanged: added: " + m); 1108 try { 1109 statuses.put(name, writeOut(m, null)); 1110 m.addPropertyChangeListener(listener); 1111 } catch (IOException ioe) { 1112 Util.err.log(Level.WARNING, null, ioe); 1113 } 1115 } 1116 } 1117 Iterator <DiskStatus> it = statuses.values().iterator(); 1119 while (it.hasNext()) { 1120 DiskStatus status = it.next(); 1121 if (! status.module.isValid()) { 1122 status.module.removePropertyChangeListener(listener); 1123 Module nue = mgr.get(status.module.getCodeNameBase()); 1124 if (nue != null) { 1125 Util.err.fine("moduleListChanged: recreated: " + nue); 1129 nue.addPropertyChangeListener(listener); 1130 status.module = nue; 1131 moduleChanged(nue, status); 1132 } else { 1133 Util.err.fine("moduleListChanged: deleted: " + status.module); 1135 it.remove(); 1136 try { 1137 deleteFromDisk(status.module, status); 1138 } catch (IOException ioe) { 1139 Util.err.log(Level.WARNING, null, ioe); 1140 } 1141 } 1142 } 1143 } 1144 } 1145 } 1146 1147 1153 private void moduleChanged(Module m, DiskStatus status) { 1154 synchronized (status) { 1155 if (Util.err.isLoggable(Level.FINE)) { 1156 Util.err.fine("ModuleList: moduleChanged: " + m); 1157 } 1158 Map <String ,Object > newProps = computeProperties(m); 1159 if (! Utilities.compareObjects(status.diskProps, newProps)) { 1160 if (Util.err.isLoggable(Level.FINE)) { 1161 Set <Map.Entry <String ,Object >> changes = new HashSet <Map.Entry <String ,Object >>(newProps.entrySet()); 1162 changes.removeAll(status.diskProps.entrySet()); 1163 Util.err.fine("ModuleList: changes are " + changes); 1164 } 1165 status.diskProps = newProps; 1167 try { 1168 writeOut(m, status); 1169 } catch (IOException ioe) { 1170 Util.err.log(Level.WARNING, null, ioe); 1171 } 1173 } 1174 } 1175 } 1176 1177 1184 private Map <String ,Object > computeProperties(Module m) { 1185 if (m.isFixed() || ! m.isValid()) throw new IllegalArgumentException ("fixed or invalid: " + m); if (! (m.getHistory() instanceof ModuleHistory)) throw new IllegalArgumentException ("weird history: " + m); Map <String ,Object > p = new HashMap <String ,Object >(); 1188 p.put("name", m.getCodeNameBase()); int rel = m.getCodeNameRelease(); 1190 if (rel >= 0) { 1191 p.put("release", new Integer (rel)); } 1193 SpecificationVersion spec = m.getSpecificationVersion(); 1194 if (spec != null) { 1195 p.put("specversion", spec); } 1197 if (!m.isAutoload() && !m.isEager()) { 1198 p.put("enabled", m.isEnabled() ? Boolean.TRUE : Boolean.FALSE); } 1200 p.put("autoload", m.isAutoload() ? Boolean.TRUE : Boolean.FALSE); p.put("eager", m.isEager() ? Boolean.TRUE : Boolean.FALSE); p.put("reloadable", m.isReloadable() ? Boolean.TRUE : Boolean.FALSE); ModuleHistory hist = (ModuleHistory)m.getHistory(); 1204 p.put("jar", hist.getJar()); if (hist.getInstallerStateChanged()) { 1206 p.put("installer", m.getCodeNameBase().replace('.', '-') + ".ser"); p.put("installerState", hist.getInstallerState()); } 1209 return p; 1210 } 1211 1212 private static RequestProcessor rpListener = null; 1213 1217 private final class Listener implements PropertyChangeListener , ErrorHandler , EntityResolver , FileChangeListener, Runnable { 1218 1219 Listener() {} 1220 1221 1223 private boolean listening = true; 1224 public void propertyChange(PropertyChangeEvent evt) { 1225 if (! triggered) throw new IllegalStateException ("Property change before trigger()"); String prop = evt.getPropertyName(); 1229 Object src = evt.getSource(); 1230 if (!listening) { 1231 if (Util.err.isLoggable(Level.FINE)) { 1233 Util.err.fine("ModuleList: ignoring own change " + prop + " from " + src); 1234 } 1235 return; 1236 } 1237 if (ModuleManager.PROP_CLASS_LOADER.equals(prop) || 1238 ModuleManager.PROP_ENABLED_MODULES.equals(prop) || 1239 Module.PROP_CLASS_LOADER.equals(prop) || 1240 Module.PROP_PROBLEMS.equals(prop) || 1241 Module.PROP_VALID.equals(prop)) { 1242 return; 1246 } else if (ModuleManager.PROP_MODULES.equals(prop)) { 1247 moduleListChanged(); 1248 } else if (src instanceof Module) { 1249 Module m = (Module)src; 1251 if (! m.isValid()) { 1252 return; 1254 } 1255 DiskStatus status = statuses.get(m.getCodeNameBase()); 1256 if (status == null) { 1257 throw new IllegalStateException ("Unknown module " + m + "; statuses=" + statuses); } 1259 if (status.pendingInstall && Module.PROP_ENABLED.equals(prop)) { 1260 throw new IllegalStateException ("Got PROP_ENABLED on " + m + " before trigger()"); } 1262 moduleChanged(m, status); 1263 } else { 1264 Util.err.fine("Unexpected property change: " + evt + " prop=" + prop + " SRC=" + src); 1265 } 1266 } 1267 1268 1270 public void warning(SAXParseException e) throws SAXException { 1271 Util.err.log(Level.WARNING, null, e); 1272 } 1273 public void error(SAXParseException e) throws SAXException { 1274 throw e; 1275 } 1276 public void fatalError(SAXParseException e) throws SAXException { 1277 throw e; 1278 } 1279 public InputSource resolveEntity(String pubid, String sysid) throws SAXException , IOException { 1280 if (pubid.equals(PUBLIC_ID)) { 1281 if (VALIDATE_XML) { 1282 return new InputSource (ModuleList.class.getResource("module-status-1_0.dtd").toExternalForm()); } else { 1285 return new InputSource (new ByteArrayInputStream (new byte[0])); 1287 } 1288 } else { 1289 return EntityCatalog.getDefault().resolveEntity(pubid, sysid); 1291 } 1292 } 1293 1294 1296 public void fileDeleted(FileEvent ev) { 1297 if (isOurs(ev)) { 1298 if (Util.err.isLoggable(Level.FINE)) { 1299 Util.err.fine("ModuleList: got expected deletion " + ev); 1300 } 1301 return; 1302 } 1303 FileObject fo = ev.getFile(); 1304 fileDeleted0(fo.getName(), fo.getExt()); 1305 } 1306 1307 public void fileDataCreated(FileEvent ev) { 1308 if (isOurs(ev)) { 1309 if (Util.err.isLoggable(Level.FINE)) { 1310 Util.err.fine("ModuleList: got expected creation " + ev); 1311 } 1312 return; 1313 } 1314 FileObject fo = ev.getFile(); 1315 fileCreated0(fo.getName(), fo.getExt()); 1316 } 1317 1318 public void fileRenamed(FileRenameEvent ev) { 1319 if (isOurs(ev)) { 1320 throw new IllegalStateException ("I don't rename anything! " + ev); } 1322 FileObject fo = ev.getFile(); 1323 fileDeleted0(ev.getName(), ev.getExt()); 1324 fileCreated0(fo.getName(), fo.getExt()); 1325 } 1326 1327 private void fileCreated0(String name, String ext) { 1328 if ("xml".equals(ext)) { String codenamebase = name.replace('-', '.'); 1330 DiskStatus status = statuses.get(codenamebase); 1331 Util.err.fine("ModuleList: outside file creation event for " + codenamebase); 1332 if (status != null) { 1333 status.dirty = true; 1335 } 1336 runme(); 1337 } else if ("ser".equals(ext)) { } } 1341 1342 private void fileDeleted0(String name, String ext) { 1343 if ("xml".equals(ext)) { String codenamebase = name.replace('-', '.'); 1346 DiskStatus status = statuses.get(codenamebase); 1347 Util.err.fine("ModuleList: outside file deletion event for " + codenamebase); 1348 if (status != null) { 1349 status.dirty = true; 1351 } 1352 runme(); 1353 } else if ("ser".equals(ext)) { } } 1357 1358 public void fileChanged(FileEvent ev) { 1359 if (isOurs(ev)) { 1360 if (Util.err.isLoggable(Level.FINE)) { 1361 Util.err.fine("ModuleList: got expected modification " + ev); 1362 } 1363 return; 1364 } 1365 FileObject fo = ev.getFile(); 1366 String name = fo.getName(); 1367 String ext = fo.getExt(); 1368 if ("xml".equals(ext)) { String codenamebase = name.replace('-', '.'); 1371 DiskStatus status = statuses.get(codenamebase); 1372 Util.err.fine("ModuleList: outside file modification event for " + codenamebase + ": " + ev); 1373 if (status != null) { 1374 status.dirty = true; 1375 } else { 1376 } 1378 runme(); 1379 } else if ("ser".equals(ext)) { } } 1383 1384 public void fileFolderCreated(FileEvent ev) { 1385 } 1387 public void fileAttributeChanged(FileAttributeEvent ev) { 1388 } 1390 1391 1395 private boolean isOurs(FileEvent ev) { 1396 Iterator it = myAtomicActions.iterator(); 1397 while (it.hasNext()) { 1398 if (ev.firedFrom((FileSystem.AtomicAction)it.next())) { 1399 return true; 1400 } 1401 } 1402 return false; 1403 } 1404 1405 1407 private boolean pendingRun = false; 1408 private synchronized void runme() { 1409 if (! pendingRun) { 1410 pendingRun = true; 1411 if (rpListener == null) { 1412 rpListener = new RequestProcessor("org.netbeans.core.modules.ModuleList.Listener"); } 1414 rpListener.post(this); 1415 } 1416 } 1417 public void run() { 1418 synchronized (this) { 1419 pendingRun = false; 1420 } 1421 Util.err.fine("ModuleList: will process outstanding external XML changes"); 1422 mgr.mutexPrivileged().enterWriteAccess(); 1423 try { 1424 folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 1425 public void run() throws IOException { 1426 Map <String ,FileObject> xmlfiles = prepareXMLFiles(); 1439 Map <String ,Map <String ,Object >> dirtyprops = prepareDirtyProps(xmlfiles); 1441 listening = false; 1445 try { 1446 stepCheckReloadable(dirtyprops); 1447 stepCreate(xmlfiles, dirtyprops); 1448 stepEnable(dirtyprops); 1449 stepDisable(dirtyprops); 1450 stepDelete(xmlfiles); 1451 stepCheckMisc(dirtyprops); 1452 stepCheckSer(xmlfiles, dirtyprops); 1453 } finally { 1454 listening = true; 1455 stepUpdateProps(dirtyprops); 1456 stepMarkClean(); 1457 } 1458 } 1459 }); 1460 Util.err.fine("ModuleList: finished processing outstanding external XML changes"); 1461 } catch (IOException ioe) { 1462 Util.err.log(Level.WARNING, null, ioe); 1463 } finally { 1464 mgr.mutexPrivileged().exitWriteAccess(); 1465 } 1466 } 1467 private Map <String ,FileObject> prepareXMLFiles() { 1469 Util.err.fine("ModuleList: prepareXMLFiles"); 1470 Map <String ,FileObject> xmlfiles = new HashMap <String ,FileObject>(100); 1471 FileObject[] kids = folder.getChildren(); 1472 for (int i = 0; i < kids.length; i++) { 1473 if (kids[i].hasExt("xml")) { xmlfiles.put(kids[i].getName().replace('-', '.'), kids[i]); 1475 } 1476 } 1477 return xmlfiles; 1478 } 1479 private Map <String ,Map <String ,Object >> prepareDirtyProps(Map <String ,FileObject> xmlfiles) throws IOException { 1480 Util.err.fine("ModuleList: prepareDirtyProps"); 1481 Map <String ,Map <String ,Object >> dirtyprops = new HashMap <String ,Map <String ,Object >>(100); 1482 Iterator <Map.Entry <String ,FileObject>> it = xmlfiles.entrySet().iterator(); 1483 while (it.hasNext()) { 1484 Map.Entry <String ,FileObject> entry = it.next(); 1485 String cnb = entry.getKey(); 1486 DiskStatus status = statuses.get(cnb); 1487 if (status == null || status.dirty) { 1488 FileObject xmlfile = entry.getValue(); 1489 if (xmlfile == null || ! xmlfile.canRead ()) { 1490 continue; 1491 } 1492 InputStream is = xmlfile.getInputStream(); 1493 try { 1494 InputSource src = new InputSource (is); 1495 src.setSystemId(xmlfile.getURL().toString()); 1496 try { 1497 dirtyprops.put(cnb, readStatus(src, null)); 1498 } catch (SAXException saxe) { 1499 throw (IOException ) new IOException (saxe.toString()).initCause(saxe); 1500 } 1501 } finally { 1502 is.close(); 1503 } 1504 } 1505 } 1506 return dirtyprops; 1507 } 1508 private void stepCheckReloadable(Map <String ,Map <String ,Object >> dirtyprops) { 1509 Util.err.fine("ModuleList: stepCheckReloadable"); 1510 Iterator <Map.Entry <String ,Map <String ,Object >>> it = dirtyprops.entrySet().iterator(); 1511 while (it.hasNext()) { 1512 Map.Entry <String ,Map <String ,Object >> entry = it.next(); 1513 String cnb = entry.getKey(); 1514 DiskStatus status = statuses.get(cnb); 1515 if (status != null) { 1516 Map <String ,Object > props = entry.getValue(); 1517 Boolean diskReloadableB = (Boolean )props.get("reloadable"); boolean diskReloadable = (diskReloadableB != null ? diskReloadableB.booleanValue() : false); 1519 boolean memReloadable = status.module.isReloadable(); 1520 if (memReloadable != diskReloadable) { 1521 Util.err.fine("Disk change in reloadable for " + cnb + " from " + memReloadable + " to " + diskReloadable); 1522 status.module.setReloadable(diskReloadable); 1523 } 1524 } 1525 } 1526 } 1527 private void stepCreate(Map <String ,FileObject> xmlfiles, Map <String ,Map <String ,Object >> dirtyprops) throws IOException { 1528 Util.err.fine("ModuleList: stepCreate"); 1529 Iterator <Map.Entry <String ,FileObject>> it = xmlfiles.entrySet().iterator(); 1530 while (it.hasNext()) { 1531 Map.Entry <String ,FileObject> entry = it.next(); 1532 String cnb = entry.getKey(); 1533 if (! statuses.containsKey(cnb)) { 1534 FileObject xmlfile = entry.getValue(); 1535 Map <String , Object > props = dirtyprops.get(cnb); 1536 if (! cnb.equals(props.get("name"))) throw new IOException ("Code name mismatch"); String jar = (String )props.get("jar"); File jarFile = findJarByName(jar, cnb); 1539 Boolean reloadableB = (Boolean )props.get("reloadable"); boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); 1541 Boolean autoloadB = (Boolean )props.get("autoload"); boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); 1543 Boolean eagerB = (Boolean )props.get("eager"); boolean eager = (eagerB != null ? eagerB.booleanValue() : false); 1545 Module m; 1546 try { 1547 m = mgr.create(jarFile, new ModuleHistory(jar), reloadable, autoload, eager); 1548 } catch (DuplicateException dupe) { 1549 throw (IOException ) new IOException (dupe.toString()).initCause(dupe); 1552 } 1553 m.addPropertyChangeListener(this); 1554 Map <String , Object > statusProps; 1557 if (props.get("enabled") != null && ((Boolean )props.get("enabled")).booleanValue()) { statusProps = new HashMap <String , Object >(props); 1559 statusProps.put("enabled", Boolean.FALSE); } else { 1561 statusProps = props; 1562 } 1563 DiskStatus status = new DiskStatus(); 1564 status.module = m; 1565 status.file = xmlfile; 1566 status.diskProps = statusProps; 1567 statuses.put(cnb, status); 1568 } 1569 } 1570 } 1571 private void stepEnable(Map <String ,Map <String ,Object >> dirtyprops) throws IOException { 1572 Util.err.fine("ModuleList: stepEnable"); 1573 Set <Module> toenable = new HashSet <Module>(); 1574 Iterator <Map.Entry <String ,Map <String ,Object >>> it = dirtyprops.entrySet().iterator(); 1575 while (it.hasNext()) { 1576 Map.Entry <String ,Map <String ,Object >> entry = it.next(); 1577 String cnb = entry.getKey(); 1578 Map <String , Object > props = entry.getValue(); 1579 if (props.get("enabled") != null && ((Boolean )props.get("enabled")).booleanValue()) { DiskStatus status = statuses.get(cnb); 1581 if (status.diskProps.get("enabled") == null || ! ((Boolean )status.diskProps.get("enabled")).booleanValue()) { if (status.module.isEnabled()) throw new IllegalStateException ("Already enabled: " + status.module); toenable.add(status.module); 1584 } 1585 } 1586 } 1587 installNew(toenable); 1588 } 1589 private void stepDisable(Map <String ,Map <String ,Object >> dirtyprops) throws IOException { 1590 Util.err.fine("ModuleList: stepDisable"); 1591 Set <Module> todisable = new HashSet <Module>(); 1592 for (Map.Entry <String ,Map <String ,Object >> entry: dirtyprops.entrySet()) { 1593 String cnb = entry.getKey(); 1594 Map <String , Object > props = entry.getValue(); 1595 if (props.get("enabled") == null || ! ((Boolean )props.get("enabled")).booleanValue()) { DiskStatus status = statuses.get(cnb); 1597 if (status.diskProps.get("enabled") != null && ((Boolean )status.diskProps.get("enabled")).booleanValue()) { if (! status.module.isEnabled()) throw new IllegalStateException ("Already disabled: " + status.module); todisable.add(status.module); 1600 } 1601 } 1602 } 1603 if (todisable.isEmpty()) { 1604 return; 1605 } 1606 List <Module> reallydisable = mgr.simulateDisable(todisable); 1607 for (Module m: reallydisable) { 1608 if (!m.isAutoload() && !m.isEager() && !todisable.contains(m)) { 1609 todisable.add(m); 1610 } 1611 } 1612 mgr.disable(todisable); 1613 } 1614 private void stepDelete(Map <String ,FileObject> xmlfiles) throws IOException { 1615 Util.err.fine("ModuleList: stepDelete"); 1616 Set <Module> todelete = new HashSet <Module>(); 1617 Iterator <Map.Entry <String ,DiskStatus>> it = statuses.entrySet().iterator(); 1618 while (it.hasNext()) { 1619 Map.Entry <String ,DiskStatus> entry = it.next(); 1620 String cnb = entry.getKey(); 1621 DiskStatus status = entry.getValue(); 1622 if (! xmlfiles.containsKey(cnb)) { 1623 Module m = status.module; 1624 todelete.add(m); 1625 it.remove(); 1626 } 1627 } 1628 if (todelete.isEmpty()) { 1629 return; 1630 } 1631 Set <Module> todisable = new HashSet <Module>(); 1632 for (Module m: todelete) { 1633 if (m.isEnabled() && !m.isAutoload() && !m.isEager()) { 1634 todisable.add(m); 1635 } 1636 } 1637 List <Module> reallydisable = mgr.simulateDisable(todisable); 1638 for (Module m: reallydisable) { 1639 if (!m.isAutoload() && !m.isEager() && !todisable.contains(m)) { 1640 todisable.add(m); 1641 } 1642 } 1643 mgr.disable(todisable); 1644 Iterator <Module> delIt = todelete.iterator(); 1646 while (delIt.hasNext()) { 1647 Module m = delIt.next(); 1648 if (m.isEnabled()) { 1649 if (!m.isAutoload() && !m.isEager()) throw new IllegalStateException ("Module " + m + " scheduled for deletion could not be disabled yet was not an autoload nor eager"); ev.log(Events.CANT_DELETE_ENABLED_AUTOLOAD, m); 1652 delIt.remove(); 1653 } else { 1654 mgr.delete(m); 1655 } 1656 } 1657 } 1658 private void stepCheckMisc(Map dirtyprops) { 1659 Util.err.fine("ModuleList: stepCheckMisc"); 1660 String [] toCheck = {"jar", "autoload", "eager", "release", "specversion"}; Iterator it = dirtyprops.entrySet().iterator(); 1662 while (it.hasNext()) { 1663 Map.Entry entry = (Map.Entry )it.next(); 1664 String cnb = (String )entry.getKey(); 1665 Map props = (Map )entry.getValue(); 1666 DiskStatus status = statuses.get(cnb); 1667 Map diskProps = status.diskProps; 1668 for (int i = 0; i < toCheck.length; i++) { 1669 String prop = toCheck[i]; 1670 Object onDisk = props.get(prop); 1671 Object inMem = diskProps.get(prop); 1672 if (! Utilities.compareObjects(onDisk, inMem)) { 1673 ev.log(Events.MISC_PROP_MISMATCH, status.module, prop, onDisk, inMem); 1674 } 1675 } 1676 } 1677 } 1678 private void stepCheckSer(Map xmlfiles, Map dirtyprops) { 1679 } 1681 private void stepUpdateProps(Map <String ,Map <String ,Object >> dirtyprops) { 1682 Util.err.fine("ModuleList: stepUpdateProps"); 1683 for (Map.Entry <String ,Map <String ,Object >> entry: dirtyprops.entrySet()) { 1684 String cnb = entry.getKey(); 1685 DiskStatus status = statuses.get(cnb); 1686 if (status != null) { 1687 Map <String ,Object > props = entry.getValue(); 1688 status.diskProps = props; 1689 } 1690 } 1691 } 1692 private void stepMarkClean() { 1693 Util.err.fine("ModuleList: stepMarkClean"); 1694 Iterator it = statuses.values().iterator(); 1695 while (it.hasNext()) { 1696 DiskStatus status = (DiskStatus)it.next(); 1697 status.dirty = false; 1698 } 1699 } 1700 1701 } 1702 1703 1704 private static final class DiskStatus { 1705 1706 public DiskStatus() {} 1707 1708 public Module module; 1709 1710 public FileObject file; 1711 1712 1714 public boolean pendingInstall = false; 1715 1716 public Map <String ,Object > diskProps; 1717 1718 public boolean dirty = false; 1719 1720 public String toString() { 1721 return "DiskStatus[module=" + module + ",valid=" + module.isValid() + ",file=" + file + ",dirty=" + dirty + ",pendingInstall=" + pendingInstall + ",diskProps=" + diskProps + "]"; } 1728 } 1729 1730} 1731 | Popular Tags |