This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 20168
Collapse All | Expand All

(-)core/src/org/netbeans/core/projects/ModuleLayeredFileSystem.java (-41 / +211 lines)
Lines 7-49 Link Here
7
 * http://www.sun.com/
7
 * http://www.sun.com/
8
 * 
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
12
 */
13
13
14
package org.netbeans.core.projects;
14
package org.netbeans.core.projects;
15
15
16
import java.beans.*;
16
import java.beans.*;
17
import java.io.File;
17
import java.io.*;
18
import java.io.IOException;
18
import java.net.*;
19
import java.net.URL;
20
import java.util.*;
19
import java.util.*;
21
20
21
import org.xml.sax.SAXException;
22
23
import org.openide.ErrorManager;
22
import org.openide.TopManager;
24
import org.openide.TopManager;
25
import org.openide.filesystems.*;
23
import org.openide.filesystems.FileSystem;
26
import org.openide.filesystems.FileSystem;
24
import org.openide.filesystems.MultiFileSystem;
27
25
import org.openide.filesystems.XMLFileSystem;
28
import org.netbeans.core.perftool.StartLog;
26
import org.openide.ErrorManager;
27
29
28
/** Layered file system serving itself as either the user or installation layer.
30
/** Layered file system serving itself as either the user or installation layer.
29
 * Holds one layer of a writable system directory, and some number
31
 * Holds one layer of a writable system directory, and some number
30
 * of module layers.
32
 * of module layers.
31
 * @author Jesse Glick
33
 * @author Jesse Glick, Jaroslav Tulach
32
 */
34
 */
33
public class ModuleLayeredFileSystem extends MultiFileSystem {
35
public class ModuleLayeredFileSystem extends MultiFileSystem {
34
    /** serial version UID */
36
    /** serial version UID */
35
    private static final long serialVersionUID = 782910986724201983L;
37
    private static final long serialVersionUID = 782910986724201983L;
38
    
39
    static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.core.projects"); // NOI18N
40
    
41
    /** current list of URLs - r/o; or null if not yet set */
42
    private List urls; // List<URL>
43
    /** cache file, or null */
44
    private final File cacheFile;
36
45
37
    /** Create layered filesystem based on a supplied writable layer.
46
    /** Create layered filesystem based on a supplied writable layer.
38
     * @param writableLayer the writable layer to use, typically a LocalFileSystem
47
     * @param writableLayer the writable layer to use, typically a LocalFileSystem
48
     * @param cacheDir a directory in which to store a cache, or null for no caching
39
     */
49
     */
40
    ModuleLayeredFileSystem (FileSystem writableLayer) {
50
    ModuleLayeredFileSystem (FileSystem writableLayer, File cacheDir) throws IOException, SAXException {
41
        super (new FileSystem[] { writableLayer, new XMLFileSystem () });
51
        this(writableLayer, false, cacheFile(cacheDir));
52
    }
53
    
54
    private ModuleLayeredFileSystem(FileSystem writableLayer, boolean ignored, File cacheFile) throws IOException, SAXException {
55
        super(new FileSystem[] {
56
            writableLayer,
57
            (cacheFile != null && cacheFile.isFile()) ?
58
                loadCache(cacheFile) :
59
                new XMLFileSystem()
60
        });
61
        this.cacheFile = cacheFile;
62
        
42
        // Wish to permit e.g. a user-installed module to mask files from a
63
        // Wish to permit e.g. a user-installed module to mask files from a
43
        // root-installed module, so propagate masks up this high.
64
        // root-installed module, so propagate masks up this high.
44
        // SystemFileSystem leaves this off, so that the final file system
65
        // SystemFileSystem leaves this off, so that the final file system
45
        // will not show them if there are some left over.
66
        // will not show them if there are some left over.
46
        setPropagateMasks (true);
67
        setPropagateMasks (true);
68
        
69
        urls = null;
70
    }
71
    
72
    private static XMLFileSystem loadCache(File cacheFile) throws IOException, SAXException {
73
        StartLog.logStart("Loading " + cacheFile);
74
        XMLFileSystem xmlfs = new XMLFileSystem(cacheFile.toURL());
75
        StartLog.logEnd("Loading " + cacheFile);
76
        return xmlfs;
77
    }
78
    
79
    // See #20168 for information on layer caching.
80
    private static File cacheFile(File cacheDir) {
81
        if (cacheDir != null && Boolean.getBoolean("netbeans.cache.layers")) {
82
            try {
83
                if (!cacheDir.isDirectory()) {
84
                    if (!cacheDir.mkdirs()) {
85
                        throw new IOException("Could not make dir: " + cacheDir); // NOI18N
86
                    }
87
                }
88
                File f = new File(cacheDir, "all-layers.xml"); // NOI18N
89
                err.log("Using layer cache in " + f);
90
                return f;
91
            } catch (IOException ex) {
92
                err.notify(ex);
93
            }
94
        }
95
        // Misleading:
96
        //err.log("Not using any layer cache");
97
        return null;
47
    }
98
    }
48
99
49
    /** Get all layers.
100
    /** Get all layers.
Lines 60-72 Link Here
60
        return getDelegates ()[0];
111
        return getDelegates ()[0];
61
    }
112
    }
62
    
113
    
63
    /** Get the XML layer.
64
     * @return the XML layer
65
     */
66
    final XMLFileSystem getXMLLayer () {
67
        return (XMLFileSystem)getDelegates ()[1];
68
    }
69
       
70
    /** Creates the system file system.
114
    /** Creates the system file system.
71
     */
115
     */
72
    public static FileSystem create (File x, File y) 
116
    public static FileSystem create (File x, File y) 
Lines 99-155 Link Here
99
    }
143
    }
