Source Code Cross Referenced for WritableXMLFileSystem.java in  » IDE-Netbeans » api » org » netbeans » modules » apisupport » project » layers » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » api » org.netbeans.modules.apisupport.project.layers 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.modules.apisupport.project.layers;
0043:
0044:        import java.beans.PropertyChangeEvent;
0045:        import java.beans.PropertyChangeListener;
0046:        import java.io.ByteArrayInputStream;
0047:        import java.io.ByteArrayOutputStream;
0048:        import java.io.FileNotFoundException;
0049:        import java.io.FilterOutputStream;
0050:        import java.io.IOException;
0051:        import java.io.InputStream;
0052:        import java.io.NotSerializableException;
0053:        import java.io.ObjectOutputStream;
0054:        import java.io.OutputStream;
0055:        import java.io.UnsupportedEncodingException;
0056:        import java.net.MalformedURLException;
0057:        import java.net.URI;
0058:        import java.net.URL;
0059:        import java.net.URLConnection;
0060:        import java.util.ArrayList;
0061:        import java.util.Collections;
0062:        import java.util.Date;
0063:        import java.util.Enumeration;
0064:        import java.util.HashSet;
0065:        import java.util.Iterator;
0066:        import java.util.Set;
0067:        import org.netbeans.api.java.classpath.ClassPath;
0068:        import org.netbeans.modules.apisupport.project.Util;
0069:        import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie;
0070:        import org.netbeans.tax.InvalidArgumentException;
0071:        import org.netbeans.tax.ReadOnlyException;
0072:        import org.netbeans.tax.TreeAttribute;
0073:        import org.netbeans.tax.TreeCDATASection;
0074:        import org.netbeans.tax.TreeChild;
0075:        import org.netbeans.tax.TreeDocumentRoot;
0076:        import org.netbeans.tax.TreeElement;
0077:        import org.netbeans.tax.TreeException;
0078:        import org.netbeans.tax.TreeObjectList;
0079:        import org.netbeans.tax.TreeParentNode;
0080:        import org.netbeans.tax.TreeText;
0081:        import org.openide.ErrorManager;
0082:        import org.openide.filesystems.AbstractFileSystem;
0083:        import org.openide.filesystems.FileAttributeEvent;
0084:        import org.openide.filesystems.FileChangeListener;
0085:        import org.openide.filesystems.FileEvent;
0086:        import org.openide.filesystems.FileLock;
0087:        import org.openide.filesystems.FileObject;
0088:        import org.openide.filesystems.FileRenameEvent;
0089:        import org.openide.filesystems.FileUtil;
0090:        import org.openide.filesystems.URLMapper;
0091:        import org.openide.util.Enumerations;
0092:        import org.openide.util.WeakListeners;
0093:
0094:        /**
0095:         * A filesystem which is based on a TAX document and implements
0096:         * the same syntax as XMLFileSystem, from which inspiration is taken.
0097:         * Not implemented similarly to XMLFileSystem because this is writable
0098:         * and designed specifically to write human-readable XML and work nicely
0099:         * as an authoring tool. The filesystem expects to get an XML document
0100:         * according to DTD "-//NetBeans//DTD Filesystem 1.0//EN" (or 1.1 is OK).
0101:         * When it is changed via FileSystems API, it will fire TAX
0102:         * events. Not intended to be efficient or terribly robust, since it
0103:         * is development-time only.
0104:         * @author Jesse Glick
0105:         */
0106:        final class WritableXMLFileSystem extends AbstractFileSystem implements 
0107:                AbstractFileSystem.Attr, AbstractFileSystem.Change,
0108:                AbstractFileSystem.Info, AbstractFileSystem.List,
0109:                //AbstractFileSystem.Transfer,
0110:                FileChangeListener, PropertyChangeListener {
0111:
0112:            private final TreeEditorCookie cookie;
0113:            private TreeDocumentRoot doc; // may be null if malformed
0114:            private URL location;
0115:            private String suffix; // for branding/localization like "_f4j_ce_ja"; never null, at worst ""
0116:            private final FileChangeListener fileChangeListener;
0117:            private ClassPath classpath; // OK to be null
0118:
0119:            public WritableXMLFileSystem(URL location, TreeEditorCookie cookie,
0120:                    ClassPath classpath) {
0121:                this .attr = this ;
0122:                this .change = this ;
0123:                this .info = this ;
0124:                this .list = this ;
0125:                //this.transfer = this;
0126:                this .cookie = cookie;
0127:                try {
0128:                    doc = cookie.openDocumentRoot();
0129:                } catch (TreeException e) {
0130:                    Util.err.notify(ErrorManager.INFORMATIONAL, e);
0131:                } catch (IOException e) {
0132:                    Util.err.notify(ErrorManager.INFORMATIONAL, e);
0133:                }
0134:                fileChangeListener = FileUtil
0135:                        .weakFileChangeListener(this , null);
0136:                cookie.addPropertyChangeListener(WeakListeners.propertyChange(
0137:                        this , cookie));
0138:                setLocation(location);
0139:                setClasspath(classpath);
0140:            }
0141:
0142:            private void writeObject(ObjectOutputStream out) throws IOException {
0143:                throw new NotSerializableException(
0144:                        "WritableXMLFileSystem is not persistent"); // NOI18N
0145:            }
0146:
0147:            private void setLocation(URL location) {
0148:                String u = location.toExternalForm();
0149:                if (u.endsWith("/")) { // NOI18N
0150:                    throw new IllegalArgumentException(u);
0151:                }
0152:                this .location = location;
0153:            }
0154:
0155:            private void setClasspath(ClassPath classpath) {
0156:                this .classpath = classpath;
0157:            }
0158:
0159:            public String getDisplayName() {
0160:                FileObject fo = URLMapper.findFileObject(location);
0161:                if (fo != null) {
0162:                    return FileUtil.getFileDisplayName(fo);
0163:                } else {
0164:                    return location.toExternalForm();
0165:                }
0166:            }
0167:
0168:            public boolean isReadOnly() {
0169:                return false;
0170:            }
0171:
0172:            private TreeElement getRootElement() {
0173:                if (doc == null) {
0174:                    return null;
0175:                }
0176:                Iterator it;
0177:                it = doc.getChildNodes().iterator();
0178:                while (it.hasNext()) {
0179:                    Object next = it.next();
0180:                    if (next instanceof  TreeElement) {
0181:                        return (TreeElement) next;
0182:                    }
0183:                }
0184:                return null;
0185:            }
0186:
0187:            /** Given a resource name, find the matching DOM element.
0188:             * @return a <folder> or <file> or <filesystem> element, or null if file does not exist
0189:             */
0190:            private TreeElement findElement(String name) {
0191:                return findElementIn(getRootElement(), name);
0192:            }
0193:
0194:            /** helper method only */
0195:            private static TreeElement findElementIn(TreeElement el, String name) {
0196:                if (el == null)
0197:                    return null;
0198:                if (name.equals("")) { // NOI18N
0199:                    return el;
0200:                } else {
0201:                    int idx = name.indexOf('/');
0202:                    String nextName, remainder;
0203:                    if (idx == -1) {
0204:                        nextName = name;
0205:                        remainder = ""; // NOI18N
0206:                    } else {
0207:                        nextName = name.substring(0, idx);
0208:                        remainder = name.substring(idx + 1);
0209:                    }
0210:                    TreeElement subel = null;
0211:                    Iterator it = el.getChildNodes(TreeElement.class)
0212:                            .iterator();
0213:                    while (it.hasNext()) {
0214:                        TreeElement e = (TreeElement) it.next();
0215:                        if (e.getLocalName().equals("file") || // NOI18N
0216:                                e.getLocalName().equals("folder")) { // NOI18N
0217:                            TreeAttribute nameAttr = e.getAttribute("name"); // NOI18N
0218:                            if (nameAttr != null
0219:                                    && nameAttr.getValue().equals(nextName)) {
0220:                                subel = e;
0221:                                break;
0222:                            }
0223:                        }
0224:                    }
0225:                    return findElementIn(subel, remainder);
0226:                }
0227:            }
0228:
0229:            public boolean folder(String name) {
0230:                TreeElement el = findElement(name);
0231:                if (el == null) {
0232:                    //System.err.println("folder <" + name + ">: false, no such element");
0233:                    return false;
0234:                }
0235:                boolean res = el.getLocalName().equals("folder"); // NOI18N
0236:                //System.err.println("folder <" + name + ">: " + res);
0237:                return res;
0238:            }
0239:
0240:            /*
0241:            private static final Set warnedAboutDupeKids = new HashSet(1); // Set<String>
0242:             */
0243:            public String[] children(String f) {
0244:                TreeElement el = findElement(f);
0245:                if (el == null) {
0246:                    //System.err.println("children <" + f + ">: none, no such element");
0247:                    return new String[] {};
0248:                }
0249:                ArrayList<String> kids = new ArrayList<String>();
0250:                Set<String> allNames = new HashSet<String>();
0251:                Iterator it = el.getChildNodes(TreeElement.class).iterator();
0252:                while (it.hasNext()) {
0253:                    TreeElement sub = (TreeElement) it.next();
0254:                    if (sub.getLocalName().equals("file") || // NOI18N
0255:                            sub.getLocalName().equals("folder")) { // NOI18N
0256:                        TreeAttribute childName = sub.getAttribute("name"); // NOI18N
0257:                        if (childName == null) {
0258:                            continue;
0259:                        }
0260:                        String name = childName.getValue(); // NOI18N
0261:                        if (allNames.add(name)) {
0262:                            kids.add(name);
0263:                            /*
0264:                            } else {
0265:                            if (warnedAboutDupeKids.add(location + ":" + f + "/" + name)) { // NOI18N
0266:                            // #18699: will deadlock if you try to change anything.
0267:                            if (f.equals("")) { // NOI18N
0268:                                LayerDataNode.getErr().println("WARNING: in " + xmlfile + " the root folder contains the child " + name + " more than once.");
0269:                            } else {
0270:                                LayerDataNode.getErr().println("WARNING: in " + xmlfile + " the folder " + f + " contains the child " + name + " more than once.");
0271:                            }
0272:                            //LayerDataNode.getErr().println("The Open APIs Support module will not work properly with such a layer.");
0273:                            //LayerDataNode.getErr().println("Please edit the XML text and merge together all children of a <folder> with the same name.");
0274:                            }
0275:                             */
0276:                        }
0277:                    }
0278:                }
0279:                //System.err.println("children <" + f + ">: " + kids);
0280:                return kids.toArray(new String[kids.size()]);
0281:            }
0282:
0283:            /** retrieve byte contents of a named resource */
0284:            private byte[] getContentsOf(final String name)
0285:                    throws FileNotFoundException {
0286:                TreeElement el = findElement(name);
0287:                if (el == null)
0288:                    throw new FileNotFoundException(name);
0289:                TreeAttribute urlAttr = el.getAttribute("url"); // NOI18N
0290:                if (urlAttr != null) {
0291:                    try {
0292:                        URL[] u = LayerUtils.currentify(new URL(location,
0293:                                urlAttr.getValue()), suffix, classpath);
0294:                        URLConnection conn = u[0].openConnection();
0295:                        conn.connect();
0296:                        InputStream is = conn.getInputStream();
0297:                        byte[] buf = new byte[conn.getContentLength()];
0298:                        if (is.read(buf) != buf.length)
0299:                            throw new IOException("wrong content length"); // NOI18N
0300:                        // Also listen to changes in it.
0301:                        FileObject fo = URLMapper.findFileObject(u[0]);
0302:                        if (fo != null) {
0303:                            fo.removeFileChangeListener(fileChangeListener);
0304:                            fo.addFileChangeListener(fileChangeListener);
0305:                        }
0306:                        return buf;
0307:                    } catch (IOException ioe) {
0308:                        throw new FileNotFoundException(ioe.getMessage());
0309:                    }
0310:                } else {
0311:                    StringBuffer buf = new StringBuffer();
0312:                    Iterator it = el.getChildNodes().iterator();
0313:                    while (it.hasNext()) {
0314:                        Object o = it.next();
0315:                        if (o instanceof  TreeCDATASection) {
0316:                            buf.append(((TreeCDATASection) o).getData());
0317:                        } else if (o instanceof  TreeText) {
0318:                            buf.append(((TreeText) o).getData().trim());
0319:                        }
0320:                    }
0321:                    try {
0322:                        // This encoding is intentional...
0323:                        return buf.toString().getBytes("UTF-8"); // NOI18N
0324:                    } catch (UnsupportedEncodingException uee) {
0325:                        throw new FileNotFoundException(uee.getMessage());
0326:                    }
0327:                }
0328:            }
0329:
0330:            // [PENDING] should I/O from/to external text files be done via EditorCookie?
0331:            // Not clear if this is safe (call from FS -> DS) even tho in separate FSs...
0332:
0333:            public InputStream inputStream(String name)
0334:                    throws FileNotFoundException {
0335:                return new ByteArrayInputStream(getContentsOf(name));
0336:            }
0337:
0338:            public OutputStream outputStream(final String name)
0339:                    throws IOException {
0340:                final TreeElement el = findElement(name);
0341:                if (el == null) {
0342:                    throw new FileNotFoundException(name);
0343:                }
0344:                TreeAttribute urlAttr = el.getAttribute("url"); // NOI18N
0345:                if (urlAttr != null) {
0346:                    String u = urlAttr.getValue();
0347:                    if (URI.create(u).isAbsolute()) {
0348:                        // What to do? Can't overwrite it, obviously.
0349:                        throw new IOException(name);
0350:                    }
0351:                    // We have an existing external file. Try to write to that instead.
0352:                    FileObject external = URLMapper.findFileObject(new URL(
0353:                            location, u));
0354:                    if (external == null) {
0355:                        throw new FileNotFoundException(name);
0356:                    }
0357:                    final FileLock lock = external.lock();
0358:                    return new FilterOutputStream(external
0359:                            .getOutputStream(lock)) {
0360:                        public void close() throws IOException {
0361:                            super .close();
0362:                            lock.releaseLock();
0363:                        }
0364:                    };
0365:                }
0366:                // We will change the layer file.
0367:                return new ByteArrayOutputStream() {
0368:                    public void close() throws IOException {
0369:                        super .close();
0370:                        byte[] contents = toByteArray();
0371:                        /* If desired to kill any existing inline content:
0372:                        Iterator it = el.getChildNodes().iterator();
0373:                        ArrayList/ *<TreeCDATASection>* / allCdata = new ArrayList();
0374:                        while (it.hasNext()) {
0375:                            Object o = it.next();
0376:                            if (o instanceof TreeCDATASection) {
0377:                                allCdata.add(o);
0378:                            } else if (o instanceof TreeText &&
0379:                                    ((TreeText) o).getData().trim().length() > 0) {
0380:                                el.removeChild((TreeText) o);
0381:                            }
0382:                        }
0383:                        Iterator it = allCdata.iterator();
0384:                        while (it.hasNext()) {
0385:                            el.removeChild((CDATASection) it.next());
0386:                        }
0387:                         */
0388:                        FileObject parent = findLayerParent();
0389:                        String externalName = LayerUtils.findGeneratedName(
0390:                                parent, name);
0391:                        assert externalName.indexOf('/') == -1 : externalName;
0392:                        FileObject externalFile = parent
0393:                                .createData(externalName);
0394:                        FileLock lock = externalFile.lock();
0395:                        try {
0396:                            OutputStream os = externalFile
0397:                                    .getOutputStream(lock);
0398:                            try {
0399:                                os.write(contents);
0400:                            } finally {
0401:                                os.close();
0402:                            }
0403:                        } finally {
0404:                            lock.releaseLock();
0405:                        }
0406:                        externalFile.addFileChangeListener(fileChangeListener);
0407:                        try {
0408:                            el.addAttribute("url", externalName); // NOI18N
0409:                        } catch (ReadOnlyException e) {
0410:                            throw (IOException) new IOException(e.toString())
0411:                                    .initCause(e);
0412:                        } catch (InvalidArgumentException e) {
0413:                            assert false : e;
0414:                        }
0415:                    }
0416:                };
0417:            }
0418:
0419:            private FileObject findLayerParent() throws IOException {
0420:                String loc = location.toExternalForm();
0421:                int slash = loc.lastIndexOf('/');
0422:                assert slash != -1 : loc;
0423:                FileObject parent = URLMapper.findFileObject(new URL(loc
0424:                        .substring(0, slash + 1)));
0425:                if (parent == null) {
0426:                    throw new IOException(loc);
0427:                }
0428:                return parent;
0429:            }
0430:
0431:            private void createFileOrFolder(String name, boolean folder)
0432:                    throws IOException {
0433:                String parentName, baseName;
0434:                int idx = name.lastIndexOf('/');
0435:                if (idx == -1) {
0436:                    parentName = ""; // NOI18N
0437:                    baseName = name;
0438:                } else {
0439:                    parentName = name.substring(0, idx);
0440:                    baseName = name.substring(idx + 1);
0441:                }
0442:                TreeElement el = findElement(parentName);
0443:                if (el == null) {
0444:                    throw new FileNotFoundException(parentName);
0445:                }
0446:                try {
0447:                    TreeElement nue = new TreeElement(folder ? "folder"
0448:                            : "file", true); // NOI18N
0449:                    nue.addAttribute("name", baseName); // NOI18N
0450:                    appendWithIndent(el, nue);
0451:                } catch (InvalidArgumentException e) {
0452:                    assert false : e;
0453:                } catch (ReadOnlyException e) {
0454:                    throw (IOException) new IOException(e.toString())
0455:                            .initCause(e);
0456:                }
0457:            }
0458:
0459:            public void createFolder(String name) throws IOException {
0460:                createFileOrFolder(name, true);
0461:            }
0462:
0463:            public void createData(String name) throws IOException {
0464:                createFileOrFolder(name, false);
0465:            }
0466:
0467:            public void delete(String name) throws IOException {
0468:                TreeElement el = findElement(name);
0469:                if (el == null) {
0470:                    throw new FileNotFoundException(name);
0471:                }
0472:                TreeAttribute externalName = el.getAttribute("url"); // NOI18N
0473:                if (externalName != null
0474:                        && !URI.create(externalName.getValue()).isAbsolute()) {
0475:                    // Delete the external file if it can be found.
0476:                    FileObject externalFile = URLMapper.findFileObject(new URL(
0477:                            location, externalName.getValue()));
0478:                    if (externalFile != null) {
0479:                        externalFile
0480:                                .removeFileChangeListener(fileChangeListener);
0481:                        externalFile.delete();
0482:                    }
0483:                }
0484:                try {
0485:                    deleteWithIndent((TreeChild) el);
0486:                } catch (ReadOnlyException e) {
0487:                    throw (IOException) new IOException(e.toString())
0488:                            .initCause(e);
0489:                }
0490:            }
0491:
0492:            public void rename(String oldName, String newName)
0493:                    throws IOException {
0494:                TreeElement el = findElement(oldName);
0495:                if (el == null) {
0496:                    throw new FileNotFoundException(oldName);
0497:                }
0498:                int idx = newName.lastIndexOf('/') + 1;
0499:                if (idx != oldName.lastIndexOf('/') + 1
0500:                        || !oldName.substring(0, idx).equals(
0501:                                newName.substring(0, idx))) {
0502:                    throw new IOException("Cannot rename to a different dir: "
0503:                            + oldName + " -> " + newName); // NOI18N
0504:                }
0505:                String newBaseName = newName.substring(idx);
0506:                assert newBaseName.indexOf('/') == -1;
0507:                assert newBaseName.length() > 0;
0508:                try {
0509:                    el.getAttribute("name").setValue(newBaseName); // NOI18N
0510:                } catch (ReadOnlyException e) {
0511:                    throw (IOException) new IOException(e.toString())
0512:                            .initCause(e);
0513:                } catch (InvalidArgumentException e) {
0514:                    assert false : e;
0515:                }
0516:            }
0517:
0518:            /*
0519:            public boolean copy(String name, Transfer target, String targetName) throws IOException {
0520:                if (! (target instanceof WritableXMLFileSystem)) return false;
0521:                WritableXMLFileSystem otherfs = (WritableXMLFileSystem) target;
0522:                Element el = findElement(name);
0523:                if (el == null) throw new FileNotFoundException(name);
0524:                Element el2;
0525:                if (otherfs == this) {
0526:                    el2 = (Element) el.cloneNode(true);
0527:                } else {
0528:                    el2 = (Element) otherfs.doc.importNode(el, true);
0529:                }
0530:                String path, base;
0531:                int idx = targetName.lastIndexOf('/');
0532:                if (idx == -1) {
0533:                    path = ""; // NOI18N
0534:                    base = targetName;
0535:                } else {
0536:                    path = targetName.substring(0, idx);
0537:                    base = targetName.substring(idx + 1);
0538:                }
0539:                Element parent = otherfs.findElement(path);
0540:                if (parent == null) throw new FileNotFoundException(path);
0541:                el2.setAttribute("name", base); // NOI18N
0542:                Element old = otherfs.findElement(targetName);
0543:                if (old != null) {
0544:                    parent.replaceChild(el2, old);
0545:                } else {
0546:                    appendWithIndent(parent, el2);
0547:                }
0548:                return true;
0549:            }
0550:            
0551:            public boolean move(String name, Transfer target, String targetName) throws IOException {
0552:                if (! (target instanceof WritableXMLFileSystem)) return false;
0553:                WritableXMLFileSystem otherfs = (WritableXMLFileSystem) target;
0554:                Element el = findElement(name);
0555:                if (el == null) throw new FileNotFoundException(name);
0556:                Element el2;
0557:                if (otherfs == this) {
0558:                    // Just move it, no need to clone.
0559:                    el2 = el;
0560:                } else {
0561:                    el2 = (Element) otherfs.doc.importNode(el, true);
0562:                }
0563:                String path, base;
0564:                int idx = targetName.lastIndexOf('/');
0565:                if (idx == -1) {
0566:                    path = ""; // NOI18N
0567:                    base = targetName;
0568:                } else {
0569:                    path = targetName.substring(0, idx);
0570:                    base = targetName.substring(idx + 1);
0571:                }
0572:                Element parent = otherfs.findElement(path);
0573:                if (parent == null) throw new FileNotFoundException(path);
0574:                el2.setAttribute("name", base); // NOI18N
0575:                Element old = otherfs.findElement(targetName);
0576:                if (el != el2) {
0577:                    // Cross-document import, so need to remove old one.
0578:                    el.getParentNode().removeChild(el);
0579:                }
0580:                if (old != null) {
0581:                    parent.replaceChild(el2, old);
0582:                } else {
0583:                    appendWithIndent(parent, el2);
0584:                }
0585:                return true;
0586:            }
0587:             */
0588:
0589:            public Enumeration<String> attributes(String name) {
0590:                TreeElement el = findElement(name);
0591:                if (el == null) {
0592:                    return Enumerations.empty();
0593:                }
0594:                java.util.List<String> l = new ArrayList<String>(10);
0595:                Iterator it = el.getChildNodes(TreeElement.class).iterator();
0596:                while (it.hasNext()) {
0597:                    TreeElement sub = (TreeElement) it.next();
0598:                    if (sub.getLocalName().equals("attr")) { // NOI18N
0599:                        TreeAttribute nameAttr = sub.getAttribute("name"); // NOI18N
0600:                        if (nameAttr == null) {
0601:                            // Malformed.
0602:                            continue;
0603:                        }
0604:                        l.add(nameAttr.getValue());
0605:                    }
0606:                }
0607:                return Collections.enumeration(l);
0608:            }
0609:
0610:            public Object readAttribute(String name, String attrName) {
0611:                if (attrName.equals("WritableXMLFileSystem.cp")) { // NOI18N
0612:                    // XXX currently unused
0613:                    return classpath;
0614:                }
0615:                if (attrName.equals("WritableXMLFileSystem.location")) { // NOI18N
0616:                    // XXX used from PickIconAction; use a constant instead
0617:                    return location;
0618:                }
0619:                if (attrName.equals("DataFolder.Index.reorderable")) { // NOI18N
0620:                    return Boolean.TRUE;
0621:                }
0622:                TreeElement el = findElement(name);
0623:                if (el == null) {
0624:                    return null;
0625:                }
0626:                boolean literal = false;
0627:                if (attrName.startsWith("literal:")) { // NOI18N
0628:                    attrName = attrName.substring("literal:".length()); // NOI18N
0629:                    literal = true;
0630:                }
0631:                Iterator it = el.getChildNodes(TreeElement.class).iterator();
0632:                while (it.hasNext()) {
0633:                    TreeElement sub = (TreeElement) it.next();
0634:                    if (!sub.getLocalName().equals("attr")) { // NOI18N
0635:                        continue;
0636:                    }
0637:                    TreeAttribute nameAttr = sub.getAttribute("name"); // NOI18N
0638:                    if (nameAttr == null) {
0639:                        // Malformed.
0640:                        continue;
0641:                    }
0642:                    if (!attrName.equals(nameAttr.getValue())) {
0643:                        continue;
0644:                    }
0645:                    try {
0646:                        if ((nameAttr = sub.getAttribute("stringvalue")) != null) { // NOI18N
0647:                            // Stolen from XMLMapAttr, with tweaks:
0648:                            String inStr = nameAttr.getValue();
0649:                            StringBuffer outStr = new StringBuffer(inStr
0650:                                    .length());
0651:                            for (int j = 0; j < inStr.length(); j++) {
0652:                                char ch = inStr.charAt(j);
0653:                                if (ch == '\\' && inStr.charAt(j + 1) == 'u'
0654:                                        && j + 5 < inStr.length()) {
0655:                                    String hex = inStr.substring(j + 2, j + 6);
0656:                                    try {
0657:                                        outStr.append((char) Integer.parseInt(
0658:                                                hex, 16));
0659:                                        j += 5;
0660:                                    } catch (NumberFormatException e) {
0661:                                        // OK, just treat as literal text.
0662:                                        outStr.append(ch);
0663:                                    }
0664:                                } else {
0665:                                    outStr.append(ch);
0666:                                }
0667:                            }
0668:                            return outStr.toString();
0669:                        } else if ((nameAttr = sub.getAttribute("boolvalue")) != null) { // NOI18N
0670:                            return Boolean.valueOf(nameAttr.getValue());
0671:                        } else if ((nameAttr = sub.getAttribute("urlvalue")) != null) { // NOI18N
0672:                            return new URL(nameAttr.getValue());
0673:                        } else if ((nameAttr = sub.getAttribute("charvalue")) != null) { // NOI18N
0674:                            return new Character(nameAttr.getValue().charAt(0));
0675:                        } else if ((nameAttr = sub.getAttribute("bytevalue")) != null) { // NOI18N
0676:                            return Byte.valueOf(nameAttr.getValue());
0677:                        } else if ((nameAttr = sub.getAttribute("shortvalue")) != null) { // NOI18N
0678:                            return Short.valueOf(nameAttr.getValue());
0679:                        } else if ((nameAttr = sub.getAttribute("intvalue")) != null) { // NOI18N
0680:                            return Integer.valueOf(nameAttr.getValue());
0681:                        } else if ((nameAttr = sub.getAttribute("longvalue")) != null) { // NOI18N
0682:                            return Long.valueOf(nameAttr.getValue());
0683:                        } else if ((nameAttr = sub.getAttribute("floatvalue")) != null) { // NOI18N
0684:                            return Float.valueOf(nameAttr.getValue());
0685:                        } else if ((nameAttr = sub.getAttribute("doublevalue")) != null) { // NOI18N
0686:                            return Double.valueOf(nameAttr.getValue());
0687:                        } else if ((nameAttr = sub.getAttribute("newvalue")) != null) { // NOI18N
0688:                            String clazz = nameAttr.getValue();
0689:                            if (literal) {
0690:                                return "new:" + clazz; // NOI18N
0691:                            } // else XXX
0692:                        } else if ((nameAttr = sub.getAttribute("methodvalue")) != null) { // NOI18N
0693:                            String clazz = nameAttr.getValue();
0694:                            if (literal) {
0695:                                return "method:" + clazz; // NOI18N
0696:                            } // else XXX
0697:                        }
0698:                    } catch (Exception e) {
0699:                        // MalformedURLException, etc.
0700:                        // XXX notify?
0701:                        return null;
0702:                    }
0703:                    // XXX warn that this attr had no recognized *value?
0704:                }
0705:                return null;
0706:                /*
0707:                                if ((v = sub.getAttributeNode("bytevalue")) != null) { // NOI18N
0708:                                    return new Byte(v.getValue());
0709:                                } else if ((v = sub.getAttributeNode("shortvalue")) != null) { // NOI18N
0710:                                    return new Short(v.getValue());
0711:                                } else if ((v = sub.getAttributeNode("intvalue")) != null) { // NOI18N
0712:                                    return new Integer(v.getValue());
0713:                                } else if ((v = sub.getAttributeNode("longvalue")) != null) { // NOI18N
0714:                                    return new Long(v.getValue());
0715:                                } else if ((v = sub.getAttributeNode("floatvalue")) != null) { // NOI18N
0716:                                    return new Float(v.getValue());
0717:                                } else if ((v = sub.getAttributeNode("doublevalue")) != null) { // NOI18N
0718:                                    // When was the last time you set a file attribute to a double?!
0719:                                    // Useless list of primitives...
0720:                                    return new Double(v.getValue());
0721:                                } else if ((v = sub.getAttributeNode("charvalue")) != null) { // NOI18N
0722:                                    return new Character(v.getValue().charAt(0));
0723:                                } else if ((v = sub.getAttributeNode("methodvalue")) != null) { // NOI18N
0724:                                    String value = v.getValue();
0725:                                    Object[] params = new Object[] { findResource(name), attrName };
0726:                                    // Stolen from XMLMapAttr:
0727:                                    String className,methodName;
0728:                                    int j = value.lastIndexOf('.');
0729:                                    if (j != -1) {
0730:                 
0731:                                        methodName = value.substring(j+1);
0732:                 
0733:                                        className = value.substring(0,j);
0734:                                        ClassLoader cl = cp.getClassLoader(true);
0735:                                        Class cls = Class.forName(className, true, cl);
0736:                                        // Note that unlike XMLMapAttr, we want to use currentClassLoader.
0737:                 
0738:                                        Object objArray[][] = {null,null,null};
0739:                                        Method methArray[] = {null,null,null};
0740:                 
0741:                 
0742:                                        Class fParam = null, sParam = null;
0743:                 
0744:                                        if (params != null) {
0745:                                            if (params.length > 0) fParam = params[0].getClass();
0746:                                            if (params.length > 1) sParam = params[1].getClass();
0747:                                        }
0748:                 
0749:                                        Method[] allMethods = cls.getDeclaredMethods();
0750:                                        Class[] paramClss;
0751:                 
0752:                                        for (int k=0; k < allMethods.length; k++) {
0753:                 
0754:                                            if (!allMethods[k].getName().equals(methodName))  continue;
0755:                 
0756:                 
0757:                                            paramClss = allMethods[k].getParameterTypes();
0758:                 
0759:                                            if (params == null  || params.length == 0 || paramClss.length == 0) {
0760:                                                if (paramClss.length == 0 && methArray[0] == null && objArray[0] == null) {
0761:                                                    methArray[paramClss.length] = allMethods[k];
0762:                                                    objArray[paramClss.length] = new Object[] {};
0763:                                                    continue;
0764:                                                }
0765:                 
0766:                                                continue;
0767:                                            }
0768:                 
0769:                 
0770:                                            if (paramClss.length == 2 && params.length >= 2  && methArray[2] == null && objArray[2] == null)  {
0771:                                                if (paramClss[0].isAssignableFrom(fParam) && paramClss[1].isAssignableFrom(sParam)) {
0772:                                                    methArray[paramClss.length] = allMethods[k];
0773:                                                    objArray[paramClss.length] = new Object[] {params[0],params[1]};
0774:                                                    break;
0775:                                                }
0776:                 
0777:                                                if (paramClss[0].isAssignableFrom(sParam) && paramClss[1].isAssignableFrom(fParam)) {
0778:                                                    methArray[paramClss.length] = allMethods[k];
0779:                                                    objArray[paramClss.length] = new Object[] {params[1],params[0]};
0780:                                                    break;
0781:                                                }
0782:                 
0783:                                                continue;
0784:                                            }
0785:                 
0786:                                            if (paramClss.length == 1 && params.length >= 1 && methArray[1] == null && objArray[1] == null)  {
0787:                                                if (paramClss[0].isAssignableFrom(fParam)) {
0788:                                                    methArray[paramClss.length] = allMethods[k];
0789:                                                    objArray[paramClss.length] = new Object[] {params[0]};
0790:                                                    continue;
0791:                                                }
0792:                 
0793:                                                if (paramClss[0].isAssignableFrom(sParam)) {
0794:                                                    methArray[paramClss.length] = allMethods[k];
0795:                                                    objArray[paramClss.length] = new Object[] {params[1]};
0796:                                                    continue;
0797:                                                }
0798:                 
0799:                                                continue;
0800:                                            }
0801:                 
0802:                                        }
0803:                 
0804:                                        for (int l = methArray.length-1; l >= 0; l-- ) {//clsArray.length
0805:                                            if (methArray[l] != null && objArray[l] != null)  {
0806:                                                //Method meth = cls.getDeclaredMethod(methodName,clsArray[l]);
0807:                                                methArray[l].setAccessible(true); //otherwise cannot invoke private
0808:                                                return methArray[l].invoke(null,objArray[l]);
0809:                                            }
0810:                                        }
0811:                                    }
0812:                                    // Some message to logFile
0813:                                    throw new InstantiationException(value);
0814:                                } else if ((v = sub.getAttributeNode("serialvalue")) != null) { // NOI18N
0815:                                    // Copied from XMLMapAttr:
0816:                                    String value = v.getValue();
0817:                                    if (value.length() == 0) return null;
0818:                 
0819:                                    byte[] bytes = new byte[value.length()/2];
0820:                                    int tempJ;
0821:                                    int count = 0;
0822:                                    for (int j = 0; j < value.length(); j += 2) {
0823:                                        tempJ = Integer.parseInt(value.substring(j,j+2),16);
0824:                                        if (tempJ > 127) tempJ -=256;
0825:                                        bytes[count++] = (byte) tempJ;
0826:                                    }
0827:                 
0828:                                    ByteArrayInputStream bis = new ByteArrayInputStream(bytes, 0, count);
0829:                                    // XXX this should be using a subclass that specifies the right class loader:
0830:                                    ObjectInputStream ois = new NbObjectInputStream(bis);
0831:                                    return ois.readObject();
0832:                                } else if ((v = sub.getAttributeNode("newvalue")) != null) { // NOI18N
0833:                                    ClassLoader cl = cp.getClassLoader(true);
0834:                                    return Class.forName(v.getValue(), true, cl).newInstance();
0835:                                }
0836:                 */
0837:            }
0838:
0839:            public void writeAttribute(String name, String attrName, Object v)
0840:                    throws IOException {
0841:                //System.err.println("wA: " + name + " " + attrName + " " + v);
0842:                if (v != null
0843:                        && v
0844:                                .getClass()
0845:                                .getName()
0846:                                .equals(
0847:                                        "org.openide.filesystems.MultiFileObject$VoidValue")) { // NOI18N
0848:                    // XXX is this legitimate? Definitely not pretty. But needed for testOpenideFolderOrder to pass.
0849:                    v = null;
0850:                }
0851:                TreeElement el = findElement(name);
0852:                if (el == null) {
0853:                    throw new FileNotFoundException(name);
0854:                }
0855:                // Find any existing <attr>.
0856:                TreeChild existingAttr = null;
0857:                Iterator it = el.getChildNodes(TreeElement.class).iterator();
0858:                while (it.hasNext()) {
0859:                    TreeElement sub = (TreeElement) it.next();
0860:                    if (sub.getLocalName().equals("attr")) { // NOI18N
0861:                        TreeAttribute attr = sub.getAttribute("name"); // NOI18N
0862:                        if (attr == null) {
0863:                            // Malformed.
0864:                            continue;
0865:                        }
0866:                        if (attr.getValue().equals(attrName)) {
0867:                            existingAttr = sub;
0868:                            break;
0869:                        }
0870:                    }
0871:                }
0872:                TreeElement attr;
0873:                try {
0874:                    attr = new TreeElement("attr", true); // NOI18N
0875:                    attr.addAttribute("name", attrName); // NOI18N
0876:                    if (v instanceof  String) {
0877:                        String inStr = (String) v;
0878:                        String newValueMagic = "newvalue:"; // NOI18N
0879:                        String methodValueMagic = "methodvalue:"; // NOI18N
0880:                        if (inStr.startsWith(newValueMagic)) {
0881:                            // Impossible to set this (reliably) as a real value, so use this magic technique instead:
0882:                            attr.addAttribute("newvalue", inStr
0883:                                    .substring(newValueMagic.length())); // NOI18N
0884:                        } else if (inStr.startsWith(methodValueMagic)) {
0885:                            // Same here:
0886:                            attr.addAttribute("methodvalue", inStr
0887:                                    .substring(methodValueMagic.length())); // NOI18N
0888:                        } else {
0889:                            // Regular string value.
0890:                            // Stolen from XMLMapAttr w/ mods:
0891:                            StringBuffer outStr = new StringBuffer();
0892:                            for (int i = 0; i < inStr.length(); i++) {
0893:                                char c = inStr.charAt(i);
0894:                                if (Character.isISOControl(c) || c == '&'
0895:                                        || c == '<' || c == '>' || c == '"'
0896:                                        || c == '\'') {
0897:                                    outStr.append(encodeChar(c));
0898:                                } else {
0899:                                    outStr.append(c);
0900:                                }
0901:                            }
0902:                            attr.addAttribute("stringvalue", outStr.toString()); // NOI18N
0903:                        }
0904:                    } else if (v instanceof  URL) {
0905:                        attr.addAttribute("urlvalue", ((URL) v)
0906:                                .toExternalForm()); // NOI18N
0907:                    } else if (v instanceof  Boolean) {
0908:                        attr.addAttribute("boolvalue", v.toString()); // NOI18N
0909:                    } else if (v instanceof  Character) {
0910:                        attr.addAttribute("charvalue", v.toString()); // NOI18N
0911:                    } else if (v instanceof  Integer) {
0912:                        attr.addAttribute("intvalue", v.toString()); // NOI18N
0913:                    } else if (v != null) {
0914:                        throw new UnsupportedOperationException("XXX: " + v); // NOI18N
0915:                    }
0916:                    if (v != null && existingAttr == null) {
0917:                        appendWithIndent(el, attr);
0918:                    } else if (v != null) {
0919:                        ((TreeParentNode) el).replaceChild(existingAttr, attr);
0920:                    } else if (existingAttr != null) {
0921:                        deleteWithIndent(existingAttr);
0922:                    }
0923:                } catch (InvalidArgumentException e) {
0924:                    throw new AssertionError(e);
0925:                } catch (ReadOnlyException e) {
0926:                    throw (IOException) new IOException(e.toString())
0927:                            .initCause(e);
0928:                }
0929:                /*
0930:                if (v instanceof Byte) {
0931:                    attr.setAttribute("bytevalue", v.toString()); // NOI18N
0932:                } else if (v instanceof Short) {
0933:                    attr.setAttribute("shortvalue", v.toString()); // NOI18N
0934:                } else if (v instanceof Integer) {
0935:                    attr.setAttribute("intvalue", v.toString()); // NOI18N
0936:                } else if (v instanceof Long) {
0937:                    attr.setAttribute("longvalue", v.toString()); // NOI18N
0938:                } else if (v instanceof Float) {
0939:                    attr.setAttribute("floatvalue", v.toString()); // NOI18N
0940:                } else if (v instanceof Double) {
0941:                    attr.setAttribute("doublevalue", v.toString()); // NOI18N
0942:                } else if (v instanceof Character) {
0943:                    attr.setAttribute("charvalue", v.toString()); // NOI18N
0944:                } else {
0945:                    // Stolen from XMLMapAttr, mostly.
0946:                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
0947:                    ObjectOutputStream oos = new ObjectOutputStream(bos);
0948:                    oos.writeObject(v);
0949:                    oos.close();
0950:                    byte bArray[] = bos.toByteArray();
0951:                    // Check to see if this is the same as a default instance.
0952:                    Class clazz = v.getClass();
0953:                    boolean usenewinstance = false;
0954:                    try {
0955:                        Object v2 = clazz.newInstance();
0956:                        bos = new ByteArrayOutputStream();
0957:                        oos = new ObjectOutputStream(bos);
0958:                        oos.writeObject(v2);
0959:                        oos.close();
0960:                        byte[] bArray2 = bos.toByteArray();
0961:                        usenewinstance = Utilities.compareObjects(bArray, bArray2);
0962:                    } catch (Exception e) {
0963:                        // quite expectable - ignore
0964:                    }
0965:                    if (usenewinstance) {
0966:                        attr.setAttribute("newvalue", clazz.getName()); // NOI18N
0967:                    } else {
0968:                        StringBuffer strBuff = new StringBuffer(bArray.length*2);
0969:                        for(int i = 0; i < bArray.length;i++) {
0970:                            if (bArray[i] < 16 && bArray[i] >= 0) strBuff.append("0");// NOI18N
0971:                            strBuff.append(Integer.toHexString(bArray[i] < 0?bArray[i]+256:bArray[i]));
0972:                        }
0973:                        attr.setAttribute("serialvalue", strBuff.toString()); // NOI18N
0974:                        // Also mention what the original value was, for reference.
0975:                        // Do it after adding element since otherwise we cannot indent correctly.
0976:                        String asString;
0977:                        if (clazz.isArray()) {
0978:                            // Default toString sucks for arrays. Pretty common so worth special-casing.
0979:                            asString = Arrays.asList((Object[]) v).toString();
0980:                        } else {
0981:                            asString = v.toString();
0982:                        }
0983:                        serialComment = " (" + attrName + "=" + asString + ") ";
0984:                    }
0985:                }
0986:                if (adding) {
0987:                    appendWithIndent(el, attr);
0988:                }
0989:                // Deal with serial comments now.
0990:                Comment comment = findSerialComment(el, attrName);
0991:                if (serialComment != null) {
0992:                    if (comment != null) {
0993:                        comment.setData(serialComment);
0994:                    } else {
0995:                        appendWithIndent(el, doc.createComment(serialComment));
0996:                    }
0997:                } else if (comment != null) {
0998:                    // Changed from some serialvalue to simple value; kill comment.
0999:                    el.removeChild(comment);
1000:                }
1001:                if (attrName.startsWith("SystemFileSystem")) { // NOI18N
1002:                    fireFileStatusChanged(new FileStatusEvent(this, findResource(name), true, true));
1003:                }
1004:                }
1005:                private Comment findSerialComment(Element el, String attrName) {
1006:                NodeList nl = el.getChildNodes();
1007:                for (int i = 0; i < nl.getLength(); i++) {
1008:                    if (nl.item(i).getNodeType() == Node.COMMENT_NODE) {
1009:                        String comm = nl.item(i).getNodeValue();
1010:                        if (comm.startsWith(" (" + attrName + "=") && comm.endsWith(") ")) {
1011:                            return (Comment) nl.item(i);
1012:                        }
1013:                    }
1014:                }
1015:                return null;
1016:                 */
1017:            }
1018:
1019:            /** stolen from XMLMapAttr */
1020:            private static String encodeChar(char ch) {
1021:                String encChar = Integer.toString((int) ch, 16);
1022:                return "\\u"
1023:                        + "0000".substring(0,
1024:                                "0000".length() - encChar.length()).concat(
1025:                                encChar); // NOI18N
1026:            }
1027:
1028:            public void renameAttributes(String oldName, String newName) {
1029:                // do nothing
1030:            }
1031:
1032:            public void deleteAttributes(String name) {
1033:                // do nothing
1034:            }
1035:
1036:            public boolean readOnly(String name) {
1037:                return false;
1038:            }
1039:
1040:            public String mimeType(String name) {
1041:                return null; // i.e. use default resolvers
1042:            }
1043:
1044:            public long size(String name) {
1045:                try {
1046:                    return getContentsOf(name).length;
1047:                } catch (FileNotFoundException fnfe) {
1048:                    return 0;
1049:                }
1050:            }
1051:
1052:            public void markUnimportant(String name) {
1053:                // do nothing
1054:            }
1055:
1056:            public Date lastModified(String name) {
1057:                final TreeElement el = findElement(name);
1058:                if (el == null) {
1059:                    return new Date(0L);
1060:                }
1061:                TreeAttribute attr = el.getAttribute("url"); // NOI18N
1062:                if (attr == null) {
1063:                    return new Date(0L);
1064:                }
1065:                String u = attr.getValue();
1066:                if (URI.create(u).isAbsolute()) {
1067:                    return new Date(0L);
1068:                }
1069:                FileObject external;
1070:                try {
1071:                    external = URLMapper.findFileObject(new URL(location, u));
1072:                } catch (MalformedURLException e) {
1073:                    assert false : e;
1074:                    return new Date(0L);
1075:                }
1076:                if (external == null) {
1077:                    return new Date(0L);
1078:                }
1079:                return external.lastModified();
1080:            }
1081:
1082:            // These are not important for us:
1083:
1084:            public void lock(String name) throws IOException {
1085:                // [PENDING] should this try to lock the XML document??
1086:                // (not clear if it is safe to do so from FS call, even tho
1087:                // on a different FS)
1088:            }
1089:
1090:            public void unlock(String name) {
1091:                // do nothing
1092:            }
1093:
1094:            // don't bother making configurable; or could use an indentation engine
1095:            private static final int INDENT_STEP = 4;
1096:
1097:            /**
1098:             * Add a new element to a parent in the correct position.
1099:             * Inserts whitespace to retain indentation rules.
1100:             */
1101:            private static void appendWithIndent(TreeElement parent,
1102:                    TreeChild child) throws ReadOnlyException {
1103:                TreeParentNode doc = parent;
1104:                int depth = -2; // will get <filesystem> then TreeDocument then null
1105:                while (doc != null) {
1106:                    doc = ((TreeChild) doc).getParentNode();
1107:                    depth++;
1108:                }
1109:                TreeChild position = insertBefore(parent, child);
1110:                try {
1111:                    if (position != null) {
1112:                        parent.insertBefore(child, position);
1113:                        parent.insertBefore(new TreeText("\n"
1114:                                + spaces((depth + 1) * INDENT_STEP)), position); // NOI18N
1115:                    } else {
1116:                        if (/*XXX this is clumsy*/parent.hasChildNodes()) {
1117:                            parent
1118:                                    .appendChild(new TreeText(
1119:                                            spaces(INDENT_STEP)));
1120:                        } else {
1121:                            parent.appendChild(new TreeText("\n"
1122:                                    + spaces((depth + 1) * INDENT_STEP))); // NOI18N
1123:                        }
1124:                        parent.appendChild(child);
1125:                        parent.appendChild(new TreeText("\n"
1126:                                + spaces(depth * INDENT_STEP))); // NOI18N
1127:                    }
1128:                    parent.normalize();
1129:                    /* XXX could check for adding position attr and resort parent of parent?
1130:                    TreeElement childe = (TreeElement) child;
1131:                    if (childe.getQName().equals("attr") && childe.getAttribute("name").getValue().indexOf('/') != -1) { // NOI18N
1132:                        // Check for ordering attributes, which we have to handle specially.
1133:                        resort(parent);
1134:                    }
1135:                     */
1136:                } catch (InvalidArgumentException e) {
1137:                    assert false : e;
1138:                }
1139:            }
1140:
1141:            /**
1142:             * Find the proper location for a newly inserted element.
1143:             * Rules:
1144:             * 1. <file> or <folder> must be added in alphabetical order w.r.t. existing ones.
1145:             * 2. <attr> must be added to top of element in alpha order w.r.t. existing ones.
1146:             * Returns a position to insert before (null for end).
1147:             */
1148:            private static TreeChild insertBefore(TreeElement parent,
1149:                    TreeChild child) throws ReadOnlyException {
1150:                if (!(child instanceof  TreeElement)) {
1151:                    return null; // TBD for now
1152:                }
1153:                TreeElement childe = (TreeElement) child;
1154:                if (childe.getQName().equals("file")
1155:                        || childe.getQName().equals("folder")) { // NOI18N
1156:                    String name = childe.getAttribute("name").getValue(); // NOI18N
1157:                    Iterator it = parent.getChildNodes(TreeElement.class)
1158:                            .iterator();
1159:                    while (it.hasNext()) {
1160:                        TreeElement kid = (TreeElement) it.next();
1161:                        if (kid.getQName().equals("file")
1162:                                || kid.getQName().equals("folder")) { // NOI18N
1163:                            TreeAttribute attr = kid.getAttribute("name"); // NOI18N
1164:                            if (attr != null) { // #66816 - layer might be malformed
1165:                                String kidname = attr.getValue();
1166:                                if (kidname.compareTo(name) > 0) {
1167:                                    return kid;
1168:                                }
1169:                            }
1170:                        }
1171:                    }
1172:                    return null;
1173:                } else if (childe.getQName().equals("attr")) { // NOI18N
1174:                    String name = childe.getAttribute("name").getValue(); // NOI18N
1175:                    Iterator it = parent.getChildNodes(TreeElement.class)
1176:                            .iterator();
1177:                    while (it.hasNext()) {
1178:                        TreeElement kid = (TreeElement) it.next();
1179:                        if (kid.getQName().equals("file")
1180:                                || kid.getQName().equals("folder")) { // NOI18N
1181:                            return kid;
1182:                        } else if (kid.getQName().equals("attr")) { // NOI18N
1183:                            TreeAttribute attr = kid.getAttribute("name"); // NOI18N
1184:                            if (attr != null) {
1185:                                String kidname = attr.getValue();
1186:                                if (kidname.compareTo(name) > 0) {
1187:                                    return kid;
1188:                                }
1189:                            }
1190:                        } else {
1191:                            throw new AssertionError("Weird child: "
1192:                                    + kid.getQName());
1193:                        }
1194:                    }
1195:                    return null;
1196:                } else {
1197:                    throw new AssertionError("Weird child: "
1198:                            + childe.getQName());
1199:                }
1200:            }
1201:
1202:            /**
1203:             * Resort all files and folders and attributes in a folder context. The order is:
1204:             * 1. Attributes are alpha-sorted at the top.
1205:             * 2. Files and folders are alpha-sorted if they have no position.
1206:             * 3. Files with positions are sorted numerically above files without.
1207:             */
1208:            /* XXX not important yet
1209:            private static void resort(TreeElement parent) throws ReadOnlyException {
1210:                class Item {
1211:                    public TreeElement child;
1212:                    boolean isAttr() {
1213:                        return child.getQName().equals("attr"); // NOI18N
1214:                    }
1215:                    String getName() {
1216:                        TreeAttribute attr = child.getAttribute("name"); // NOI18N
1217:                        return attr != null ? attr.getValue() : "";
1218:                    }
1219:                    boolean isOrderingAttr() {
1220:                        return isAttr() && getName().indexOf('/') != -1;
1221:                    }
1222:                    String getFormer() {
1223:                        String n = getName();
1224:                        return n.substring(0, n.indexOf('/'));
1225:                    }
1226:                    String getLatter() {
1227:                        String n = getName();
1228:                        return n.substring(n.indexOf('/') + 1);
1229:                    }
1230:                }
1231:                Set<Item> items = new LinkedHashSet();
1232:                SortedSet<Integer> indices = new TreeSet();
1233:                for (int i = 0; i < parent.getChildrenNumber(); i++) {
1234:                    TreeChild child = (TreeChild) parent.getChildNodes().get(i);
1235:                    if (child instanceof TreeElement) {
1236:                        Item item = new Item();
1237:                        item.child = (TreeElement) child;
1238:                        items.add(item);
1239:                        indices.add(new Integer(i));
1240:                    }
1241:                }
1242:                Map<Item,Collection<Item>> edges = new LinkedHashMap();
1243:                Map<String,Item> filesAndFolders = new LinkedHashMap();
1244:                Map<String,Item> attrs = new LinkedHashMap();
1245:                Set<String> orderedFilesAndFolders = new LinkedHashSet();
1246:                Iterator it = items.iterator();
1247:                while (it.hasNext()) {
1248:                    Item item = (Item) it.next();
1249:                    String name = item.getName();
1250:                    if (item.isAttr()) {
1251:                        attrs.put(name, item);
1252:                        if (item.isOrderingAttr()) {
1253:                            orderedFilesAndFolders.add(item.getFormer());
1254:                            orderedFilesAndFolders.add(item.getLatter());
1255:                        }
1256:                    } else {
1257:                        filesAndFolders.put(name, item);
1258:                    }
1259:                }
1260:                class NameComparator implements Comparator {
1261:                    public int compare(Object o1, Object o2) {
1262:                        Item i1 = (Item) o1;
1263:                        Item i2 = (Item) o2;
1264:                        return i1.getName().compareTo(i2.getName());
1265:                    }
1266:                }
1267:                Set<Item> sortedAttrs = new TreeSet(new NameComparator());
1268:                Set<Item> sortedFilesAndFolders = new TreeSet(new NameComparator());
1269:                Set<Item> orderableItems = new LinkedHashSet();
1270:                it = items.iterator();
1271:                while (it.hasNext()) {
1272:                    Item item = (Item) it.next();
1273:                    String name = item.getName();
1274:                    if (item.isAttr()) {
1275:                        if (item.isOrderingAttr()) {
1276:                            Item former = (Item) filesAndFolders.get(item.getFormer());
1277:                            if (former != null) {
1278:                                Set<Item> formerConstraints = (Set) edges.get(former);
1279:                                if (formerConstraints == null) {
1280:                                    formerConstraints = new LinkedHashSet();
1281:                                    edges.put(former, formerConstraints);
1282:                                }
1283:                                formerConstraints.add(item);
1284:                            }
1285:                            Item latter = (Item) filesAndFolders.get(item.getLatter());
1286:                            if (latter != null) {
1287:                                Set<Item> constraints = new LinkedHashSet();
1288:                                constraints.add(latter);
1289:                                edges.put(item, constraints);
1290:                            }
1291:                            orderableItems.add(item);
1292:                        } else {
1293:                            sortedAttrs.add(item);
1294:                        }
1295:                    } else {
1296:                        if (orderedFilesAndFolders.contains(name)) {
1297:                            orderableItems.add(item);
1298:                        } else {
1299:                            sortedFilesAndFolders.add(item);
1300:                        }
1301:                    }
1302:                }
1303:                java.util.List<Item> orderedItems;
1304:                try {
1305:                    orderedItems = Utilities.topologicalSort(orderableItems, edges);
1306:                } catch (TopologicalSortException e) {
1307:                    // OK, ignore.
1308:                    return;
1309:                }
1310:                it = items.iterator();
1311:                while (it.hasNext()) {
1312:                    Item item = (Item) it.next();
1313:                    parent.removeChild(item.child);
1314:                }
1315:                java.util.List<Item> allOrderedItems = new ArrayList(sortedAttrs);
1316:                allOrderedItems.addAll(orderedItems);
1317:                allOrderedItems.addAll(sortedFilesAndFolders);
1318:                assert new HashSet(allOrderedItems).equals(items);
1319:                it = allOrderedItems.iterator();
1320:                Iterator indexIt = indices.iterator();
1321:                while (it.hasNext()) {
1322:                    Item item = (Item) it.next();
1323:                    int index = ((Integer) indexIt.next()).intValue();
1324:                    parent.insertChildAt(item.child, index);
1325:                }
1326:            }
1327:             */
1328:            private static String spaces(int size) {
1329:                char[] chars = new char[size];
1330:                for (int i = 0; i < size; i++) {
1331:                    chars[i] = ' ';
1332:                }
1333:                return new String(chars);
1334:            }
1335:
1336:            /**
1337:             * Remove an element (and its children), deleting any surrounding newlines and indentation too.
1338:             */
1339:            private static void deleteWithIndent(TreeChild child)
1340:                    throws ReadOnlyException {
1341:                TreeChild next = child.getNextSibling();
1342:                // XXX better might be to delete any maximal [ \t]+ previous plus \n next (means splitting up TreeText's)
1343:                if (next instanceof  TreeText
1344:                        && ((TreeText) next).getData().matches(
1345:                                "(\r|\n|\r\n)[ \t]+")) { // NOI18N
1346:                    next.removeFromContext();
1347:                } else {
1348:                    TreeChild previous = child.getPreviousSibling();
1349:                    if (previous instanceof  TreeText
1350:                            && ((TreeText) previous).getData().matches(
1351:                                    "(\r|\n|\r\n)[ \t]+")) { // NOI18N
1352:                        previous.removeFromContext();
1353:                    } else {
1354:                        // Well, not sure what is here, so skip it.
1355:                    }
1356:                }
1357:                TreeElement parent = (TreeElement) child.getParentNode();
1358:                TreeObjectList list = parent.getChildNodes();
1359:                boolean kill = true;
1360:                Iterator it = list.iterator();
1361:                while (it.hasNext()) {
1362:                    Object o = it.next();
1363:                    if (o == child) {
1364:                        continue;
1365:                    }
1366:                    if (!(o instanceof  TreeText)) {
1367:                        kill = false;
1368:                        break;
1369:                    }
1370:                    if (((TreeText) o).getData().trim().length() > 0) {
1371:                        kill = false;
1372:                        break;
1373:                    }
1374:                }
1375:                if (kill) {
1376:                    try {
1377:                        // Special case for root of filesystem.
1378:                        if (((TreeChild) parent).getParentNode() instanceof  TreeDocumentRoot) {
1379:                            it = list.iterator();
1380:                            while (it.hasNext()) {
1381:                                ((TreeChild) it.next()).removeFromContext();
1382:                            }
1383:                            parent.appendChild(new TreeText("\n")); // NOI18N
1384:                        } else {
1385:                            // Make sure we convert it to an empty tag (seems to only affect elements
1386:                            // which were originally parsed?):
1387:                            TreeElement parent2 = new TreeElement(parent
1388:                                    .getQName(), true);
1389:                            TreeAttribute attr = parent.getAttribute("name"); // NOI18N
1390:                            if (attr != null) {
1391:                                parent2.addAttribute("name", attr.getValue()); // NOI18N
1392:                            }
1393:                            TreeParentNode grandparent = ((TreeChild) parent)
1394:                                    .getParentNode();
1395:                            // TreeElement.empty is sticky - cannot be changed retroactively (argh!).
1396:                            grandparent.replaceChild(parent, parent2);
1397:                            parent = parent2; // for normalize() below
1398:                        }
1399:                    } catch (InvalidArgumentException e) {
1400:                        assert false : e;
1401:                    }
1402:                }
1403:                child.removeFromContext();
1404:                parent.normalize();
1405:            }
1406:
1407:            // Listen to changes in files used as url= external contents. If these change,
1408:            // the filesystem needs to show something else. Properly we would
1409:            // keep track of *which* file changed and thus which of our resources
1410:            // is affected. Practically this would be a lot of work and gain
1411:            // very little.
1412:            public void fileDeleted(FileEvent fe) {
1413:                someFileChange();
1414:            }
1415:
1416:            public void fileFolderCreated(FileEvent fe) {
1417:                // does not apply to us
1418:            }
1419:
1420:            public void fileDataCreated(FileEvent fe) {
1421:                // not interesting here
1422:            }
1423:
1424:            public void fileAttributeChanged(FileAttributeEvent fe) {
1425:                // don't care about attributes on included files...
1426:            }
1427:
1428:            public void fileRenamed(FileRenameEvent fe) {
1429:                someFileChange();
1430:            }
1431:
1432:            public void fileChanged(FileEvent fe) {
1433:                someFileChange();
1434:            }
1435:
1436:            private void someFileChange() {
1437:                // If used as url=, refresh contents, timestamp, ...
1438:                refreshResource("", true);
1439:            }
1440:
1441:            public void propertyChange(PropertyChangeEvent evt) {
1442:                if (!evt.getPropertyName().equals(
1443:                        TreeEditorCookie.PROP_DOCUMENT_ROOT)) {
1444:                    return;
1445:                }
1446:                if (cookie.getStatus() == TreeEditorCookie.STATUS_OK
1447:                        || cookie.getStatus() == TreeEditorCookie.STATUS_NOT) {
1448:                    // Document was modified, and reparsed OK. See what changed.
1449:                    try {
1450:                        doc = cookie.openDocumentRoot();
1451:                        /* Neither of the following work:
1452:                        refreshResource("", true); // only works on root folder
1453:                        refreshRoot();             // seems to do nothing at all
1454:                         */
1455:                        Enumeration<? extends FileObject> e = existingFileObjects(getRoot());
1456:                        while (e.hasMoreElements()) {
1457:                            FileObject fo = (FileObject) e.nextElement();
1458:                            // fo.refresh() does not work
1459:                            refreshResource(fo.getPath(), true);
1460:                        }
1461:                        //System.err.println("got changes; new files: " + Collections.list(getRoot().getChildren(true)));
1462:                        //Thread.dumpStack();
1463:                    } catch (TreeException e) {
1464:                        Util.err.notify(ErrorManager.INFORMATIONAL, e);
1465:                    } catch (IOException e) {
1466:                        Util.err.notify(ErrorManager.INFORMATIONAL, e);
1467:                    }
1468:                }
1469:            }
1470:
1471:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.