Index: core/src/org/netbeans/core/modules/ModuleList.java =================================================================== RCS file: /usr/local/tigris/data/helm/cvs/repository/core/src/org/netbeans/core/modules/ModuleList.java,v retrieving revision 1.11 diff -u -t -r1.11 ModuleList.java --- core/src/org/netbeans/core/modules/ModuleList.java 2001/08/01 08:31:21 1.11 +++ core/src/org/netbeans/core/modules/ModuleList.java 2001/08/16 19:55:15 @@ -36,6 +36,7 @@ import org.openide.util.io.NbObjectInputStream; import org.openide.util.io.NbObjectOutputStream; import org.openide.execution.NbClassPath; +import org.openide.util.RequestProcessor; /** Class responsible for maintaining the list of modules in the IDE persistently. @@ -243,7 +244,10 @@ */ public Set readInitial() { ev.log(Events.START_READ); - Set read = new HashSet(); // Set + final Set read = new HashSet(); // Set + try { + folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { FileObject[] children = folder.getChildren(); ev.log(Events.PERF_TICK, "list of files found"); @@ -280,26 +284,9 @@ } if (! name.equals(props.get("name"))) throw new IOException("Code name mismatch"); // NOI18N String origin = (String)props.get("origin"); // NOI18N - if (origin == null) throw new IOException("Must define origin param"); // NOI18N String relativeJar = (String)props.get("jar"); // NOI18N - if (relativeJar == null) throw new IOException("Must define jar param"); // NO18N // NOI18N - File jar; + File jar = findJarByName(origin, relativeJar); - if (origin.equals("adhoc")) { // NOI18N - jar = new File(relativeJar); - if (! jar.isAbsolute()) throw new IOException("With adhoc base, jar must be absolute"); // NOI18N - } else { - Iterator it = autoscanFolders.iterator(); - jar = null; - while (it.hasNext()) { - AutoscanFolder dir = (AutoscanFolder)it.next(); - if (origin.equals(dir.origin)) { - jar = new File(dir.folder, relativeJar); - break; - } - } - if (jar == null) throw new IOException("Unrecognized origin: " + origin); // NOI18N - } if (! jar.isFile()) { Util.err.log("Cannot find: " + jar); ev.log(Events.MISSING_JAR_FILE, jar); @@ -312,18 +299,17 @@ } ModuleHistory history = new ModuleHistory(origin, origin.equals("adhoc") ? null : relativeJar); // NOI18N - String prevReleaseS = (String)props.get("release"); // NOI18N - int prevRelease = (prevReleaseS == null ? -1 : Integer.parseInt(prevReleaseS)); - String prevSpecS = (String)props.get("specversion"); // NOI18N - SpecificationVersion prevSpec = (prevSpecS == null ? null : new SpecificationVersion(prevSpecS)); + Integer prevReleaseI = (Integer)props.get("release"); // NOI18N + int prevRelease = (prevReleaseI == null ? -1 : prevReleaseI.intValue()); + SpecificationVersion prevSpec = (SpecificationVersion)props.get("specversion"); // NOI18N history.upgrade(prevRelease, prevSpec); - String reloadableS = (String)props.get("reloadable"); // NOI18N - boolean reloadable = (reloadableS != null ? Boolean.valueOf(reloadableS).booleanValue() : false); - String enabledS = (String)props.get("enabled"); // NOI18N - boolean enabled = (enabledS != null ? Boolean.valueOf(enabledS).booleanValue() : false); - String autoloadS = (String)props.get("autoload"); // NOI18N - boolean autoload = (autoloadS != null ? Boolean.valueOf(autoloadS).booleanValue() : false); - if (autoload && enabledS != null) throw new IOException("Autoloads cannot specify enablement"); // NOI18N + Boolean reloadableB = (Boolean)props.get("reloadable"); // NOI18N + boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); + Boolean enabledB = (Boolean)props.get("enabled"); // NOI18N + boolean enabled = (enabledB != null ? enabledB.booleanValue() : false); + Boolean autoloadB = (Boolean)props.get("autoload"); // NOI18N + boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); + if (autoload && enabledB != null) throw new IOException("Autoloads cannot specify enablement"); // NOI18N String installer = (String)props.get("installer"); // NOI18N if (installer != null) { if (! installer.equals(nameDashes + ".ser")) throw new IOException("Incorrect installer ser name: " + installer); // NOI18N @@ -347,7 +333,7 @@ DiskStatus status = new DiskStatus(); status.module = m; status.file = children[i]; - status.lastApprovedChange = children[i].lastModified().getTime(); + //status.lastApprovedChange = children[i].lastModified().getTime(); status.pendingInstall = enabled; // Will only really be flushed if mgr props != disk props, i.e // if version changed or could not be enabled. @@ -370,9 +356,30 @@ if (Boolean.getBoolean("org.netbeans.core.modules.ModuleList.13921")) { // XXX disable by default for now... folder.addFileChangeListener(WeakListener.fileChange(listener, folder)); } + }}); + } catch (IOException ioe) { + Util.err.notify(ioe); + } return read; } + private File findJarByName(String origin, String relativeJar) throws IOException { + if (origin.equals("adhoc")) { // NOI18N + File jar = new File(relativeJar); + if (! jar.isAbsolute()) throw new IOException("With adhoc base, jar must be absolute"); // NOI18N + return jar; + } else { + Iterator it = autoscanFolders.iterator(); + while (it.hasNext()) { + AutoscanFolder dir = (AutoscanFolder)it.next(); + if (origin.equals(dir.origin)) { + return new File(dir.folder, relativeJar); + } + } + throw new IOException("Unrecognized origin: " + origin); // NOI18N + } + } + /** Actually go ahead and enable modules which were queued up by * scanning/reading methods. Should be done after as many modules * are collected as possible, in case they have odd mutual @@ -935,6 +942,8 @@ * One distinguished property 'name' is the code name base * and is taken from the root element. Others are taken * from the param elements. + * Properties are of type String, Boolean, Integer, or SpecificationVersion + * according to the property name. */ private Map readStatus(InputSource is) throws IOException, SAXException { Document doc = XMLUtil.parse(is, VALIDATE_XML, false, listener, listener); @@ -963,8 +972,26 @@ } } if (contents == null) throw new SAXException("No text contents in " + name + " of " + m.get("name") + ": " + param); // NOI18N - m.put(name, contents); + try { + if (name.equals("release")) { // NOI18N + m.put(name, new Integer(contents)); + } else if (name.equals("enabled") || name.equals("autoload") || name.equals("reloadable")) { // NOI18N + m.put(name, Boolean.valueOf(contents)); + } else if (name.equals("specversion")) { // NOI18N + m.put(name, new SpecificationVersion(contents)); + } else { + // Other properties are of type String. + m.put(name, contents); + } + } catch (NumberFormatException nfe) { + // From either Integer or SpecificationVersion constructors. + IOException ioe = new IOException(nfe.toString()); + Util.err.annotate(ioe, nfe); + throw ioe; + } } + if (m.get("origin") == null) throw new IOException("Must define origin param"); // NOI18N + if (m.get("jar") == null) throw new IOException("Must define jar param"); // NOI18N return m; } @@ -975,6 +1002,7 @@ private void writeStatus(Map m, OutputStream os) throws IOException, DOMException { String codeName = (String)m.get("name"); // NOI18N if (codeName == null) throw new IllegalArgumentException("no code name present"); // NOI18N + // XXX is it faster to omit the DOCTYPE altogether? Document doc = XMLUtil.createDocument("module", null, PUBLIC_ID, SYSTEM_ID); // NOI18N Element el = doc.getDocumentElement(); el.setAttribute("name", codeName); // NOI18N @@ -989,10 +1017,10 @@ continue; } Object val = entry.getValue(); - if (! (val instanceof String)) throw new ClassCastException("Entry " + name + " was: " + val); // NOI18N + //if (! (val instanceof String)) throw new ClassCastException("Entry " + name + " was: " + val); // NOI18N Element param = doc.createElement("param"); // NOI18N param.setAttribute("name", name); // NOI18N - param.appendChild(doc.createTextNode((String)val)); + param.appendChild(doc.createTextNode(val.toString())); el.appendChild(param); } XMLUtil.write(doc, os, "UTF-8"); // NOI18N @@ -1017,12 +1045,16 @@ } folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { public void run() throws IOException { + boolean created; if (nue.file == null) { + created = true; nue.file = folder.createData(((String)nue.diskProps.get("name")).replace('.', '-'), "xml"); // NOI18N } else { + created = false; // Just verify that no one else touched it since we last did. - if (nue.lastApprovedChange != nue.file.lastModified().getTime()) { + if (/*nue.lastApprovedChange != nue.file.lastModified().getTime()*/nue.dirty) { // Oops, something is wrong. + // XXX should this only warn instead? throw new IOException("Will not clobber external changes in " + nue.file); // NOI18N } } @@ -1044,7 +1076,7 @@ } finally { lock.releaseLock(); } - nue.lastApprovedChange = nue.file.lastModified().getTime(); + //nue.lastApprovedChange = nue.file.lastModified().getTime(); // Now check up on the installer ser. byte[] data = (byte[])nue.diskProps.get("installerState"); // NOI18N String installerName = (String) nue.diskProps.get("installer"); // NOI18N @@ -1075,6 +1107,12 @@ } */ } + if (created) { + // XXX will this also send a file modified event? + nue.addCount++; + } else { + nue.modifyCount++; + } } }); return nue; @@ -1082,19 +1120,32 @@ /** Delete a module from disk. */ - private void deleteFromDisk(Module m, DiskStatus status) throws IOException { + private void deleteFromDisk(final Module m, final DiskStatus status) throws IOException { final String nameDashes = m.getCodeNameBase().replace('.', '-'); // NOI18N - final long expectedTime = status.lastApprovedChange; + //final long expectedTime = status.lastApprovedChange; folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { public void run() throws IOException { FileObject xml = folder.getFileObject(nameDashes, "xml"); // NOI18N - if (xml == null) throw new IOException("No such XML file: " + nameDashes + ".xml"); // NOI18N + if (xml == null) { + // Could be that the XML was already deleted externally, etc. + Util.err.log("ModuleList: " + m + "'s XML already gone from disk"); + return; + } + //if (xml == null) throw new IOException("No such XML file: " + nameDashes + ".xml"); // NOI18N + if (status.dirty) { + // Someone wrote to the file since we did. Don't delete it blindly! + // XXX should this throw an exception, or just warn?? + throw new IOException("Unapproved external change to " + xml); // NOI18N + } Util.err.log("ModuleList: deleting " + xml); + /* if (xml.lastModified().getTime() != expectedTime) { // Someone wrote to the file since we did. Don't delete it blindly! throw new IOException("Unapproved external change to " + xml); // NOI18N } + */ xml.delete(); + status.removeCount++; FileObject ser = folder.getFileObject(nameDashes, "ser"); // NOI18N if (ser != null) { Util.err.log("(and also " + ser + ")"); @@ -1246,17 +1297,17 @@ p.put("name", m.getCodeNameBase()); // NOI18N int rel = m.getCodeNameRelease(); if (rel >= 0) { - p.put("release", String.valueOf(rel)); // NOI18N + p.put("release", new Integer(rel)); // NOI18N } SpecificationVersion spec = m.getSpecificationVersion(); if (spec != null) { - p.put("specversion", spec.toString()); // NOI18N + p.put("specversion", spec); // NOI18N } if (! m.isAutoload()) { - p.put("enabled", String.valueOf(m.isEnabled())); // NOI18N + p.put("enabled", new Boolean(m.isEnabled())); // NOI18N } - p.put("autoload", String.valueOf(m.isAutoload())); // NOI18N - p.put("reloadable", String.valueOf(m.isReloadable())); // NOI18N + p.put("autoload", new Boolean(m.isAutoload())); // NOI18N + p.put("reloadable", new Boolean(m.isReloadable())); // NOI18N ModuleHistory hist = (ModuleHistory)m.getHistory(); p.put("origin", hist.getOrigin()); // NOI18N if (hist.getOrigin().equals("adhoc")) { // NOI18N @@ -1275,8 +1326,12 @@ /** Listener for changes in set of modules and various properties of individual modules. * Also serves as a strict error handler for XML parsing. + * Also listens to changes in the Modules/ folder and processes them in req proc. */ - private final class Listener implements PropertyChangeListener, ErrorHandler, EntityResolver, FileChangeListener { + private final class Listener implements PropertyChangeListener, ErrorHandler, EntityResolver, FileChangeListener, Runnable { + + // Property change coming from ModuleManager or some known Module. + public void propertyChange(PropertyChangeEvent evt) { if (! triggered) throw new IllegalStateException("Property change before trigger()"); // NOI18N // REMEMBER this is inside *read* mutex, it is forbidden to even attempt @@ -1313,6 +1368,9 @@ Util.err.log("Unexpected property change: " + evt + " prop=" + prop + " src=" + src); } } + + // SAX stuff. + public void warning(SAXParseException e) throws SAXException { Util.err.notify(ErrorManager.WARNING, e); } @@ -1336,52 +1394,315 @@ return EntityCatalog.getDefault().resolveEntity(pubid, sysid); } } + + // Changes in Modules/ folder. + public void fileDeleted(FileEvent ev) { FileObject fo = ev.getFile(); - fileDeleted0(fo.getName(), fo.getExt()); + fileDeleted0(fo.getName(), fo.getExt()/*, ev.getTime()*/); } + public void fileDataCreated(FileEvent ev) { FileObject fo = ev.getFile(); - fileCreated0(fo.getName(), fo.getExt()); + fileCreated0(fo, fo.getName(), fo.getExt()/*, ev.getTime()*/); } + public void fileRenamed(FileRenameEvent ev) { FileObject fo = ev.getFile(); - fileDeleted0(ev.getName(), ev.getExt()); - fileCreated0(fo.getName(), fo.getExt()); + fileDeleted0(ev.getName(), ev.getExt()/*, ev.getTime()*/); + fileCreated0(fo, fo.getName(), fo.getExt()/*, ev.getTime()*/); } - private void fileCreated0(String name, String ext) { + + private void fileCreated0(FileObject fo, String name, String ext/*, long time*/) { if ("xml".equals(ext)) { // NOI18N + String codenamebase = name.replace('-', '.'); + DiskStatus status = (DiskStatus)stati.get(codenamebase); + if (status != null && status.addCount > 0) { + Util.err.log("ModuleList: got expected file creation event for " + codenamebase); + status.addCount--; + return; + } + Util.err.log("ModuleList: outside file creation event for " + codenamebase); + if (status != null) { + // XXX should this really happen?? + status.dirty = true; + } + runme(); + /* + if (status != null) { + // XXX check to make sure the times match up?? + Util.err.log("ModuleList.fileCreated0: got expected file creation for " + codenamebase); + return; + } // New module. - // XXX create it + Map props; + try { + InputStream is = fo.getInputStream(); + try { + InputSource src = new InputSource(is); + src.setEncoding("UTF-8"); // NOI18N + // Make sure any includes etc. are handled properly: + src.setSystemId(fo.getURL().toString()); + props = readStatus(src); + } finally { + is.close(); + } + } catch (Exception e) { + Util.err.notify(e); + return; + } + if (! codenamebase.equals(props.get("name"))) { // NOI18N + Util.err.log("Code name mismatch for newly added module XML: " + props.get(name) + " rather than " + codenamebase); + return; + } + String relativeJar = (String)props.get("jar"); // NOI18N + String origin = (String)props.get("origin"); // NOI18N + */ } else if ("ser".equals(ext)) { // NOI18N // XXX handle newly added installers?? or not } // else ignore } - private void fileDeleted0(String name, String ext) { + + private void fileDeleted0(String name, String ext/*, long time*/) { if ("xml".equals(ext)) { // NOI18N // Removed module. - // XXX delete it + String codenamebase = name.replace('-', '.'); + DiskStatus status = (DiskStatus)stati.get(codenamebase); + if (status != null && status.removeCount > 0) { + Util.err.log("ModuleList: got expected file deletion event for " + codenamebase); + status.removeCount--; + stati.remove(codenamebase); + return; + } + Util.err.log("ModuleList: outside file deletion event for " + codenamebase); + if (status != null) { + // XXX should this ever happen? + status.dirty = true; + } + runme(); } else if ("ser".equals(ext)) { // NOI18N // XXX handle newly deleted installers?? or not } // else ignore } + public void fileChanged(FileEvent ev) { FileObject fo = ev.getFile(); String name = fo.getName(); String ext = fo.getExt(); if ("xml".equals(ext)) { // NOI18N // Changed module. - // XXX reload its info + String codenamebase = name.replace('-', '.'); + DiskStatus status = (DiskStatus)stati.get(codenamebase); + if (status != null && status.modifyCount > 0) { + Util.err.log("ModuleList: got expected file modification event for " + codenamebase + ": " + ev); + status.modifyCount--; + return; + } + Util.err.log("ModuleList: outside file modification event for " + codenamebase + ": " + ev); + if (status != null) { + status.dirty = true; + } else { + // XXX should this ever happen? + } + runme(); } else if ("ser".equals(ext)) { // NOI18N // XXX handle changes of installers?? or not } // else ignore } + public void fileFolderCreated(FileEvent ev) { // ignore } public void fileAttributeChanged(FileAttributeEvent ev) { // ignore } + + // Dealing with changes in Modules/ folder and processing them. + + private boolean pendingRun = false; + private synchronized void runme() { + if (! pendingRun) { + pendingRun = true; + RequestProcessor.postRequest(this); + } + } + public void run() { + synchronized (this) { + pendingRun = false; + } + Util.err.log("ModuleList: will process outstanding external XML changes"); + mgr.mutexPrivileged().enterWriteAccess(); + try { + folder.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { + // 1. For any dirty XML for which status exists but reloadable differs from XML: change. + // 2. For any XML for which we have no status: create & create status, as disabled. + // 3. For all dirty XML which says enabled but status says disabled: batch-enable as possible. + // (Where not possible, mark disabled in XML??) + // 4. For all dirty XML which says disabled but status says enabled: batch-disable plus others. + // 5. For all status for which no XML exists: batch-disable plus others, then delete. + // 6. For any dirty XML for which jar/origin/autoload/release/specversion differs from + // actual state of module: warn but do nothing. + // 7. For now, ignore any changes in *.ser. + // 8. For any dirty XML for which status now exists: replace diskProps with contents of XML. + // 9. Mark all stati clean. + // Code name to module XMLs found on disk: + Map xmlfiles = prepareXMLFiles(); + // Code name to properties for dirty XML or XML sans status only. + Map dirtyprops = prepareDirtyProps(xmlfiles); + stepCheckReloadable(xmlfiles, dirtyprops); + stepCreate(xmlfiles, dirtyprops); + stepEnable(xmlfiles, dirtyprops); + stepDisable(xmlfiles, dirtyprops); + stepDelete(xmlfiles, dirtyprops); + stepCheckMisc(xmlfiles, dirtyprops); + stepCheckSer(xmlfiles, dirtyprops); + stepUpdateProps(xmlfiles, dirtyprops); + stepMarkClean(xmlfiles, dirtyprops); + } + }); + } catch (IOException ioe) { + Util.err.notify(ioe); + } finally { + mgr.mutexPrivileged().exitWriteAccess(); + } + Util.err.log("ModuleList: finished processing outstanding external XML changes"); + } + // All the steps called from the run() method to handle disk changes: + private Map prepareXMLFiles() { + Map xmlfiles = new HashMap(100); // Map + FileObject[] kids = folder.getChildren(); + for (int i = 0; i < kids.length; i++) { + if (kids[i].hasExt("xml")) { // NOI18N + xmlfiles.put(kids[i].getName().replace('-', '.'), kids[i]); + } + } + return xmlfiles; + } + private Map prepareDirtyProps(Map xmlfiles) throws IOException { + Map dirtyprops = new HashMap(100); // Map> + Iterator it = xmlfiles.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + String cnb = (String)entry.getKey(); + DiskStatus status = (DiskStatus)stati.get(cnb); + if (status == null || status.dirty) { + FileObject xmlfile = (FileObject)entry.getValue(); + InputStream is = xmlfile.getInputStream(); + try { + InputSource src = new InputSource(is); + src.setSystemId(xmlfile.getURL().toString()); + try { + dirtyprops.put(cnb, readStatus(src)); + } catch (SAXException saxe) { + IOException ioe = new IOException(saxe.toString()); + Util.err.annotate(ioe, saxe); + throw ioe; + } + } finally { + is.close(); + } + } + } + return dirtyprops; + } + private void stepCheckReloadable(Map xmlfiles, Map dirtyprops) { + Iterator it = dirtyprops.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + String cnb = (String)entry.getKey(); + DiskStatus status = (DiskStatus)stati.get(cnb); + if (status != null) { + Map props = (Map)entry.getValue(); + Boolean diskReloadableB = (Boolean)props.get("reloadable"); // NOI18N + boolean diskReloadable = (diskReloadableB != null ? diskReloadableB.booleanValue() : false); + boolean memReloadable = status.module.isReloadable(); + if (memReloadable != diskReloadable) { + Util.err.log("Disk change in reloadable for " + cnb + " from " + memReloadable + " to " + diskReloadable); + status.module.setReloadable(diskReloadable); + } + } + } + } + private void stepCreate(Map xmlfiles, Map dirtyprops) throws IOException { + Iterator it = xmlfiles.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + String cnb = (String)entry.getKey(); + if (stati.get(cnb) == null) { + FileObject xmlfile = (FileObject)entry.getValue(); + Map props = (Map)dirtyprops.get(cnb); + if (! cnb.equals(props.get("name"))) throw new IOException("Code name mismatch"); // NOI18N + String origin = (String)props.get("origin"); // NOI18N + String relativeJar = (String)props.get("jar"); // NOI18N + File jar = findJarByName(origin, relativeJar); + if (! jar.isFile()) throw new IOException("No such module JAR: " + jar); // NOI18N + Boolean reloadableB = (Boolean)props.get("reloadable"); // NOI18N + boolean reloadable = (reloadableB != null ? reloadableB.booleanValue() : false); + Boolean autoloadB = (Boolean)props.get("autoload"); // NOI18N + boolean autoload = (autoloadB != null ? autoloadB.booleanValue() : false); + Module m; + try { + m = mgr.create(jar, new ModuleHistory(origin, relativeJar), reloadable, autoload); + } catch (DuplicateException dupe) { + // XXX should this be tolerated somehow? In case the original is + // in fact scheduled for deletion anyway? + IOException ioe = new IOException(dupe.toString()); + Util.err.annotate(ioe, dupe); + throw ioe; + } + // Mark the status as disabled for the moment, so in step 3 it will be turned on + // if in dirtyprops it was marked enabled. + Map statusProps; + if (props.get("enabled") != null && ((Boolean)props.get("enabled")).booleanValue()) { // NOI18N + statusProps = new HashMap(props); + statusProps.put("enabled", Boolean.FALSE); // NOI18N + } else { + statusProps = props; + } + DiskStatus status = new DiskStatus(); + status.module = m; + status.file = xmlfile; + status.diskProps = statusProps; + stati.put(cnb, status); + } + } + } + private void stepEnable(Map xmlfiles, Map dirtyprops) throws IOException { + // XXX + } + private void stepDisable(Map xmlfiles, Map dirtyprops) throws IOException { + // XXX + } + private void stepDelete(Map xmlfiles, Map dirtyprops) throws IOException { + // XXX + } + private void stepCheckMisc(Map xmlfiles, Map dirtyprops) { + // XXX + } + private void stepCheckSer(Map xmlfiles, Map dirtyprops) { + // There is NO step 7! + } + private void stepUpdateProps(Map xmlfiles, Map dirtyprops) { + Iterator it = dirtyprops.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = (Map.Entry)it.next(); + String cnb = (String)entry.getKey(); + DiskStatus status = (DiskStatus)stati.get(cnb); + if (status != null) { + Map props = (Map)entry.getValue(); + status.diskProps = props; + } + } + } + private void stepMarkClean(Map xmlfiles, Map dirtyprops) { + Iterator it = stati.values().iterator(); + while (it.hasNext()) { + DiskStatus status = (DiskStatus)it.next(); + status.dirty = false; + } + } + } /** Representation of the status of a module on disk and so on. */ @@ -1393,16 +1714,21 @@ /** XML file holding its status */ public FileObject file; /** timestamp of last modification to XML file that this class did */ - public long lastApprovedChange; + //public long lastApprovedChange; /** if true, this module was scanned and should be enabled but we are waiting for trigger */ - public boolean pendingInstall; + public boolean pendingInstall = false; /** properties of the module on disk */ - public Map diskProps; + public Map diskProps; // Map + /** if true, the XML was changed on disk by someone else */ + public boolean dirty = false; + /** count of FileEvent's we expect to come from this file due to our own actions, of each type */ + public int addCount = 0, removeCount = 0, modifyCount = 0; /** for debugging: */ public String toString() { return "DiskStatus[module=" + module + // NOI18N ",valid=" + module.isValid() + // NOI18N - ",file=" + file + ",lastApprovedChange=" + new Date(lastApprovedChange) + // NOI18N + ",file=" + file + /*",lastApprovedChange=" + new Date(lastApprovedChange) +*/ // NOI18N + ",dirty=" + dirty + ",addCount=" + addCount + ",removeCount=" + removeCount + ",modifyCount=" + modifyCount + // NOI18N ",pendingInstall=" + pendingInstall + // NOI18N ",diskProps=" + diskProps + "]"; // NOI18N }