100
144
101
    /** Change the list of module layers URLs.
145
    /** Change the list of module layers URLs.
102
     * @param urls the urls describing module layers to use. List (List (URL))
146
     * @param urls the urls describing module layers to use. List<URL>
103
     */
147
     */
104
    public void setURLs (final List urls) throws Exception {
148
    public void setURLs (final List urls) throws Exception {
105
        if (urls.contains(null)) throw new NullPointerException("urls=" + urls); // NOI18N
149
        if (urls.contains(null)) throw new NullPointerException("urls=" + urls); // NOI18N
150
        if (err.isLoggable(ErrorManager.INFORMATIONAL)) {
151
            err.log("setURLs: " + urls);
152
        }
153
        if (this.urls != null && urls.equals(this.urls)) {
154
            err.log("no-op");
155
            return;
156
        }
157
        
158
        StartLog.logStart("setURLs");
159
        
160
        final XMLFileSystem xmlfs = (XMLFileSystem)getDelegates()[1];
161
        
162
        final File stampFile;
163
        final Stamp stamp;
164
        if (cacheFile != null) {
165
            stampFile = new File(cacheFile.getParentFile(), "layer-stamp.txt"); // NOI18N
166
            stamp = new Stamp(urls);
167
        } else {
168
            stampFile = null;
169
            stamp = null;
170
        }
171
        if (cacheFile != null && cacheFile.isFile() && stampFile.isFile()) {
172
            err.log("Stamp of new URLs: " + stamp.getHash());
173
            BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(stampFile), "UTF-8")); // NOI18N
174
            try {
175
                String line = r.readLine();
176
                long hash = Long.parseLong(line);
177
                err.log("Stamp in the cache: " + hash);
178
                if (hash == stamp.getHash()) {
179
                    err.log("Cache hit!");
180
                    this.urls = urls;
181
                    StartLog.logEnd("setURLs");
182
                    return;
183
                }
184
            } finally {
185
                r.close();
186
            }
187
        }
106
188
107
        // #17656: don't hold synch lock while firing changes, it could be dangerous...
