KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > vfs > MemoryPath


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.vfs;
31
32 import com.caucho.util.Alarm;
33 import com.caucho.util.ByteBuffer;
34 import com.caucho.util.L10N;
35
36 import java.io.FileNotFoundException JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.Map JavaDoc;
40
41 public class MemoryPath extends FilesystemPath {
42   private static L10N L = new L10N(MemoryPath.class);
43
44   private Node _rootNode;
45
46   protected MemoryPath(FilesystemPath root,
47                        String JavaDoc userPath, Map JavaDoc<String JavaDoc,Object JavaDoc> attributes,
48                        String JavaDoc path)
49   {
50     super(root, userPath, path);
51
52     if (root instanceof MemoryPath)
53       _rootNode = ((MemoryPath) root)._rootNode;
54     else
55       _root = this;
56   }
57
58   public MemoryPath()
59   {
60     this(null, "/", null, "/");
61
62     _root = this;
63     _rootNode = new Node("", null, Node.DIR);
64   }
65
66   public Path fsWalk(String JavaDoc userPath,
67                      Map JavaDoc<String JavaDoc,Object JavaDoc> attributes,
68                      String JavaDoc path)
69   {
70     return new MemoryPath(_root, userPath, attributes, path);
71   }
72
73   public String JavaDoc getScheme()
74   {
75     return "memory";
76   }
77
78   public String JavaDoc getURL()
79   {
80     return getScheme() + ":" + getFullPath();
81   }
82
83   public boolean exists()
84   {
85     synchronized (_rootNode) {
86       return lookupAll() != null;
87     }
88   }
89
90   private Node lookupAll()
91   {
92     String JavaDoc fullPath = getFullPath();
93
94     int head = 0;
95     Node node = _rootNode;
96
97     while (node != null && head < fullPath.length()) {
98       int tail = fullPath.indexOf('/', head);
99
100       if (tail == -1) {
101     if (head < fullPath.length())
102       return node.lookup(fullPath.substring(head));
103     else
104       return node;
105       }
106
107       if (head != tail)
108         node = node.lookup(fullPath.substring(head, tail));
109
110       head = tail + 1;
111     }
112
113     return node;
114   }
115
116   private Node lookupAllButTail()
117   {
118     String JavaDoc fullPath = getFullPath();
119
120     int head = 0;
121     Node node = this._rootNode;
122
123     while (node != null && head < fullPath.length()) {
124       int tail = fullPath.indexOf('/', head);
125
126       if (tail == -1 || tail == fullPath.length() - 1)
127         return node;
128
129       if (head != tail)
130         node = node.lookup(fullPath.substring(head, tail));
131
132       head = tail + 1;
133     }
134
135     return node;
136   }
137
138   public boolean isDirectory()
139   {
140     synchronized (_rootNode) {
141       Node node = lookupAll();
142
143       return node != null && node.type == node.DIR;
144     }
145   }
146
147   public boolean isFile()
148   {
149     synchronized (_rootNode) {
150       Node node = lookupAll();
151
152       return node != null && node.type == node.FILE;
153     }
154   }
155
156   public boolean isObject()
157   {
158     synchronized (_rootNode) {
159       Node node = lookupAll();
160
161       return node != null && node.type == node.OBJECT;
162     }
163   }
164
165   public boolean setExecutable(boolean isExecutable)
166   {
167     synchronized (_rootNode) {
168       Node node = lookupAll();
169
170       if (node != null && (node.type == node.FILE || node.type == node.DIR)) {
171         node.isExecutable = isExecutable;
172         return true;
173       }
174       else
175         return false;
176     }
177   }
178
179   public boolean isExecutable()
180   {
181     synchronized (_rootNode) {
182       Node node = lookupAll();
183
184       if (node != null && (node.type == node.FILE || node.type == node.DIR))
185         return node.isExecutable;
186       else
187         return false;
188     }
189   }
190
191   public long getLength()
192   {
193     synchronized (_rootNode) {
194       Node node = lookupAll();
195
196       if (node != null && node.type == node.FILE)
197         return ((ByteBuffer) node.data).length();
198       else
199         return 0;
200     }
201   }
202
203   public long getLastModified()
204   {
205     synchronized (_rootNode) {
206       Node node = lookupAll();
207
208       return node == null ? 0 : node.lastModified;
209     }
210   }
211
212   public boolean canRead()
213   {
214     synchronized (_rootNode) {
215       Node node = lookupAll();
216
217       return node != null;
218     }
219   }
220
221   public boolean canWrite()
222   {
223     synchronized (_rootNode) {
224       Node node = lookupAll();
225
226       return node != null;
227     }
228   }
229
230   public String JavaDoc []list()
231   {
232     synchronized (_rootNode) {
233       Node node = lookupAll();
234
235       if (node == null || node.data != null)
236         return new String JavaDoc[0];
237
238       ArrayList JavaDoc<String JavaDoc> a = new ArrayList JavaDoc<String JavaDoc>();
239       for (Node child = node.firstChild; child != null; child = child.next) {
240         a.add(child.name);
241       }
242
243       return (String JavaDoc []) a.toArray(new String JavaDoc[a.size()]);
244     }
245   }
246
247   // XXX: could have iterator
248

249   private boolean mkdir(boolean parent)
250   {
251     synchronized (_rootNode) {
252       String JavaDoc fullPath = getFullPath();
253
254       int head = 0;
255       Node node = this._rootNode;
256
257       while (node != null && head < fullPath.length()) {
258         int tail = fullPath.indexOf('/', head);
259         String JavaDoc name;
260
261         if (tail == head) {
262           head = tail + 1;
263           continue;
264         }
265         if (tail == -1) {
266           name = fullPath.substring(head);
267           if (node.lookup(name) != null)
268             return false;
269           node.createDir(name);
270           return true;
271         }
272
273         name = fullPath.substring(head, tail);
274         Node next = node.lookup(name);
275
276         if (next == null && parent)
277           next = node.createDir(name);
278
279         if (next == null || next.type != next.DIR)
280           return false;
281
282         node = next;
283         head = tail + 1;
284       }
285
286       return false;
287     }
288   }
289
290   public boolean mkdir()
291   {
292     return mkdir(false);
293   }
294
295   public boolean mkdirs()
296   {
297     return mkdir(true);
298   }
299
300   public boolean remove()
301   {
302     synchronized (_rootNode) {
303       Node node = lookupAllButTail();
304       String JavaDoc tail = getTail();
305
306       if (node == null)
307         return false;
308
309       Node child = node.lookup(tail);
310       if (child == null || child.firstChild != null)
311         return false;
312
313       node.remove(tail);
314
315       return true;
316     }
317   }
318
319   public boolean renameTo(Path path)
320   {
321     synchronized (_rootNode) {
322       if (! (path instanceof MemoryPath))
323         return false;
324
325       MemoryPath file = (MemoryPath) path;
326       if (_rootNode != file._rootNode)
327         return false;
328
329       Node oldParent = lookupAllButTail();
330       if (oldParent == null)
331         return false;
332
333       Node child = oldParent.lookup(getTail());
334       if (child == null)
335         return false;
336
337       Node newParent = file.lookupAllButTail();
338       if (newParent == null || newParent.type != Node.DIR)
339         return false;
340
341       if (newParent.lookup(file.getTail()) != null)
342         return false;
343
344       oldParent.remove(getTail());
345       child.name = file.getTail();
346       newParent.create(child);
347
348       return true;
349     }
350   }
351
352   public StreamImpl openReadImpl() throws IOException JavaDoc
353   {
354     synchronized (_rootNode) {
355       Node node = lookupAll();
356
357       if (node == null)
358         throw new FileNotFoundException JavaDoc(getPath());
359       else if (node.type != node.FILE)
360         throw new IOException JavaDoc("is directory: " + getPath());
361
362       return new MemoryStream(node, (ByteBuffer) node.data, false);
363     }
364   }
365
366   public StreamImpl openWriteImpl() throws IOException JavaDoc
367   {
368     return openWriteImpl(false);
369   }
370
371   public StreamImpl openAppendImpl() throws IOException JavaDoc
372   {
373     return openWriteImpl(true);
374   }
375
376   private StreamImpl openWriteImpl(boolean append)
377     throws IOException JavaDoc
378   {
379     synchronized (_rootNode) {
380       Node node = lookupAllButTail();
381       String JavaDoc tail = getTail();
382
383       if (node == null || node.type != Node.DIR)
384         throw new IOException JavaDoc(L.l("can't create file {0}", getFullPath()));
385
386       Node child = node.lookup(tail);
387       if (child == null)
388         child = node.createFile(tail, new ByteBuffer(256));
389       else if (! append) {
390         node.remove(tail);
391         child = node.createFile(tail, new ByteBuffer(256));
392       }
393       else if (child.type != child.FILE)
394         throw new IOException JavaDoc(L.l("can't create file {0}", getFullPath()));
395       return new MemoryStream(child, (ByteBuffer) child.data, true);
396     }
397   }
398
399   public Object JavaDoc getValue() throws IOException JavaDoc
400   {
401     synchronized (_rootNode) {
402       Node node = lookupAll();
403
404       if (node == null || node.type != node.OBJECT)
405         throw new IOException JavaDoc("no such object: " + getFullPath().toString());
406
407       return node.data;
408     }
409   }
410
411   synchronized public void setValue(Object JavaDoc object) throws IOException JavaDoc
412   {
413     synchronized (_rootNode) {
414       Node node = lookupAllButTail();
415       String JavaDoc tail = getTail();
416
417       if (node == null || node.type != Node.DIR)
418         throw new IOException JavaDoc(L.l("can't set object {0}", getFullPath()));
419
420       Node child = node.lookup(tail);
421       if (child == null)
422         child = node.createObject(tail, object);
423       else if (child.type == child.OBJECT)
424         child.data = object;
425       else
426         throw new IOException JavaDoc(L.l("can't set object {0}", getFullPath()));
427     }
428   }
429
430   public Path copyCache()
431   {
432     return null;
433   }
434
435   public MemoryPath copyDeep()
436   {
437     MemoryPath path = new MemoryPath();
438
439     path._rootNode = _rootNode.copy();
440
441     return path;
442   }
443
444   public boolean equals(Object JavaDoc o)
445   {
446     if (o == null || ! getClass().equals(o.getClass()))
447       return false;
448
449     MemoryPath mp = (MemoryPath) o;
450
451     return getURL().equals(mp.getURL()) && _rootNode == mp._rootNode;
452   }
453
454   private static class Node {
455     static final int DIR = 0;
456     static final int FILE = DIR + 1;
457     static final int OBJECT = FILE + 1;
458
459     String JavaDoc name;
460     Node next;
461     Node firstChild;
462     long lastModified;
463     int type;
464     Object JavaDoc data;
465     boolean isExecutable;
466
467     Node(String JavaDoc name, Object JavaDoc data, int type)
468     {
469       if (name == null)
470         throw new NullPointerException JavaDoc();
471       this.name = name;
472       this.data = data;
473       this.type = type;
474       this.lastModified = Alarm.getCurrentTime();
475     }
476
477     Node lookup(String JavaDoc name)
478     {
479       for (Node node = firstChild; node != null; node = node.next) {
480         if (node.name.equals(name)) {
481           return node;
482         }
483       }
484
485       return null;
486     }
487
488     private Node create(String JavaDoc name, Object JavaDoc data, int type)
489     {
490       for (Node node = firstChild; node != null; node = node.next) {
491         if (node.name.equals(name))
492           return null;
493       }
494
495       Node newNode = new Node(name, data, type);
496       newNode.next = firstChild;
497       firstChild = newNode;
498       lastModified = Alarm.getCurrentTime();
499
500       return newNode;
501     }
502
503     Node createDir(String JavaDoc name)
504     {
505       return create(name, null, DIR);
506     }
507
508     Node createFile(String JavaDoc name, ByteBuffer data)
509     {
510       return create(name, data, FILE);
511     }
512
513     Node createObject(String JavaDoc name, Object JavaDoc data)
514     {
515       return create(name, data, OBJECT);
516     }
517
518     Node create(Node newNode)
519     {
520       newNode.next = firstChild;
521       firstChild = newNode;
522
523       return newNode;
524     }
525
526     boolean remove(String JavaDoc name)
527     {
528       Node last = null;
529       for (Node node = firstChild; node != null; node = node.next) {
530         if (node.name.equals(name)) {
531           if (node.firstChild != null)
532             return false;
533
534           if (last != null)
535             last.next = node.next;
536           else
537             firstChild = node.next;
538
539           return true;
540         }
541
542         last = node;
543       }
544
545       return false;
546     }
547
548     Node copy()
549     {
550       Node newNode = new Node(name, data, type);
551
552       if (type == DIR) {
553         for (Node child = firstChild; child != null; child = child.next) {
554           Node newChild = child.copy();
555
556           newChild.next = newNode.firstChild;
557           newNode.firstChild = newChild;
558         }
559       }
560
561       return newNode;
562     }
563   };
564
565   public class MemoryStream extends StreamImpl {
566     Node _node;
567     ByteBuffer _bb;
568     int _offset;
569     boolean _write;
570
571     MemoryStream(Node node, ByteBuffer bb, boolean write)
572     {
573       setPath(MemoryPath.this);
574
575       _node = node;
576       if (write)
577         node.lastModified = Alarm.getCurrentTime();
578       _write = write;
579
580       _bb = bb;
581     }
582
583     public int getAvailable()
584     {
585       return _bb.length() - _offset;
586     }
587
588     public boolean canRead() { return true; }
589
590     public int read(byte []buf, int bufOffset, int length) throws IOException JavaDoc
591     {
592       synchronized (_bb) {
593         int sublen = _bb.length() - _offset;
594         if (length < sublen)
595           sublen = length;
596
597         if (sublen <= 0)
598           return -1;
599
600         System.arraycopy(_bb.getBuffer(), _offset, buf, bufOffset, sublen);
601         _offset += sublen;
602
603         return sublen;
604       }
605     }
606
607     public int getPosition()
608     {
609       return _offset;
610     }
611
612     public void seekStart(long pos)
613     {
614       _offset = (int) pos;
615       if (_offset < 0)
616         _offset = 0;
617       if (_offset > _bb.length())
618         _offset = _bb.length();
619     }
620
621     public boolean canWrite() { return true; }
622
623     /**
624      * Writes a buffer to the underlying stream.
625      *
626      * @param buffer the byte array to write.
627      * @param offset the offset into the byte array.
628      * @param length the number of bytes to write.
629      * @param isEnd true when the write is flushing a close.
630      */

631     public void write(byte []buf, int offset, int length, boolean isEnd)
632       throws IOException JavaDoc
633     {
634       synchronized (_bb) {
635         _bb.add(buf, offset, length);
636       }
637
638       _node.lastModified = Alarm.getCurrentTime();
639     }
640   }
641 }
642
Popular Tags