# HG changeset patch # Parent 6db5825b9f05236a4eb2d7f3a3a2d36bdc9d464c diff --git a/apisupport.project/nbproject/project.xml b/apisupport.project/nbproject/project.xml --- a/apisupport.project/nbproject/project.xml +++ b/apisupport.project/nbproject/project.xml @@ -255,12 +255,21 @@ - org.netbeans.modules.xml.tax + org.netbeans.modules.xml.xam - 2 - 1.16 + 1 + 1.11 + + + + org.netbeans.modules.xml.xdm + + + + 1 + 1.12 diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/api/LayerHandle.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/api/LayerHandle.java --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/api/LayerHandle.java +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/api/LayerHandle.java @@ -42,8 +42,6 @@ package org.netbeans.modules.apisupport.project.api; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -59,7 +57,6 @@ import org.netbeans.modules.apisupport.project.NbModuleProjectGenerator; import org.netbeans.modules.apisupport.project.Util; import org.netbeans.modules.apisupport.project.layers.LayerUtils; -import org.netbeans.modules.apisupport.project.layers.LayerUtils.SavableTreeEditorCookie; import org.netbeans.modules.apisupport.project.layers.WritableXMLFileSystem; import org.netbeans.modules.apisupport.project.spi.NbModuleProvider; import org.openide.ErrorManager; @@ -68,7 +65,6 @@ import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileRenameEvent; -import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; import org.openide.filesystems.MultiFileSystem; @@ -99,7 +95,7 @@ private final Project project; private final FileObject layerXML; private FileSystem fs; - private SavableTreeEditorCookie cookie; + private WritableXMLFileSystem wxmlfs; private boolean autosave; public LayerHandle(Project project, FileObject layerXML) { @@ -120,11 +116,11 @@ public synchronized FileSystem layer(boolean create) { if (fs == null) { FileObject xml = getLayerFile(); - if (xml == null) { - if (!create) { - return new DualLayers(null); - } - try { + try { + if (xml == null) { + if (!create) { + return new DualLayers(null); + } NbModuleProvider module = project.getLookup().lookup(NbModuleProvider.class); FileObject manifest = module.getManifestFile(); if (manifest != null) { // #121056 @@ -138,29 +134,35 @@ } } xml = NbModuleProjectGenerator.createLayer(project.getProjectDirectory(), module.getResourceDirectoryPath(false) + '/' + newLayerPath()); - } catch (IOException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); - return fs = FileUtil.createMemoryFileSystem(); } + WritableXMLFileSystem _wxmlfs = new WritableXMLFileSystem(xml, LayerUtils.findResourceCP(project)); + fs = new DualLayers(_wxmlfs); + wxmlfs = _wxmlfs; + // XXX maybe cleaner & more reliable to listen to EditorCookie.Observable.PROP_MODIFIED + wxmlfs.addFileChangeListener(new FileChangeListener() { + public @Override void fileFolderCreated(FileEvent fe) { + setAutosave(autosave); // causes it to save if autosave is on + } + public @Override void fileDataCreated(FileEvent fe) { + setAutosave(autosave); + } + public @Override void fileChanged(FileEvent fe) { + setAutosave(autosave); + } + public @Override void fileDeleted(FileEvent fe) { + setAutosave(autosave); + } + public @Override void fileRenamed(FileRenameEvent fe) { + setAutosave(autosave); + } + public @Override void fileAttributeChanged(FileAttributeEvent fe) { + setAutosave(autosave); + } + }); + } catch (IOException e) { + Util.err.notify(ErrorManager.INFORMATIONAL, e); + fs = FileUtil.createMemoryFileSystem(); } - try { - fs = new DualLayers(new WritableXMLFileSystem(xml.getURL(), cookie = LayerUtils.cookieForFile(xml), LayerUtils.findResourceCP(project))); - } catch (FileStateInvalidException e) { - throw new AssertionError(e); - } - cookie.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - //System.err.println("changed in mem"); - if (autosave && SavableTreeEditorCookie.PROP_DIRTY.equals(evt.getPropertyName())) { - //System.err.println(" will save..."); - try { - save(); - } catch (IOException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } - } - } - }); } return fs; } @@ -215,10 +217,10 @@ * Note that nonempty layer entries you created will already be on disk. */ public void save() throws IOException { - if (cookie == null) { + if (wxmlfs == null) { throw new IOException("Cannot save a nonexistent layer"); // NOI18N } - cookie.save(); + wxmlfs.save(); } /** @@ -251,9 +253,9 @@ */ public void setAutosave(boolean autosave) { this.autosave = autosave; - if (autosave && cookie != null) { + if (autosave && wxmlfs != null) { try { - cookie.save(); + save(); } catch (IOException e) { Util.err.notify(ErrorManager.INFORMATIONAL, e); } diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/LayerUtils.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/LayerUtils.java --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/LayerUtils.java +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/LayerUtils.java @@ -44,14 +44,10 @@ package org.netbeans.modules.apisupport.project.layers; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -85,26 +81,13 @@ import org.netbeans.modules.apisupport.project.universe.ModuleEntry; import org.netbeans.modules.apisupport.project.universe.ModuleList; import org.netbeans.modules.apisupport.project.universe.NbPlatform; -import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie; -import org.netbeans.modules.xml.tax.parser.XMLParsingSupport; import org.netbeans.spi.java.classpath.support.ClassPathSupport; -import org.netbeans.tax.TreeDocumentRoot; -import org.netbeans.tax.TreeException; -import org.netbeans.tax.TreeObject; -import org.netbeans.tax.io.TreeStreamResult; import org.openide.ErrorManager; -import org.openide.filesystems.FileAttributeEvent; -import org.openide.filesystems.FileChangeListener; -import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.FileSystem; -import org.openide.filesystems.FileSystem.AtomicAction; import org.openide.filesystems.FileUtil; import org.openide.filesystems.XMLFileSystem; -import org.openide.util.Task; -import org.xml.sax.InputSource; /** * Misc support for dealing with layers. @@ -296,151 +279,6 @@ } /** - * Representation of in-memory TAX tree which can be saved upon request. - */ - public interface SavableTreeEditorCookie extends TreeEditorCookie { - - /** property change fired when dirty flag changes */ - String PROP_DIRTY = "dirty"; // NOI18N - - /** true if there are in-memory mods */ - boolean isDirty(); - - /** try to save any in-memory mods to disk */ - void save() throws IOException; - - } - - private static final class CookieImpl implements SavableTreeEditorCookie, FileChangeListener, AtomicAction { - private TreeDocumentRoot root; - private boolean dirty; - private Exception problem; - private final FileObject f; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - public CookieImpl(FileObject f) { - //System.err.println("new CookieImpl for " + f); - this.f = f; - f.addFileChangeListener(FileUtil.weakFileChangeListener(this, f)); - } - public TreeDocumentRoot getDocumentRoot() { - return root; - } - public int getStatus() { - if (problem != null) { - return TreeEditorCookie.STATUS_ERROR; - } else if (root != null) { - return TreeEditorCookie.STATUS_OK; - } else { - return TreeEditorCookie.STATUS_NOT; - } - } - public TreeDocumentRoot openDocumentRoot() throws IOException, TreeException { - if (root == null && f.isValid()) { - try { - //System.err.println("openDocumentRoot: really opening"); - boolean oldDirty = dirty; - int oldStatus = getStatus(); - root = new XMLParsingSupport().parse(new InputSource(f.getURL().toExternalForm())); - problem = null; - dirty = false; - pcs.firePropertyChange(PROP_DIRTY, oldDirty, false); - pcs.firePropertyChange(PROP_STATUS, oldStatus, TreeEditorCookie.STATUS_OK); - //pcs.firePropertyChange(PROP_DOCUMENT_ROOT, null, root); - } catch (IOException e) { - problem = e; - throw e; - } catch (TreeException e) { - problem = e; - throw e; - } - ((TreeObject) root).addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - //System.err.println("tree modified"); - modified(); - } - }); - } - return root; - } - public Task prepareDocumentRoot() { - throw new UnsupportedOperationException(); - } - public void addPropertyChangeListener(PropertyChangeListener listener) { - pcs.addPropertyChangeListener(listener); - } - public void removePropertyChangeListener(PropertyChangeListener listener) { - pcs.removePropertyChangeListener(listener); - } - private void modified() { - //System.err.println("modified(): dirty=" + dirty + " in " + Thread.currentThread().getName() + " for " + this); - if (!dirty) { - dirty = true; - pcs.firePropertyChange(PROP_DIRTY, false, true); - } - } - public boolean isDirty() { - return dirty; - } - public synchronized void save() throws IOException { - //System.err.println("save(): dirty=" + dirty + " in " + Thread.currentThread().getName() + " for " + this); - if (root == null || !dirty) { - return; - } - //System.err.println("saving in " + Thread.currentThread().getName() + " for " + this); - f.getFileSystem().runAtomicAction(this); - //System.err.println("!saving in " + Thread.currentThread().getName() + " for " + this); - dirty = false; - pcs.firePropertyChange(PROP_DIRTY, true, false); - } - public void run() throws IOException { - OutputStream os = f.getOutputStream(); - try { - new TreeStreamResult(os).getWriter(root).writeDocument(); - } catch (TreeException e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } finally { - os.close(); - } - } - public void fileChanged(FileEvent fe) { - changed(fe); - } - public void fileDeleted(FileEvent fe) { - changed(fe); - } - public void fileRenamed(FileRenameEvent fe) { - changed(fe); - } - public void fileAttributeChanged(FileAttributeEvent fe) { - // ignore - } - public void fileFolderCreated(FileEvent fe) { - assert false; - } - public void fileDataCreated(FileEvent fe) { - assert false; - } - private void changed(FileEvent fe) { - //System.err.println("changed on disk in " + Thread.currentThread().getName() + " for " + this); - //Thread.dumpStack(); - synchronized (this) { - if (fe.firedFrom(this)) { - //System.err.println("(my own change)"); - return; - } - problem = null; - dirty = false; - root = null; - } - pcs.firePropertyChange(PROP_DOCUMENT_ROOT, null, null); - } - } - - public static SavableTreeEditorCookie cookieForFile(FileObject f) { - return new CookieImpl(f); - } - - /** * Get a filesystem that will look like what this project would "see". *