189
        // #17656: don't hold synch lock while firing changes, it could be dangerous...
108
        runAtomicAction(new AtomicAction() {
190
        runAtomicAction(new AtomicAction() {
109
            public void run() throws IOException {
191
            public void run() throws IOException {
110
                synchronized (ModuleLayeredFileSystem.this) {
192
                synchronized (ModuleLayeredFileSystem.this) {
111
                    try {
193
                    try {
112
                        getXMLLayer().setXmlUrls((URL[])urls.toArray(new URL[urls.size()]));
194
                        if (cacheFile != null) {
195
                            err.log("Rewriting cache in " + cacheFile);
196
                            // Cf. XMLFileSystem impl.
197
                            System.setProperty("netbeans.cache.layers.filename", cacheFile.getAbsolutePath());
198
                            if (cacheFile.isFile() && !cacheFile.delete()) {
199
                                throw new IOException("Deletion failed: " + cacheFile); // NOI18N
200
                            }
201
                        }
202
                        xmlfs.setXmlUrls((URL[])urls.toArray(new URL[urls.size()]));
113
                    } catch (PropertyVetoException pve) {
203
                    } catch (PropertyVetoException pve) {
114
                        IOException ioe = new IOException(pve.toString());
204
                        IOException ioe = new IOException(pve.toString());
115
                        ErrorManager.getDefault().annotate(ioe, pve);
205
                        err.annotate(ioe, pve);
116
                        throw ioe;
206
                        throw ioe;
207
                    } finally {
208
                        if (cacheFile != null) {
209
                            System.setProperty("netbeans.cache.layers.filename", "");
210
                            if (cacheFile.isFile()) {
211
                                // Write out new stamp too.
212
                                Writer wr = new OutputStreamWriter(new FileOutputStream(stampFile), "UTF-8"); // NOI18N
213
                                try {
214
                                    wr.write(String.valueOf(stamp.getHash()));
215
                                    wr.write("\nLine above is identifying hash key, do not edit!\nBelow is metadata about all-layer.xml, for debugging purposes.\n"); // NOI18N
216
                                    wr.write(stamp.toString());
217
                                } finally {
218
                                    wr.close();
219
                                }
220
                            } else {
221
                                err.log(ErrorManager.WARNING, "WARNING - XMLFileSystem did not manage to create " + cacheFile);
222
                            }
223
                        }
117
                    }
224
                    }
118
                }
225
                }
119
            }
226
            }
120
        });
227
        });
121
        
228
        
229
        this.urls = urls;
122
        firePropertyChange ("layers", null, null); // NOI18N
230
        firePropertyChange ("layers", null, null); // NOI18N
231
        
232
        StartLog.logEnd("setURLs");
123
    }
233
    }
124
    
234
    
125
    /** Adds few URLs.
235
    /** Adds few URLs.
126
     */
236
     */
127
    public void addURLs (Collection urls) throws Exception {
237
    public void addURLs(Collection urls) throws Exception {
128
        if (urls.contains(null)) throw new NullPointerException("urls=" + urls); // NOI18N
238
        if (urls.contains(null)) throw new NullPointerException("urls=" + urls); // NOI18N
129
        FileSystem[] delegates = getDelegates ();
239
        ArrayList arr = new ArrayList();
130
        XMLFileSystem fs = delegates.length < 2 ? null : (XMLFileSystem)delegates[1];
240
        if (this.urls != null) arr.addAll(this.urls);
131
        ArrayList arr = new ArrayList ();
241
        arr.addAll(urls);
132
        if (fs != null) {
242
        setURLs(arr);
133
            arr.addAll (Arrays.asList (fs.getXmlUrls ()));
134
        }
135
        arr.addAll (urls);
136
        setURLs (arr);    
137
    }
243
    }
138
    
244
    
139
    /** Removes few URLs.
245
    /** Removes few URLs.
140
     *
141
     */
246
     */
142
    public void removeURLs (Collection urls) throws Exception {
247
    public void removeURLs(Collection urls) throws Exception {
143
        FileSystem[] delegates = getDelegates ();
248
        if (urls.contains(null)) throw new NullPointerException("urls=" + urls); // NOI18N
144
        XMLFileSystem fs = delegates.length < 2 ? null : (XMLFileSystem)delegates[1];
249
        ArrayList arr = new ArrayList();
145
        if (fs == null) {
250
        if (this.urls != null) arr.addAll(this.urls);
146
            // no filesystem available
251
        arr.removeAll(urls);
147
            return;
252
        setURLs(arr);
253
    }
254
    
255
    /** Represents a hash of a bunch of jar: URLs and the associated JAR timestamps.
256
     */
257
    private static final class Stamp implements Comparator {
258
        private final List urls; // List<URL>
259
        private final long[] times;
260
        private final long hash;
261
        public Stamp(List urls) throws IOException {
262
            this.urls = new ArrayList(urls);
263
            Collections.sort(this.urls, this);
264
            times = new long[this.urls.size()];
265
            long x = 17L;
266
            Iterator it = this.urls.iterator();
267
            int i = 0;
268
            while (it.hasNext()) {
269
                URL u = (URL)it.next();
270
                String s = u.toString();
271
                x += 3199876987199633L;
272
                x ^= s.hashCode();
273
                File extracted = findFile(s);
274
                if (extracted != null) {
275
                    x ^= (times[i++] = extracted.lastModified());
276
                } else {
277
                    times[i++] = 0L;
278
                }
279
            }
280
            hash = x;
281
        }
282
        private static File findFile(String u) throws IOException {
283
            if (u.startsWith("jar:") && u.lastIndexOf("!/") != -1) { // NOI18N
284
                u = u.substring(4, u.lastIndexOf("!/"));
285
            }
286
            if (u.startsWith("file:")) { // NOI18N
287
                //return new File(u.substring(5));
288
                // XXX is this algorithm really portable? Unfortunately Java
289
                // platform provides no better way that I know of.
290
                URL fu = new URL(u);
291
                String path = URLDecoder.decode(fu.getPath());
292
                if (File.separatorChar != '/') {
293
                    path = path.replace('/', File.separatorChar);
294
                }
295
                return new File(path);
296
            } else {
297
                return null;
298
            }
299
        }
300
        public long getHash() {
301
            return hash;
302
        }
303
        public String toString() {
304
            StringBuffer buf = new StringBuffer();
305
            Iterator it = urls.iterator();
306
            int i = 0;
307
            while (it.hasNext()) {
308
                long t = times[i++];
309
                if (t == 0L) {
310
                    buf.append("<file not found>"); // NOI18N
311
                } else {
312
                    buf.append(new Date(t));
313
                }
314
                buf.append('\t');
315
                buf.append(it.next());
316
                buf.append('\n');
317
            }
318
            return buf.toString();
319
        }
320
        public int compare(Object o1, Object o2) {
321
            return ((URL)o1).toString().compareTo(((URL)o2).toString());
148
        }
322
        }
149
        ArrayList arr = new ArrayList ();
150
        arr.addAll (Arrays.asList (fs.getXmlUrls ()));
151
        arr.removeAll (urls);
152
        setURLs (arr);    
153
    }
323
    }
154
324
    
155
}
325
}
(-)core/src/org/netbeans/core/projects/SystemFileSystem.java (-4 / +12 lines)
Lines 7-13 Link Here
7
 * http://www.sun.com/
7
 * http://www.sun.com/
8
 * 
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
12
 */