There are four possibilities:

*
    diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystem.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystem.java --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystem.java +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystem.java @@ -65,24 +65,12 @@ import java.util.Date; import java.util.Enumeration; import java.util.HashSet; -import java.util.Iterator; import java.util.Set; import org.netbeans.api.java.classpath.ClassPath; -import org.netbeans.modules.apisupport.project.Util; -import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie; -import org.netbeans.tax.InvalidArgumentException; -import org.netbeans.tax.ReadOnlyException; -import org.netbeans.tax.TreeAttribute; -import org.netbeans.tax.TreeCDATASection; -import org.netbeans.tax.TreeChild; -import org.netbeans.tax.TreeDocumentRoot; -import org.netbeans.tax.TreeDocumentType; -import org.netbeans.tax.TreeElement; -import org.netbeans.tax.TreeException; -import org.netbeans.tax.TreeObjectList; -import org.netbeans.tax.TreeParentNode; -import org.netbeans.tax.TreeText; -import org.openide.ErrorManager; +import org.netbeans.editor.BaseDocument; +import org.netbeans.modules.xml.xam.ModelSource; +import org.netbeans.modules.xml.xdm.XDMModel; +import org.openide.cookies.EditorCookie; import org.openide.filesystems.AbstractFileSystem; import org.openide.filesystems.FileAttributeEvent; import org.openide.filesystems.FileChangeListener; @@ -91,19 +79,24 @@ import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.FileUtil; import org.openide.filesystems.URLMapper; +import org.openide.loaders.DataObject; import org.openide.util.Enumerations; -import org.openide.util.WeakListeners; +import org.openide.util.lookup.Lookups; +import org.openide.xml.XMLUtil; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** - * A filesystem which is based on a TAX document and implements + * A filesystem which is based on an XML document and implements * the same syntax as XMLFileSystem, from which inspiration is taken. * Not implemented similarly to XMLFileSystem because this is writable * and designed specifically to write human-readable XML and work nicely * as an authoring tool. The filesystem expects to get an XML document - * according to DTD "-//NetBeans//DTD Filesystem 1.0//EN" (or 1.1 is OK). - * When it is changed via FileSystems API, it will fire TAX - * events. Not intended to be efficient or terribly robust, since it - * is development-time only. + * according to DTD "-//NetBeans//DTD Filesystem 1.0//EN" (or 1.1 or 1.2 is OK). + * When it is changed via the FileSystems API, it will update the document. + * Not intended to be efficient or terribly robust, since it is development-time only. * @author Jesse Glick */ public final class WritableXMLFileSystem extends AbstractFileSystem @@ -111,37 +104,43 @@ AbstractFileSystem.Change, AbstractFileSystem.Info, AbstractFileSystem.List, - //AbstractFileSystem.Transfer, FileChangeListener, PropertyChangeListener { - private final TreeEditorCookie cookie; - private TreeDocumentRoot doc; // may be null if malformed + private final EditorCookie editorCookie; + private final XDMModel model; private URL location; - private String suffix; // for branding/localization like "_f4j_ce_ja"; never null, at worst "" private final FileChangeListener fileChangeListener; private ClassPath classpath; // OK to be null - public WritableXMLFileSystem(URL location, TreeEditorCookie cookie, ClassPath classpath) { - this.attr = this; - this.change = this; - this.info = this; - this.list = this; - //this.transfer = this; - this.cookie = cookie; - suffix = ""; - try { - doc = cookie.openDocumentRoot(); - } catch (TreeException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } catch (IOException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); + @SuppressWarnings("LeakingThisInConstructor") + public WritableXMLFileSystem(FileObject xml, ClassPath classpath) throws IOException { + editorCookie = DataObject.find(xml).getLookup().lookup(EditorCookie.class); + if (editorCookie == null) { + throw new IOException("Noneditable layer: " + xml); } + model = new XDMModel(new ModelSource(Lookups.fixed(xml, (BaseDocument) editorCookie.openDocument()), true)); + model.sync(); + model.addPropertyChangeListener(this); + model.setPretty(true); + model.setIndentation(" "); // NOI18N + attr = this; + change = this; + info = this; + list = this; fileChangeListener = FileUtil.weakFileChangeListener(this, null); - cookie.addPropertyChangeListener(WeakListeners.propertyChange(this, cookie)); - setLocation(location); + setLocation(xml.getURL()); setClasspath(classpath); } + + /** + * Saves any outstanding modifications to disk. + * (Modifications are always applied immediately to an editor document.) + * @throws IOException if the document could not be saved + */ + public void save() throws IOException { + editorCookie.saveDocument(); + } private void writeObject(ObjectOutputStream out) throws IOException { throw new NotSerializableException("WritableXMLFileSystem is not persistent"); // NOI18N @@ -159,7 +158,7 @@ this.classpath = classpath; } - public String getDisplayName() { + public @Override String getDisplayName() { FileObject fo = URLMapper.findFileObject(location); if (fo != null) { return FileUtil.getFileDisplayName(fo); @@ -168,35 +167,26 @@ } } - public boolean isReadOnly() { + public @Override boolean isReadOnly() { return false; } - private TreeElement getRootElement() { - if (doc == null) { - return null; - } - Iterator it; - it = doc.getChildNodes().iterator(); - while (it.hasNext()) { - Object next = it.next(); - if (next instanceof TreeElement) { - return (TreeElement) next; - } - } - return null; + private Element getRootElement() { + return model.getDocument().getDocumentElement(); } /** Given a resource name, find the matching DOM element. * @return a or or element, or null if file does not exist */ - private TreeElement findElement(String name) { + private Element findElement(String name) { return findElementIn(getRootElement(), name); } /** helper method only */ - private static TreeElement findElementIn(TreeElement el, String name) { - if (el == null) return null; - if (name.equals("")) { // NOI18N + private static Element findElementIn(Element el, String name) { + if (el == null) { + return null; + } + if (name.isEmpty()) { return el; } else { int idx = name.indexOf('/'); @@ -208,14 +198,12 @@ nextName = name.substring(0, idx); remainder = name.substring(idx + 1); } - TreeElement subel = null; - Iterator it = el.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement e = (TreeElement) it.next(); - if (e.getLocalName().equals("file") || // NOI18N - e.getLocalName().equals("folder")) { // NOI18N - TreeAttribute nameAttr = e.getAttribute("name"); // NOI18N - if (nameAttr != null && nameAttr.getValue().equals(nextName)) { + Element subel = null; + for (Element e : XMLUtil.findSubElements(el)) { + if (e.getTagName().equals("file") || // NOI18N + e.getTagName().equals("folder")) { // NOI18N + String nameAttr = e.getAttribute("name"); // NOI18N + if (nameAttr.equals(nextName)) { subel = e; break; } @@ -225,53 +213,34 @@ } } - public boolean folder(String name) { - TreeElement el = findElement(name); + public @Override boolean folder(String name) { + Element el = findElement(name); if (el == null) { //System.err.println("folder <" + name + ">: false, no such element"); return false; } - boolean res = el.getLocalName().equals("folder"); // NOI18N + boolean res = el.getTagName().equals("folder"); // NOI18N //System.err.println("folder <" + name + ">: " + res); return res; } - /* - private static final Set warnedAboutDupeKids = new HashSet(1); // Set - */ - public String[] children(String f) { - TreeElement el = findElement(f); + public @Override String[] children(String f) { + Element el = findElement(f); if (el == null) { //System.err.println("children <" + f + ">: none, no such element"); return new String[] {}; } ArrayList kids = new ArrayList(); Set allNames = new HashSet(); - Iterator it = el.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement sub = (TreeElement) it.next(); - if (sub.getLocalName().equals("file") || // NOI18N - sub.getLocalName().equals("folder")) { // NOI18N - TreeAttribute childName = sub.getAttribute("name"); // NOI18N - if (childName == null) { + for (Element sub : XMLUtil.findSubElements(el)) { + if (sub.getTagName().equals("file") || // NOI18N + sub.getTagName().equals("folder")) { // NOI18N + String name = sub.getAttribute("name"); // NOI18N + if (name.isEmpty()) { continue; } - String name = childName.getValue(); // NOI18N if (allNames.add(name)) { kids.add(name); - /* - } else { - if (warnedAboutDupeKids.add(location + ":" + f + "/" + name)) { // NOI18N - // #18699: will deadlock if you try to change anything. - if (f.equals("")) { // NOI18N - LayerDataNode.getErr().println("WARNING: in " + xmlfile + " the root folder contains the child " + name + " more than once."); - } else { - LayerDataNode.getErr().println("WARNING: in " + xmlfile + " the folder " + f + " contains the child " + name + " more than once."); - } - //LayerDataNode.getErr().println("The Open APIs Support module will not work properly with such a layer."); - //LayerDataNode.getErr().println("Please edit the XML text and merge together all children of a with the same name."); - } - */ } } } @@ -281,21 +250,24 @@ /** retrieve byte contents of a named resource */ private byte[] getContentsOf(final String name) throws FileNotFoundException { - TreeElement el = findElement(name); - if (el == null) throw new FileNotFoundException(name); - TreeAttribute urlAttr = el.getAttribute("url"); // NOI18N - if (urlAttr != null) { + Element el = findElement(name); + if (el == null) { + throw new FileNotFoundException(name); + } + String sURL = el.getAttribute("url"); // NOI18N + if (!sURL.isEmpty()) { try { - String sURL = urlAttr.getValue(); URI uri = new URI(null, sURL, null); boolean nbmRelative = sURL.startsWith("nbres:") || sURL.startsWith("nbresloc:"); URL url = nbmRelative ? uri.toURL() : new URL(location, uri.getRawPath()); - URL[] u = LayerUtils.currentify(url, suffix, classpath); + URL[] u = LayerUtils.currentify(url, "", classpath); URLConnection conn = u[0].openConnection(); conn.connect(); InputStream is = conn.getInputStream(); byte[] buf = new byte[conn.getContentLength()]; - if (is.read(buf) != buf.length) throw new IOException("wrong content length"); // NOI18N + if (is.read(buf) != buf.length) { + throw new IOException("wrong content length"); + } // Also listen to changes in it. FileObject fo = URLMapper.findFileObject(u[0]); if (fo != null) { @@ -309,14 +281,12 @@ throw new FileNotFoundException(use.getMessage()); } } else { - StringBuffer buf = new StringBuffer(); - Iterator it = el.getChildNodes().iterator(); - while (it.hasNext()) { - Object o = it.next(); - if (o instanceof TreeCDATASection) { - buf.append(((TreeCDATASection) o).getData()); - } else if (o instanceof TreeText) { - buf.append(((TreeText) o).getData().trim()); + StringBuilder buf = new StringBuilder(); + NodeList nl = el.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + Node n = nl.item(i); + if (n.getNodeType() == Node.CDATA_SECTION_NODE || n.getNodeType() == Node.TEXT_NODE) { + buf.append(((CharacterData) n).getData()); } } try { @@ -331,18 +301,17 @@ // [PENDING] should I/O from/to external text files be done via EditorCookie? // Not clear if this is safe (call from FS -> DS) even tho in separate FSs... - public InputStream inputStream(String name) throws FileNotFoundException { + public @Override InputStream inputStream(String name) throws FileNotFoundException { return new ByteArrayInputStream(getContentsOf(name)); } - public OutputStream outputStream(final String name) throws IOException { - final TreeElement el = findElement(name); + public @Override OutputStream outputStream(final String name) throws IOException { + final Element el = findElement(name); if (el == null) { throw new FileNotFoundException(name); } - TreeAttribute urlAttr = el.getAttribute("url"); // NOI18N - if (urlAttr != null) { - String u = urlAttr.getValue(); + String u = el.getAttribute("url"); // NOI18N + if (!u.isEmpty()) { if (URI.create(u).isAbsolute()) { // What to do? Can't overwrite it, obviously. throw new IOException(name); @@ -356,7 +325,7 @@ } // We will change the layer file. return new ByteArrayOutputStream() { - public void close() throws IOException { + public @Override void close() throws IOException { super.close(); final byte[] contents = toByteArray(); /* If desired to kill any existing inline content: @@ -380,7 +349,7 @@ final String externalName = LayerUtils.findGeneratedName(parent, name); assert externalName.indexOf('/') == -1 : externalName; parent.getFileSystem().runAtomicAction(new AtomicAction() { - public void run() throws IOException { + public @Override void run() throws IOException { FileObject externalFile = parent.createData(externalName); OutputStream os = externalFile.getOutputStream(); try { @@ -391,13 +360,7 @@ externalFile.addFileChangeListener(fileChangeListener); } }); - try { - el.addAttribute("url", externalName); // NOI18N - } catch (ReadOnlyException e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } catch (InvalidArgumentException e) { - assert false : e; - } + model.setAttribute((org.netbeans.modules.xml.xdm.nodes.Element) el, "url", externalName); // NOI18N } }; } @@ -422,52 +385,44 @@ parentName = name.substring(0, idx); baseName = name.substring(idx + 1); } - TreeElement el = findElement(parentName); + Element el = findElement(parentName); if (el == null) { throw new FileNotFoundException(parentName); } - try { - TreeElement nue = new TreeElement(folder ? "folder" : "file", true); // NOI18N - nue.addAttribute("name", baseName); // NOI18N - appendWithIndent(el, nue); - } catch (InvalidArgumentException e) { - assert false : e; - } catch (ReadOnlyException e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } + Element nue = el.getOwnerDocument().createElement(folder ? "folder" : "file"); // NOI18N + nue.setAttribute("name", baseName); // NOI18N + model.insertBefore((org.netbeans.modules.xml.xdm.nodes.Node) el, + (org.netbeans.modules.xml.xdm.nodes.Node) nue, + (org.netbeans.modules.xml.xdm.nodes.Node) findInsertionPosition(el, nue)); } - public void createFolder(String name) throws IOException { + public @Override void createFolder(String name) throws IOException { createFileOrFolder(name, true); } - public void createData(String name) throws IOException { + public @Override void createData(String name) throws IOException { createFileOrFolder(name, false); } - public void delete(String name) throws IOException { - TreeElement el = findElement(name); + public @Override void delete(String name) throws IOException { + Element el = findElement(name); if (el == null) { throw new FileNotFoundException(name); } - TreeAttribute externalName = el.getAttribute("url"); // NOI18N - if (externalName != null && !URI.create(externalName.getValue()).isAbsolute()) { + String externalName = el.getAttribute("url"); // NOI18N + if (!externalName.isEmpty() && !URI.create(externalName).isAbsolute()) { // Delete the external file if it can be found. - FileObject externalFile = URLMapper.findFileObject(new URL(location, externalName.getValue())); + FileObject externalFile = URLMapper.findFileObject(new URL(location, externalName)); if (externalFile != null) { externalFile.removeFileChangeListener(fileChangeListener); externalFile.delete(); } } - try { - deleteWithIndent((TreeChild) el); - } catch (ReadOnlyException e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } + model.removeChildNodes((org.netbeans.modules.xml.xdm.nodes.Node) el.getParentNode(), Collections.singleton((org.netbeans.modules.xml.xdm.nodes.Node) el)); } - public void rename(String oldName, String newName) throws IOException { - TreeElement el = findElement(oldName); + public @Override void rename(String oldName, String newName) throws IOException { + Element el = findElement(oldName); if (el == null) { throw new FileNotFoundException(oldName); } @@ -478,108 +433,29 @@ String newBaseName = newName.substring(idx); assert newBaseName.indexOf('/') == -1; assert newBaseName.length() > 0; - try { - el.getAttribute("name").setValue(newBaseName); // NOI18N - } catch (ReadOnlyException e) { - throw (IOException) new IOException(e.toString()).initCause(e); - } catch (InvalidArgumentException e) { - assert false : e; - } + model.setAttribute((org.netbeans.modules.xml.xdm.nodes.Element) el, "name", newBaseName); // NOI18N } - /* - public boolean copy(String name, Transfer target, String targetName) throws IOException { - if (! (target instanceof WritableXMLFileSystem)) return false; - WritableXMLFileSystem otherfs = (WritableXMLFileSystem) target; + public @Override Enumeration attributes(String name) { Element el = findElement(name); - if (el == null) throw new FileNotFoundException(name); - Element el2; - if (otherfs == this) { - el2 = (Element) el.cloneNode(true); - } else { - el2 = (Element) otherfs.doc.importNode(el, true); - } - String path, base; - int idx = targetName.lastIndexOf('/'); - if (idx == -1) { - path = ""; // NOI18N - base = targetName; - } else { - path = targetName.substring(0, idx); - base = targetName.substring(idx + 1); - } - Element parent = otherfs.findElement(path); - if (parent == null) throw new FileNotFoundException(path); - el2.setAttribute("name", base); // NOI18N - Element old = otherfs.findElement(targetName); - if (old != null) { - parent.replaceChild(el2, old); - } else { - appendWithIndent(parent, el2); - } - return true; - } - - public boolean move(String name, Transfer target, String targetName) throws IOException { - if (! (target instanceof WritableXMLFileSystem)) return false; - WritableXMLFileSystem otherfs = (WritableXMLFileSystem) target; - Element el = findElement(name); - if (el == null) throw new FileNotFoundException(name); - Element el2; - if (otherfs == this) { - // Just move it, no need to clone. - el2 = el; - } else { - el2 = (Element) otherfs.doc.importNode(el, true); - } - String path, base; - int idx = targetName.lastIndexOf('/'); - if (idx == -1) { - path = ""; // NOI18N - base = targetName; - } else { - path = targetName.substring(0, idx); - base = targetName.substring(idx + 1); - } - Element parent = otherfs.findElement(path); - if (parent == null) throw new FileNotFoundException(path); - el2.setAttribute("name", base); // NOI18N - Element old = otherfs.findElement(targetName); - if (el != el2) { - // Cross-document import, so need to remove old one. - el.getParentNode().removeChild(el); - } - if (old != null) { - parent.replaceChild(el2, old); - } else { - appendWithIndent(parent, el2); - } - return true; - } - */ - - public Enumeration attributes(String name) { - TreeElement el = findElement(name); if (el == null) { return Enumerations.empty(); } java.util.List l = new ArrayList(10); - Iterator it = el.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement sub = (TreeElement) it.next(); - if (sub.getLocalName().equals("attr")) { // NOI18N - TreeAttribute nameAttr = sub.getAttribute("name"); // NOI18N - if (nameAttr == null) { + for (Element sub : XMLUtil.findSubElements(el)) { + if (sub.getTagName().equals("attr")) { // NOI18N + String nameAttr = sub.getAttribute("name"); // NOI18N + if (nameAttr.isEmpty()) { // Malformed. continue; } - l.add(nameAttr.getValue()); + l.add(nameAttr); } } return Collections.enumeration(l); } - public Object readAttribute(String name, String attrName) { + public @Override Object readAttribute(String name, String attrName) { if (attrName.equals("WritableXMLFileSystem.cp")) { // NOI18N // XXX currently unused return classpath; @@ -589,9 +465,9 @@ return new URL[] {location}; } if (attrName.equals("DataFolder.Index.reorderable")) { // NOI18N - return Boolean.TRUE; + return true; // XXX is this still needed? } - TreeElement el = findElement(name); + Element el = findElement(name); if (el == null) { return null; } @@ -600,29 +476,22 @@ attrName = attrName.substring("literal:".length()); // NOI18N literal = true; } - Iterator it = el.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement sub = (TreeElement) it.next(); - if (!sub.getLocalName().equals("attr")) { // NOI18N + for (Element sub : XMLUtil.findSubElements(el)) { + if (!sub.getTagName().equals("attr")) { // NOI18N continue; } - TreeAttribute nameAttr = sub.getAttribute("name"); // NOI18N - if (nameAttr == null) { - // Malformed. - continue; - } - if (!attrName.equals(nameAttr.getValue())) { + if (!attrName.equals(sub.getAttribute("name"))) { // NOI18N continue; } try { - if ((nameAttr = sub.getAttribute("stringvalue")) != null) { // NOI18N + String val = sub.getAttribute("stringvalue"); // NOI18N + if (!val.isEmpty()) { // Stolen from XMLMapAttr, with tweaks: - String inStr = nameAttr.getValue(); - StringBuffer outStr = new StringBuffer(inStr.length()); - for (int j = 0; j < inStr.length(); j++) { - char ch = inStr.charAt(j); - if (ch == '\\' && inStr.charAt(j + 1) == 'u' && j + 5 < inStr.length()) { - String hex = inStr.substring(j + 2, j + 6); + StringBuilder outStr = new StringBuilder(val.length()); + for (int j = 0; j < val.length(); j++) { + char ch = val.charAt(j); + if (ch == '\\' && val.charAt(j + 1) == 'u' && j + 5 < val.length()) { + String hex = val.substring(j + 2, j + 6); try { outStr.append((char) Integer.parseInt(hex, 16)); j += 5; @@ -635,36 +504,36 @@ } } return outStr.toString(); - } else if ((nameAttr = sub.getAttribute("boolvalue")) != null) { // NOI18N - return Boolean.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("urlvalue")) != null) { // NOI18N - return new URL(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("charvalue")) != null) { // NOI18N - return new Character(nameAttr.getValue().charAt(0)); - } else if ((nameAttr = sub.getAttribute("bytevalue")) != null) { // NOI18N - return Byte.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("shortvalue")) != null) { // NOI18N - return Short.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("intvalue")) != null) { // NOI18N - return Integer.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("longvalue")) != null) { // NOI18N - return Long.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("floatvalue")) != null) { // NOI18N - return Float.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("doublevalue")) != null) { // NOI18N - return Double.valueOf(nameAttr.getValue()); - } else if ((nameAttr = sub.getAttribute("newvalue")) != null) { // NOI18N - String clazz = nameAttr.getValue(); + } else if (!(val = sub.getAttribute("boolvalue")).isEmpty()) { // NOI18N + return Boolean.valueOf(val); + } else if (!(val = sub.getAttribute("urlvalue")).isEmpty()) { // NOI18N + return new URL(val); + } else if (!(val = sub.getAttribute("charvalue")).isEmpty()) { // NOI18N + return Character.valueOf(val.charAt(0)); + } else if (!(val = sub.getAttribute("bytevalue")).isEmpty()) { // NOI18N + return Byte.valueOf(val); + } else if (!(val = sub.getAttribute("shortvalue")).isEmpty()) { // NOI18N + return Short.valueOf(val); + } else if (!(val = sub.getAttribute("intvalue")).isEmpty()) { // NOI18N + return Integer.valueOf(val); + } else if (!(val = sub.getAttribute("longvalue")).isEmpty()) { // NOI18N + return Long.valueOf(val); + } else if (!(val = sub.getAttribute("floatvalue")).isEmpty()) { // NOI18N + return Float.valueOf(val); + } else if (!(val = sub.getAttribute("doublevalue")).isEmpty()) { // NOI18N + return Double.valueOf(val); + } else if (!(val = sub.getAttribute("newvalue")).isEmpty()) { // NOI18N + String clazz = val; if (literal) { return "new:" + clazz; // NOI18N } // else XXX - } else if ((nameAttr = sub.getAttribute("methodvalue")) != null) { // NOI18N - String clazz = nameAttr.getValue(); + } else if (!(val = sub.getAttribute("methodvalue")).isEmpty()) { // NOI18N + String clazz = val; if (literal) { return "method:" + clazz; // NOI18N } // else XXX - } else if ((nameAttr = sub.getAttribute("bundlevalue")) != null) { // NOI18N - String bundle = nameAttr.getValue(); + } else if (!(val = sub.getAttribute("bundlevalue")).isEmpty()) { // NOI18N + String bundle = val; if (literal) { return "bundle:" + bundle; // NOI18N } else { @@ -680,22 +549,6 @@ } return null; /* - if ((v = sub.getAttributeNode("bytevalue")) != null) { // NOI18N - return new Byte(v.getValue()); - } else if ((v = sub.getAttributeNode("shortvalue")) != null) { // NOI18N - return new Short(v.getValue()); - } else if ((v = sub.getAttributeNode("intvalue")) != null) { // NOI18N - return new Integer(v.getValue()); - } else if ((v = sub.getAttributeNode("longvalue")) != null) { // NOI18N - return new Long(v.getValue()); - } else if ((v = sub.getAttributeNode("floatvalue")) != null) { // NOI18N - return new Float(v.getValue()); - } else if ((v = sub.getAttributeNode("doublevalue")) != null) { // NOI18N - // When was the last time you set a file attribute to a double?! - // Useless list of primitives... - return new Double(v.getValue()); - } else if ((v = sub.getAttributeNode("charvalue")) != null) { // NOI18N - return new Character(v.getValue().charAt(0)); } else if ((v = sub.getAttributeNode("methodvalue")) != null) { // NOI18N String value = v.getValue(); Object[] params = new Object[] { findResource(name), attrName }; @@ -812,113 +665,82 @@ */ } - public void writeAttribute(String name, String attrName, Object v) throws IOException { + public @Override void writeAttribute(String name, String attrName, Object v) throws IOException { //System.err.println("wA: " + name + " " + attrName + " " + v); if (v != null && v.getClass().getName().equals("org.openide.filesystems.MultiFileObject$VoidValue")) { // NOI18N // XXX is this legitimate? Definitely not pretty. But needed for testOpenideFolderOrder to pass. v = null; } - TreeElement el = findElement(name); + Element el = findElement(name); if (el == null) { throw new FileNotFoundException(name); } // Find any existing . - TreeChild existingAttr = null; - Iterator it = el.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement sub = (TreeElement) it.next(); - if (sub.getLocalName().equals("attr")) { // NOI18N - TreeAttribute attr = sub.getAttribute("name"); // NOI18N - if (attr == null) { - // Malformed. - continue; - } - if (attr.getValue().equals(attrName)) { - existingAttr = sub; - break; - } + Element existingAttr = null; + for (Element sub : XMLUtil.findSubElements(el)) { + if (sub.getTagName().equals("attr") && sub.getAttribute("name").equals(attrName)) { // NOI18N + existingAttr = sub; + break; } } - TreeElement attr; - try { - attr = new TreeElement("attr", true); // NOI18N - attr.addAttribute("name", attrName); // NOI18N - if (v instanceof String) { - String inStr = (String) v; - final String newValueMagic = "newvalue:"; // NOI18N - final String methodValueMagic = "methodvalue:"; // NOI18N - final String bundleValueMagic = "bundlevalue:"; // NOI18N - if (inStr.startsWith(newValueMagic)) { - // Impossible to set this (reliably) as a real value, so use this magic technique instead: - attr.addAttribute("newvalue", inStr.substring(newValueMagic.length())); // NOI18N - } else if (inStr.startsWith(methodValueMagic)) { - // Same here: - attr.addAttribute("methodvalue", inStr.substring(methodValueMagic.length())); // NOI18N - } else if (inStr.startsWith(bundleValueMagic)) { - // Same here: - attr.addAttribute("bundlevalue", inStr.substring(bundleValueMagic.length())); // NOI18N - TreeObjectList nodes = doc.getChildNodes(); - for (int i = 0; i < nodes.size(); i++) { - Object object = nodes.get(i); - if (object instanceof TreeDocumentType) { - TreeDocumentType tdt = (TreeDocumentType)object; - tdt.setPublicId("-//NetBeans//DTD Filesystem 1.2//EN"); - tdt.setSystemId("http://www.netbeans.org/dtds/filesystem-1_2.dtd"); - break; - } + Element attrE = el.getOwnerDocument().createElement("attr"); // NOI18N + attrE.setAttribute("name", attrName); // NOI18N + if (v instanceof String) { + String inStr = (String) v; + final String newValueMagic = "newvalue:"; // NOI18N + final String methodValueMagic = "methodvalue:"; // NOI18N + final String bundleValueMagic = "bundlevalue:"; // NOI18N + if (inStr.startsWith(newValueMagic)) { + // Impossible to set this (reliably) as a real value, so use this magic technique instead: + attrE.setAttribute("newvalue", inStr.substring(newValueMagic.length())); // NOI18N + } else if (inStr.startsWith(methodValueMagic)) { + // Same here: + attrE.setAttribute("methodvalue", inStr.substring(methodValueMagic.length())); // NOI18N + } else if (inStr.startsWith(bundleValueMagic)) { + // Same here: + attrE.setAttribute("bundlevalue", inStr.substring(bundleValueMagic.length())); // NOI18N + /* XXX figure out how to set DOCTYPE: + el.getOwnerDocument().getDoctype().setPublicId("-//NetBeans//DTD Filesystem 1.2//EN"); + el.getOwnerDocument().getDoctype().setSystemId("http://www.netbeans.org/dtds/filesystem-1_2.dtd"); + */ + } else { + // Regular string value. + // Stolen from XMLMapAttr w/ mods: + StringBuilder outStr = new StringBuilder(); + for (int i = 0; i < inStr.length(); i++) { + char c = inStr.charAt(i); + if (Character.isISOControl(c) || c == '&' || c == '<' || c == '>' || c == '"' || c == '\'') { + outStr.append(encodeChar(c)); + } else { + outStr.append(c); } - } else { - // Regular string value. - // Stolen from XMLMapAttr w/ mods: - StringBuffer outStr = new StringBuffer(); - for (int i = 0; i < inStr.length(); i++) { - char c = inStr.charAt(i); - if (Character.isISOControl(c) || c == '&' || c == '<' || c == '>' || c == '"' || c == '\'') { - outStr.append(encodeChar(c)); - } else { - outStr.append(c); - } - } - attr.addAttribute("stringvalue", outStr.toString()); // NOI18N } - } else if (v instanceof URL) { - attr.addAttribute("urlvalue", ((URL) v).toExternalForm()); // NOI18N - } else if (v instanceof Boolean) { - attr.addAttribute("boolvalue", v.toString()); // NOI18N - } else if (v instanceof Character) { - attr.addAttribute("charvalue", v.toString()); // NOI18N - } else if (v instanceof Integer) { - attr.addAttribute("intvalue", v.toString()); // NOI18N - } else if (v != null) { - throw new UnsupportedOperationException("XXX: " + v); // NOI18N + attrE.setAttribute("stringvalue", outStr.toString()); // NOI18N } - if (v != null && existingAttr == null) { - appendWithIndent(el, attr); - } else if (v != null) { - ((TreeParentNode) el).replaceChild(existingAttr, attr); - } else if (existingAttr != null) { - deleteWithIndent(existingAttr); - } - } catch (InvalidArgumentException e) { - throw new AssertionError(e); - } catch (ReadOnlyException e) { - throw (IOException) new IOException(e.toString()).initCause(e); + } else if (v instanceof URL) { + attrE.setAttribute("urlvalue", ((URL) v).toExternalForm()); // NOI18N + } else if (v instanceof Boolean) { + attrE.setAttribute("boolvalue", v.toString()); // NOI18N + } else if (v instanceof Character) { + attrE.setAttribute("charvalue", v.toString()); // NOI18N + } else if (v instanceof Integer) { + attrE.setAttribute("intvalue", v.toString()); // NOI18N + } else if (v != null) { + throw new UnsupportedOperationException("XXX: " + v); // NOI18N + } + if (v != null && existingAttr == null) { + model.insertBefore((org.netbeans.modules.xml.xdm.nodes.Node) el, + (org.netbeans.modules.xml.xdm.nodes.Node) attrE, + (org.netbeans.modules.xml.xdm.nodes.Node) findInsertionPosition(el, attrE)); + } else if (v != null) { + model.replaceChild((org.netbeans.modules.xml.xdm.nodes.Node) el, + (org.netbeans.modules.xml.xdm.nodes.Node) attrE, + (org.netbeans.modules.xml.xdm.nodes.Node) existingAttr); + } else if (existingAttr != null) { + model.removeChildNodes((org.netbeans.modules.xml.xdm.nodes.Node) el, + Collections.singleton((org.netbeans.modules.xml.xdm.nodes.Node) existingAttr)); } /* - if (v instanceof Byte) { - attr.setAttribute("bytevalue", v.toString()); // NOI18N - } else if (v instanceof Short) { - attr.setAttribute("shortvalue", v.toString()); // NOI18N - } else if (v instanceof Integer) { - attr.setAttribute("intvalue", v.toString()); // NOI18N - } else if (v instanceof Long) { - attr.setAttribute("longvalue", v.toString()); // NOI18N - } else if (v instanceof Float) { - attr.setAttribute("floatvalue", v.toString()); // NOI18N - } else if (v instanceof Double) { - attr.setAttribute("doublevalue", v.toString()); // NOI18N - } else if (v instanceof Character) { - attr.setAttribute("charvalue", v.toString()); // NOI18N } else { // Stolen from XMLMapAttr, mostly. ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -1000,23 +822,23 @@ return "\\u" + "0000".substring(0, "0000".length() - encChar.length()).concat(encChar); // NOI18N } - public void renameAttributes(String oldName, String newName) { + public @Override void renameAttributes(String oldName, String newName) { // do nothing } - public void deleteAttributes(String name) { + public @Override void deleteAttributes(String name) { // do nothing } - public boolean readOnly(String name) { + public @Override boolean readOnly(String name) { return false; } - public String mimeType(String name) { + public @Override String mimeType(String name) { return null; // i.e. use default resolvers } - public long size(String name) { + public @Override long size(String name) { try { return getContentsOf(name).length; } catch (FileNotFoundException fnfe) { @@ -1024,20 +846,19 @@ } } - public void markUnimportant(String name) { + public @Override void markUnimportant(String name) { // do nothing } - public Date lastModified(String name) { - final TreeElement el = findElement(name); + public @Override Date lastModified(String name) { + final Element el = findElement(name); if (el == null) { return new Date(0L); } - TreeAttribute attr = el.getAttribute("url"); // NOI18N - if (attr == null) { + String u = el.getAttribute("url"); // NOI18N + if (u.isEmpty()) { return new Date(0L); } - String u = attr.getValue(); URI uri = null; try { uri = new URI(null, u, null); @@ -1063,55 +884,16 @@ // These are not important for us: - public void lock(String name) throws IOException { + public @Override void lock(String name) throws IOException { // [PENDING] should this try to lock the XML document?? // (not clear if it is safe to do so from FS call, even tho // on a different FS) } - public void unlock(String name) { + public @Override void unlock(String name) { // do nothing } - // don't bother making configurable; or could use an indentation engine - private static final int INDENT_STEP = 4; - /** - * Add a new element to a parent in the correct position. - * Inserts whitespace to retain indentation rules. - */ - private static void appendWithIndent(TreeElement parent, TreeChild child) throws ReadOnlyException { - TreeParentNode doc = parent; - int depth = -2; // will get then TreeDocument then null - while (doc != null) { - doc = ((TreeChild) doc).getParentNode(); - depth++; - } - TreeChild position = insertBefore(parent, child); - try { - if (position != null) { - parent.insertBefore(child, position); - parent.insertBefore(new TreeText("\n" + spaces((depth + 1) * INDENT_STEP)), position); // NOI18N - } else { - if (/*XXX this is clumsy*/ parent.hasChildNodes()) { - parent.appendChild(new TreeText(spaces(INDENT_STEP))); - } else { - parent.appendChild(new TreeText("\n" + spaces((depth + 1) * INDENT_STEP))); // NOI18N - } - parent.appendChild(child); - parent.appendChild(new TreeText("\n" + spaces(depth * INDENT_STEP))); // NOI18N - } - parent.normalize(); - /* XXX could check for adding position attr and resort parent of parent? - TreeElement childe = (TreeElement) child; - if (childe.getQName().equals("attr") && childe.getAttribute("name").getValue().indexOf('/') != -1) { // NOI18N - // Check for ordering attributes, which we have to handle specially. - resort(parent); - } - */ - } catch (InvalidArgumentException e) { - assert false : e; - } - } /** * Find the proper location for a newly inserted element. * Rules: @@ -1119,269 +901,51 @@ * 2. must be added to top of element in alpha order w.r.t. existing ones. * Returns a position to insert before (null for end). */ - private static TreeChild insertBefore(TreeElement parent, TreeChild child) throws ReadOnlyException { - if (!(child instanceof TreeElement)) { - return null; // TBD for now - } - TreeElement childe = (TreeElement) child; - if (childe.getQName().equals("file") || childe.getQName().equals("folder")) { // NOI18N - String name = childe.getAttribute("name").getValue(); // NOI18N - Iterator it = parent.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement kid = (TreeElement) it.next(); - if (kid.getQName().equals("file") || kid.getQName().equals("folder")) { // NOI18N - TreeAttribute attr = kid.getAttribute("name"); // NOI18N - if (attr != null) { // #66816 - layer might be malformed - String kidname = attr.getValue(); - if (kidname.compareTo(name) > 0) { - return kid; - } - } + private static Element findInsertionPosition(Element parent, Element child) { + if (child.getTagName().equals("file") || child.getTagName().equals("folder")) { // NOI18N + String name = child.getAttribute("name"); // NOI18N + for (Element kid : XMLUtil.findSubElements(parent)) { + if ((kid.getTagName().equals("file") || kid.getTagName().equals("folder")) && kid.getAttribute("name").compareTo(name) > 0) { // NOI18N + return kid; } } return null; - } else if (childe.getQName().equals("attr")) { // NOI18N - String name = childe.getAttribute("name").getValue(); // NOI18N - Iterator it = parent.getChildNodes(TreeElement.class).iterator(); - while (it.hasNext()) { - TreeElement kid = (TreeElement) it.next(); - if (kid.getQName().equals("file") || kid.getQName().equals("folder")) { // NOI18N + } else if (child.getTagName().equals("attr")) { // NOI18N + String name = child.getAttribute("name"); // NOI18N + for (Element kid : XMLUtil.findSubElements(parent)) { + if (kid.getTagName().equals("file") || kid.getTagName().equals("folder")) { // NOI18N return kid; - } else if (kid.getQName().equals("attr")) { // NOI18N - TreeAttribute attr = kid.getAttribute("name"); // NOI18N - if (attr != null) { - String kidname = attr.getValue(); - if (kidname.compareTo(name) > 0) { - return kid; - } - } - } else { - throw new AssertionError("Weird child: " + kid.getQName()); + } else if (kid.getTagName().equals("attr") && kid.getAttribute("name").compareTo(name) > 0) { // NOI18N + return kid; } } return null; } else { - throw new AssertionError("Weird child: " + childe.getQName()); + throw new AssertionError("Weird child: " + child.getTagName()); } } - /** - * Resort all files and folders and attributes in a folder context. The order is: - * 1. Attributes are alpha-sorted at the top. - * 2. Files and folders are alpha-sorted if they have no position. - * 3. Files with positions are sorted numerically above files without. - */ - /* XXX not important yet - private static void resort(TreeElement parent) throws ReadOnlyException { - class Item { - public TreeElement child; - boolean isAttr() { - return child.getQName().equals("attr"); // NOI18N - } - String getName() { - TreeAttribute attr = child.getAttribute("name"); // NOI18N - return attr != null ? attr.getValue() : ""; - } - boolean isOrderingAttr() { - return isAttr() && getName().indexOf('/') != -1; - } - String getFormer() { - String n = getName(); - return n.substring(0, n.indexOf('/')); - } - String getLatter() { - String n = getName(); - return n.substring(n.indexOf('/') + 1); - } - } - Set items = new LinkedHashSet(); - SortedSet indices = new TreeSet(); - for (int i = 0; i < parent.getChildrenNumber(); i++) { - TreeChild child = (TreeChild) parent.getChildNodes().get(i); - if (child instanceof TreeElement) { - Item item = new Item(); - item.child = (TreeElement) child; - items.add(item); - indices.add(new Integer(i)); - } - } - Map> edges = new LinkedHashMap(); - Map filesAndFolders = new LinkedHashMap(); - Map attrs = new LinkedHashMap(); - Set orderedFilesAndFolders = new LinkedHashSet(); - Iterator it = items.iterator(); - while (it.hasNext()) { - Item item = (Item) it.next(); - String name = item.getName(); - if (item.isAttr()) { - attrs.put(name, item); - if (item.isOrderingAttr()) { - orderedFilesAndFolders.add(item.getFormer()); - orderedFilesAndFolders.add(item.getLatter()); - } - } else { - filesAndFolders.put(name, item); - } - } - class NameComparator implements Comparator { - public int compare(Object o1, Object o2) { - Item i1 = (Item) o1; - Item i2 = (Item) o2; - return i1.getName().compareTo(i2.getName()); - } - } - Set sortedAttrs = new TreeSet(new NameComparator()); - Set sortedFilesAndFolders = new TreeSet(new NameComparator()); - Set orderableItems = new LinkedHashSet(); - it = items.iterator(); - while (it.hasNext()) { - Item item = (Item) it.next(); - String name = item.getName(); - if (item.isAttr()) { - if (item.isOrderingAttr()) { - Item former = (Item) filesAndFolders.get(item.getFormer()); - if (former != null) { - Set formerConstraints = (Set) edges.get(former); - if (formerConstraints == null) { - formerConstraints = new LinkedHashSet(); - edges.put(former, formerConstraints); - } - formerConstraints.add(item); - } - Item latter = (Item) filesAndFolders.get(item.getLatter()); - if (latter != null) { - Set constraints = new LinkedHashSet(); - constraints.add(latter); - edges.put(item, constraints); - } - orderableItems.add(item); - } else { - sortedAttrs.add(item); - } - } else { - if (orderedFilesAndFolders.contains(name)) { - orderableItems.add(item); - } else { - sortedFilesAndFolders.add(item); - } - } - } - java.util.List orderedItems; - try { - orderedItems = Utilities.topologicalSort(orderableItems, edges); - } catch (TopologicalSortException e) { - // OK, ignore. - return; - } - it = items.iterator(); - while (it.hasNext()) { - Item item = (Item) it.next(); - parent.removeChild(item.child); - } - java.util.List allOrderedItems = new ArrayList(sortedAttrs); - allOrderedItems.addAll(orderedItems); - allOrderedItems.addAll(sortedFilesAndFolders); - assert new HashSet(allOrderedItems).equals(items); - it = allOrderedItems.iterator(); - Iterator indexIt = indices.iterator(); - while (it.hasNext()) { - Item item = (Item) it.next(); - int index = ((Integer) indexIt.next()).intValue(); - parent.insertChildAt(item.child, index); - } - } - */ - private static String spaces(int size) { - char[] chars = new char[size]; - for (int i = 0; i < size; i++) { - chars[i] = ' '; - } - return new String(chars); - } - /** - * Remove an element (and its children), deleting any surrounding newlines and indentation too. - */ - private static void deleteWithIndent(TreeChild child) throws ReadOnlyException { - TreeChild next = child.getNextSibling(); - // XXX better might be to delete any maximal [ \t]+ previous plus \n next (means splitting up TreeText's) - if (next instanceof TreeText && ((TreeText) next).getData().matches("(\r|\n|\r\n)[ \t]+")) { // NOI18N - next.removeFromContext(); - } else { - TreeChild previous = child.getPreviousSibling(); - if (previous instanceof TreeText && ((TreeText) previous).getData().matches("(\r|\n|\r\n)[ \t]+")) { // NOI18N - previous.removeFromContext(); - } else { - // Well, not sure what is here, so skip it. - } - } - TreeElement parent = (TreeElement) child.getParentNode(); - TreeObjectList list = parent.getChildNodes(); - boolean kill = true; - Iterator it = list.iterator(); - while (it.hasNext()) { - Object o = it.next(); - if (o == child) { - continue; - } - if (!(o instanceof TreeText)) { - kill = false; - break; - } - if (((TreeText) o).getData().trim().length() > 0) { - kill = false; - break; - } - } - if (kill) { - try { - // Special case for root of filesystem. - if (((TreeChild) parent).getParentNode() instanceof TreeDocumentRoot) { - it = list.iterator(); - while (it.hasNext()) { - ((TreeChild) it.next()).removeFromContext(); - } - parent.appendChild(new TreeText("\n")); // NOI18N - } else { - // Make sure we convert it to an empty tag (seems to only affect elements - // which were originally parsed?): - TreeElement parent2 = new TreeElement(parent.getQName(), true); - TreeAttribute attr = parent.getAttribute("name"); // NOI18N - if (attr != null) { - parent2.addAttribute("name", attr.getValue()); // NOI18N - } - TreeParentNode grandparent = ((TreeChild) parent).getParentNode(); - // TreeElement.empty is sticky - cannot be changed retroactively (argh!). - grandparent.replaceChild(parent, parent2); - parent = parent2; // for normalize() below - } - } catch (InvalidArgumentException e) { - assert false : e; - } - } - child.removeFromContext(); - parent.normalize(); - } // Listen to changes in files used as url= external contents. If these change, // the filesystem needs to show something else. Properly we would // keep track of *which* file changed and thus which of our resources // is affected. Practically this would be a lot of work and gain // very little. - public void fileDeleted(FileEvent fe) { + public @Override void fileDeleted(FileEvent fe) { someFileChange(); } - public void fileFolderCreated(FileEvent fe) { + public @Override void fileFolderCreated(FileEvent fe) { // does not apply to us } - public void fileDataCreated(FileEvent fe) { + public @Override void fileDataCreated(FileEvent fe) { // not interesting here } - public void fileAttributeChanged(FileAttributeEvent fe) { + public @Override void fileAttributeChanged(FileAttributeEvent fe) { // don't care about attributes on included files... } - public void fileRenamed(FileRenameEvent fe) { + public @Override void fileRenamed(FileRenameEvent fe) { someFileChange(); } - public void fileChanged(FileEvent fe) { + public @Override void fileChanged(FileEvent fe) { someFileChange(); } private void someFileChange() { @@ -1389,14 +953,14 @@ refreshResource("", true); } - public void propertyChange(PropertyChangeEvent evt) { - if (!evt.getPropertyName().equals(TreeEditorCookie.PROP_DOCUMENT_ROOT)) { - return; - } - if (cookie.getStatus() == TreeEditorCookie.STATUS_OK || cookie.getStatus() == TreeEditorCookie.STATUS_NOT) { + public @Override void propertyChange(PropertyChangeEvent evt) { + /* XXX do we need to synch periodically? + model.sync(); + */ + model.flush(); + // XXX if supporting external changes: + if (false/*model.getStatus() == XDMModel.Status.STABLE*/) { // Document was modified, and reparsed OK. See what changed. - try { - doc = cookie.openDocumentRoot(); /* Neither of the following work: refreshResource("", true); // only works on root folder refreshRoot(); // seems to do nothing at all @@ -1409,11 +973,6 @@ } //System.err.println("got changes; new files: " + Collections.list(getRoot().getChildren(true))); //Thread.dumpStack(); - } catch (TreeException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } catch (IOException e) { - Util.err.notify(ErrorManager.INFORMATIONAL, e); - } } } diff --git a/apisupport.project/test/unit/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystemTest.java b/apisupport.project/test/unit/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystemTest.java --- a/apisupport.project/test/unit/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystemTest.java +++ b/apisupport.project/test/unit/src/org/netbeans/modules/apisupport/project/layers/WritableXMLFileSystemTest.java @@ -56,7 +56,6 @@ import java.util.Set; import org.netbeans.junit.RandomlyFails; import org.netbeans.modules.apisupport.project.TestBase; -import org.netbeans.modules.apisupport.project.layers.LayerUtils.SavableTreeEditorCookie; import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.filesystems.FileAttributeEvent; import org.openide.filesystems.FileChangeListener; @@ -123,8 +122,7 @@ Layer orig = new Layer("", files); FileObject orgTest = FileUtil.createFolder(new File(orig.folder, "org/test")); FileObject lf = orig.f.copy(orgTest, "layer", "xml"); - SavableTreeEditorCookie cookie = LayerUtils.cookieForFile(lf); - FileSystem fs = new WritableXMLFileSystem(lf.getURL(), cookie, + FileSystem fs = new WritableXMLFileSystem(lf, ClassPathSupport.createClassPath(new FileObject[] { FileUtil.toFileObject(orig.folder) } )); FileObject x = fs.findResource("x"); assertNotNull(x); @@ -677,7 +675,7 @@ private final class Layer { private final File folder; private final FileObject f; - private LayerUtils.SavableTreeEditorCookie cookie; + private WritableXMLFileSystem fs; /** * Create a layer from a fixed bit of filesystem-DTD XML. * Omit the ... tag and just give the contents. @@ -731,8 +729,7 @@ * Read the filesystem from the layer. */ public WritableXMLFileSystem read() throws Exception { - cookie = LayerUtils.cookieForFile(f); - return new WritableXMLFileSystem(f.getURL(), cookie, null); + return fs = new WritableXMLFileSystem(f, null); } /** * Write the filesystem to the layer and retrieve the new contents. @@ -742,7 +739,7 @@ return write(HEADER, FOOTER); } String write(String head, String foot) throws Exception { - cookie.save(); + fs.save(); String raw = TestBase.slurp(f); for (int i = 1; i <= 2; i++) { diff --git a/xml.tax/nbproject/project.xml b/xml.tax/nbproject/project.xml --- a/xml.tax/nbproject/project.xml +++ b/xml.tax/nbproject/project.xml @@ -157,7 +157,6 @@ - org.netbeans.modules.apisupport.project org.netbeans.modules.xml.tools org.netbeans.modules.xml.tools.java org.netbeans.tax