13
13
Lines 22-27 Link Here
22
import java.util.*;
22
import java.util.*;
23
import javax.swing.JMenuItem;
23
import javax.swing.JMenuItem;
24
24
25
import org.xml.sax.SAXException;
26
25
import org.openide.ErrorManager;
27
import org.openide.ErrorManager;
26
import org.openide.TopManager;
28
import org.openide.TopManager;
27
import org.openide.filesystems.*;
29
import org.openide.filesystems.*;
Lines 393-401 Link Here
393
        }
395
        }
394
396
395
        FileSystem[] arr = new FileSystem[home == null ? 2 : 3];
397
        FileSystem[] arr = new FileSystem[home == null ? 2 : 3];
396
        arr[0] = new ModuleLayeredFileSystem (user);
398
        try {
397
        if (home != null) {
399
            arr[0] = new ModuleLayeredFileSystem (user, null);
398
            arr[1] = new ModuleLayeredFileSystem (home);
400
            if (home != null) {
401
                arr[1] = new ModuleLayeredFileSystem (home, new File(userDir, "cache")); // NOI18N
402
            }
403
        } catch (SAXException saxe) {
404
            IOException ioe = new IOException(saxe.toString());
405
            ModuleLayeredFileSystem.err.annotate(ioe, saxe);
406
            throw ioe;
399
        }
407
        }
400
        FixedFileSystem.deflt = new FixedFileSystem
408
        FixedFileSystem.deflt = new FixedFileSystem
401
            ("org.netbeans.core.projects.FixedFileSystem", "Automatic Manifest Installation"); // NOI18N
409
            ("org.netbeans.core.projects.FixedFileSystem", "Automatic Manifest Installation"); // NOI18N
(-)openide/src/org/openide/filesystems/XMLFileSystem.java (-2 / +156 lines)
Lines 7-13 Link Here
7
 * http://www.sun.com/
7
 * http://www.sun.com/
8
 * 
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun
11
 * Microsystems, Inc. All Rights Reserved.
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
12
 */
13
13
Lines 16-28 Link Here
16
import java.lang.ref.*;
16
import java.lang.ref.*;
17
import java.io.*;
17
import java.io.*;
18
import java.lang.reflect.*;
18
import java.lang.reflect.*;
19
20
import java.beans.*;
19
import java.beans.*;
21
import java.util.*;
20
import java.util.*;
22
import java.net.*;
21
import java.net.*;
22
import java.util.zip.CRC32;
23
23
24
import org.openide.util.enum.EmptyEnumeration;
24
import org.openide.util.enum.EmptyEnumeration;
25
import org.openide.util.NbBundle;
25
import org.openide.util.NbBundle;
26
import org.openide.xml.XMLUtil;
26
27
27
import org.xml.sax.*;
28
import org.xml.sax.*;
28
import org.xml.sax.helpers.ParserFactory;
29
import org.xml.sax.helpers.ParserFactory;
Lines 202-207 Link Here
202
    }
203
    }
203
    
204
    
204
    private synchronized void setXmlUrls (URL[] urls, boolean validate) throws IOException, PropertyVetoException {
205
    private synchronized void setXmlUrls (URL[] urls, boolean validate) throws IOException, PropertyVetoException {
206
//long time = System.currentTimeMillis();
205
        ResourceElem rootElem;
207
        ResourceElem rootElem;
206
        String oldDisplayName = getDisplayName ();        
208
        String oldDisplayName = getDisplayName ();        
207
        if (urls.length == 0) {
209
        if (urls.length == 0) {
Lines 241-247 Link Here
241
		handler.urlContext = act;
243
		handler.urlContext = act;
242
		xp.parse(act.toString());
244
		xp.parse(act.toString());
243
            }
245
            }
246
//time = System.currentTimeMillis() - time;
247
//System.err.println("Parsing took " + time + "ms");
248
//time = System.currentTimeMillis();
244
            refreshChildrenInAtomicAction ((AbstractFolder)getRoot (),rootElem ); 
249
            refreshChildrenInAtomicAction ((AbstractFolder)getRoot (),rootElem ); 
250
//time = System.currentTimeMillis() - time;
251
//System.err.println("Notifying took " + time + "ms");
245
        } catch (IOException iox) {
252
        } catch (IOException iox) {
246
            urlsToXml = origUrls;                       
253
            urlsToXml = origUrls;                       
247
            throw iox;
254
            throw iox;
Lines 250-260 Link Here
250
            ExternalUtil.copyAnnotation (x,e);
257
            ExternalUtil.copyAnnotation (x,e);
251
            throw x;
258
            throw x;
252
        } finally {
259
        } finally {
260
            String cachename = System.getProperty("netbeans.cache.layers.filename");
261
            if (cachename != null && cachename.length() > 0) {
262
                // Refer to org.netbeans.core.projects.ModuleLayeredFileSystem and #20168.
263
                File cacheFile = new File(cachename);
264
                OutputStream os = new FileOutputStream(cacheFile);
265
                try {
266
                    writeOut(rootElem, os, Boolean.getBoolean("netbeans.cache.layers.prettyprint"), cacheFile.getParentFile());
267
                } finally {
268
                    os.close();
269
                }
270
            }
253
            rootElem = null;                        
271
            rootElem = null;                        
254
        }
272
        }
255
        firePropertyChange (PROP_DISPLAY_NAME, oldDisplayName, getDisplayName ());                            
273
        firePropertyChange (PROP_DISPLAY_NAME, oldDisplayName, getDisplayName ());                            
256
    }
274
    }
257
275
276
    private void writeOut(ResourceElem root, OutputStream out, boolean pretty, File datadir) throws IOException {
277
        Writer wr = new OutputStreamWriter(out, "UTF-8");
278
        wr.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
279
        wr.write("<!DOCTYPE filesystem PUBLIC \"-//NetBeans//DTD Filesystem 1.1//EN\" \"http://www.netbeans.org/dtds/filesystem-1_1.dtd\">\n");
280
        wr.write("<!-- Module layer cache generated by NetBeans. Do not edit. -->\n");
281
        wr.write("<filesystem");
282
        if(writeAttrs(wr, root.getAttr(false), 1, pretty)) {
283
            wr.write(">");
284
            if (pretty) wr.write('\n');
285
        }
286
        writeFolder(wr, root, 1, pretty, datadir);
287
        wr.write("</filesystem>\n");
288
        wr.close();
289
    }
290
    
291
    private static final String SPACES = "                                                                                        "; // NOI18N
292
    private static final int SPACES_LENGTH = SPACES.length();
293
    private static final int INDENT = 4;
294
    private String space(int n) {
295
        int size = n * INDENT;
296
        if (size <= SPACES_LENGTH) {
297
            return SPACES.substring(0, size);
298
        } else {
299
            StringBuffer buf = new StringBuffer(size);
300
            for (int i = 0; i < size; i++) buf.append(' ');
301
            return buf.toString();
302
        }
303
    }
304
    
305
    private void writeFolder(Writer wr, ResourceElem elem, int depth, boolean pretty, File datadir) throws IOException {
306
        if (elem.children == null) return;
307
        Iterator it = new TreeSet(elem.children.keySet()).iterator();
308
        
309
        while (it.hasNext()) {
310
            String name = (String)it.next();
311
            ResourceElem child = (ResourceElem)elem.children.get(name);
312
            
313
            if( child.isFolder()) {
314
                if (pretty) wr.write(space(depth));
315
                wr.write("<folder name=\"");
316
                wr.write(XMLUtil.toAttributeValue(name));
317
                wr.write('"');
318
                if(writeAttrs(wr, child.getAttr(false), depth + 1, pretty)) {
319
                    wr.write('>');
320
                    if (pretty) wr.write('\n');
321
                }
322
                writeFolder(wr, child, depth + 1, pretty, datadir);
323
                if (pretty) wr.write(space(depth));
324
                wr.write("</folder>");
325
                if (pretty) wr.write('\n');
326
            } else {
327
                String uri = child.getURI();
328
                if (pretty) wr.write(space(depth));
329
                wr.write("<file name=\"");
330
                wr.write(XMLUtil.toAttributeValue(name));
331
                byte[] content = child.getContent();
332
                if (content != null) {
333
                    if (uri != null) throw new IOException("url attr and contents too: url=" + uri + " content=" + new String(content) + " file name=" + name); // NOI18N
334
                    CRC32 crc = new CRC32();
335
                    crc.update(content);
336
                    File data = new File(datadir, "data_" + Long.toHexString(crc.getValue())); // NOI18N
337
                    uri = data.toURL().toString();
338
                    OutputStream os = new FileOutputStream(data);
339
                    try {
340
                        os.write(content);
341
                    } finally {
342
                        os.close();
343
                    }
344
                }
345
                if (uri != null) {
346
                    wr.write("\" url=\"");
347
                    URL[] ctxt = child.getUrlContext();
348
                    if (ctxt == null || ctxt.length != 1) throw new IOException("Weird urlContent: " + Arrays.asList(ctxt)); // NOI18N
349
                    wr.write(XMLUtil.toAttributeValue(new URL(ctxt[0], uri).toString()));
350
                }
351
                wr.write('"');
352
                /*
353
                if(content != null) {
354
                    empty = false;
355
                    String contents = new String(content);
356
                    int idx = -1;
357
                    while ((idx = contents.indexOf("]]>", idx)) != -1) {
358
                        // E.g. "foo]]>bar" -> idx = 3
359
                        // escaped to "foo]]>]]&gt;<![CDATA[bar"
360
                        // and start searching now at 21
361
                        contents = contents.substring(0, idx) + "]]>]]&gt;<![CDATA[" + contents.substring(idx + 3);
362
                        idx += 18;
363
                    }
364
                    wr.write(">\n");
365
                    if (pretty) wr.write(space(depth + 1));
366
                    wr.write("<![CDATA[");
367
                    wr.write(contents);
368
                    wr.write("]]");
369
                    if (writeAttrs(wr, child.getAttr(false), depth + 1, pretty)) {
370
                        wr.write('>');
371
                        if (pretty) wr.write('\n');
372
                    }
373
                 */
374
                if (writeAttrs(wr, child.getAttr(false), depth + 1, pretty)) {
375
                    wr.write("/>");
376
                    if (pretty) wr.write('\n');
377
                } else {
378
                    if (pretty) wr.write(space(depth));
379
                    wr.write("</file>");
380
                    if (pretty) wr.write('\n');
381
                }
382
            }
383
        }
384
        
385
    }
386
387
    private boolean writeAttrs( Writer wr, XMLMapAttr attrs, int depth, boolean pretty) throws IOException {
388
        if (attrs == null) return true; // empty attrs
389
390
        Iterator attri = new TreeSet(attrs.map.keySet()).iterator();
391
        if (!attri.hasNext()) return true;
392
393
        wr.write('>');
394
        if (pretty) wr.write('\n');
395
        while (attri.hasNext()) {
396
            String aname = (String)attri.next();
397
            XMLMapAttr.Attr a = (XMLMapAttr.Attr)attrs.map.get(aname);
398
            if (pretty) wr.write(space(depth));
399
            wr.write("<attr name=\"");
400
            wr.write(XMLUtil.toAttributeValue(aname));
401
            wr.write("\" ");
402
            wr.write(a.getKey());
403
            wr.write("=\"");
404
            wr.write(XMLUtil.toAttributeValue(a.getValue()));
405
            wr.write("\"/>");
406
            if (pretty) wr.write('\n');
407
        }
408
        
409
        return false;
410
    }
411
    
258
    /**
412
    /**
259
    * @return if value of lastModified should be cached
413
    * @return if value of lastModified should be cached
260
    */    
414
    */    

Return to bug 20168