KickJava   Java API By Example, From Geeks To Geeks.

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


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.CharBuffer;
33 import com.caucho.util.Crc64;
34 import com.caucho.util.L10N;
35 import com.caucho.util.LruCache;
36 import com.caucho.util.RandomUtil;
37
38 import java.io.File JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.OutputStream JavaDoc;
41 import java.security.cert.Certificate JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.Map JavaDoc;
45
46 /**
47  * A virtual filesystem path, essentially represented by a URL.
48  * Its API resembles a combination of the JDK File object and the URL object.
49  *
50  * <p>Paths are, in general, given with the canonical file separator of
51  * forward slash, '/'. The filesystems will take care of any necessary
52  * translation.
53  *
54  * <p>Currently available filesystems:
55  * <dl>
56  * <dt>file:/path/to/file<dd>Java file
57  * <dt>http://host:port/path/name?query<dd>HTTP request
58  * <dt>tcp://host:port<dd>Raw TCP connection
59  * <dt>mailto:user@host?subject=foo&cc=user2<dd>Mail to a user.
60  * <dt>log:/group/subgroup/item<dd>Logging based on the configuration file.
61  * <dt>stdout:<dd>System.out
62  * <dt>stderr:<dd>System.err
63  * <dt>null:<dd>The equivalent of /dev/null
64  * </dl>
65  */

66 public abstract class Path {
67   protected final static L10N L = new L10N(Path.class);
68
69   private static final Integer JavaDoc LOCK = new Integer JavaDoc(0);
70
71   private static final LruCache<PathKey,Path> _pathLookupCache
72     = new LruCache<PathKey,Path>(8192);
73
74   private static boolean _isTestWindows;
75
76   protected static char _separatorChar = File.separatorChar;
77   protected static char _pathSeparatorChar = File.pathSeparatorChar;
78   private static String JavaDoc _newline;
79   
80   private static final PathKey _key = new PathKey();
81
82   private static final SchemeMap DEFAULT_SCHEME_MAP = new SchemeMap();
83   
84   private static SchemeMap _defaultSchemeMap;
85
86   protected SchemeMap _schemeMap = _defaultSchemeMap;
87
88   /**
89    * Creates a new Path object.
90    *
91    * @param root the new Path root.
92    */

93   protected Path(Path root)
94   {
95     if (root != null)
96       _schemeMap = root._schemeMap;
97     else if (_defaultSchemeMap != null)
98       _schemeMap = _defaultSchemeMap;
99     else
100       _schemeMap = DEFAULT_SCHEME_MAP;
101   }
102
103   /**
104    * Looks up a new path based on the old path.
105    *
106    * @param name relative url to the new path
107    * @return The new path.
108    */

109   public final Path lookup(String JavaDoc name)
110   {
111     return lookup(name, null);
112   }
113
114   /**
115     * Returns a new path relative to the current one.
116     *
117     * <p>Path only handles scheme:xxx. Subclasses of Path will specialize
118     * the xxx.
119     *
120     * @param userPath relative or absolute path, essentially any url.
121     * @param newAttributes attributes for the new path.
122     *
123     * @return the new path or null if the scheme doesn't exist
124     */

125    public Path lookup(String JavaDoc userPath, Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes)
126    {
127      if (newAttributes != null)
128        return lookupImpl(userPath, newAttributes);
129      
130      synchronized (_key) {
131        _key.init(this, userPath);
132
133        Path path = _pathLookupCache.get(_key);
134
135        if (path != null) {
136      return path.cacheCopy();
137        }
138      }
139
140      Path path = lookupImpl(userPath, null);
141
142      synchronized (_key) {
143        Path copy = path.cacheCopy();
144
145        if (copy != null) {
146      _pathLookupCache.putIfNew(new PathKey(this, userPath), copy);
147        }
148      }
149
150      return path;
151    }
152
153   /**
154    * Returns a new path relative to the current one.
155    *
156    * <p>Path only handles scheme:xxx. Subclasses of Path will specialize
157    * the xxx.
158    *
159    * @param userPath relative or absolute path, essentially any url.
160    * @param newAttributes attributes for the new path.
161    *
162    * @return the new path or null if the scheme doesn't exist
163    */

164   public Path lookupImpl(String JavaDoc userPath, Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes)
165   {
166     if (userPath == null)
167       return lookupImpl(getPath(), newAttributes);
168
169     String JavaDoc scheme = scanScheme(userPath);
170
171     if (scheme == null)
172       return schemeWalk(userPath, newAttributes, userPath, 0);
173
174     Path path;
175
176     SchemeMap schemeMap = _schemeMap;
177
178     // Special case to handle the windows special schemes
179
// c:xxx -> file:/c:xxx
180
if (isWindows()) {
181       int length = scheme.length();
182       int ch;
183
184       if (length == 1 &&
185           ((ch = scheme.charAt(0)) >= 'a' && ch <= 'z' ||
186             ch >= 'A' && ch <= 'Z')) {
187         path = schemeMap.get("file");
188
189         if (path != null)
190           return path.schemeWalk(userPath, newAttributes, "/" + userPath, 0);
191       }
192     }
193
194     path = schemeMap.get(scheme);
195
196     // assume the foo:bar is a subfile
197
if (path == null)
198       return schemeWalk(userPath, newAttributes, userPath, 0);
199
200     return path.schemeWalk(userPath, newAttributes,
201                            userPath, scheme.length() + 1);
202   }
203
204   /**
205    * Looks up a path using the local filesystem conventions. e.g. on
206    * Windows, a name of 'd:\foo\bar\baz.html' will look up the baz.html
207    * on drive d.
208    *
209    * @param name relative url using local filesystem separators.
210    */

211   public final Path lookupNative(String JavaDoc name)
212   {
213     return lookupNative(name, null);
214   }
215   /**
216    * Looks up a native path, adding attributes.
217    */

218   public Path lookupNative(String JavaDoc name, Map JavaDoc<String JavaDoc,Object JavaDoc> attributes)
219   {
220     return lookup(name, attributes);
221   }
222
223   /**
224    * Returns a native path relative to this native path if the passed path
225    * is relative to this path, or an absolute path if the passed path is not
226    * relative to this path.
227    */

228   public String JavaDoc lookupRelativeNativePath(Path path)
229   {
230     String JavaDoc thisNative = getNativePath();
231     String JavaDoc pathNative = path.getNativePath();
232
233     if (pathNative.startsWith(thisNative)) {
234       int i = thisNative.length();
235
236       while (i < pathNative.length()) {
237         if (pathNative.charAt(i) != getFileSeparatorChar())
238           break;
239
240         i++;
241       }
242
243       return i == pathNative.length() ? "" : pathNative.substring(i);
244     }
245     else
246       return pathNative;
247   }
248
249   /**
250    * Looks up all the resources matching a name. (Generally only useful
251    * with MergePath.
252    */

253   public ArrayList JavaDoc<Path> getResources(String JavaDoc name)
254   {
255     ArrayList JavaDoc<Path> list = new ArrayList JavaDoc<Path>();
256     Path path = lookup(name);
257     if (path.exists())
258       list.add(path);
259
260     return list;
261   }
262
263   /**
264    * Looks up all the existing resources. (Generally only useful
265    * with MergePath.
266    */

267   public ArrayList JavaDoc<Path> getResources()
268   {
269     ArrayList JavaDoc<Path> list = new ArrayList JavaDoc<Path>();
270
271     //if (exists())
272
list.add(this);
273
274     return list;
275   }
276
277   /**
278    * Returns the parent path.
279    */

280   public Path getParent()
281   {
282     return this;
283   }
284
285   /**
286    * Returns the scheme portion of a uri. Since schemes are case-insensitive,
287    * normalize them to lower case.
288    */

289   protected String JavaDoc scanScheme(String JavaDoc uri)
290   {
291     int i = 0;
292     if (uri == null)
293       return null;
294
295     int length = uri.length();
296     if (length == 0)
297       return null;
298
299     int ch = uri.charAt(0);
300     if (ch >= 'a' && ch <= 'z' ||
301     ch >= 'A' && ch <= 'Z') {
302       for (i = 1; i < length; i++) {
303     ch = uri.charAt(i);
304
305     if (ch == ':')
306       return uri.substring(0, i).toLowerCase();
307
308     if (! (ch >= 'a' && ch <= 'z' ||
309            ch >= 'A' && ch <= 'Z' ||
310            ch >= '0' && ch <= '0' ||
311            ch == '+' || ch == '-' || ch == '.'))
312       break;
313       }
314     }
315
316     return null;
317   }
318
319   /**
320    * Path-specific lookup. Path implementations will override this.
321    *
322    * @param userPath the user's lookup() path.
323    * @param newAttributes the attributes for the new path.
324    * @param newPath the lookup() path
325    * @param offset offset into newPath to start lookup.
326    *
327    * @return the found path
328    */

329   abstract protected Path schemeWalk(String JavaDoc userPath,
330                      Map JavaDoc<String JavaDoc,Object JavaDoc> newAttributes,
331                                      String JavaDoc newPath, int offset);
332
333   /**
334    * Returns the full url for the given path.
335    */

336   public String JavaDoc getURL()
337   {
338     return escapeURL(getScheme() + ":" + getFullPath());
339   }
340   
341   /**
342    * Returns the url scheme
343    */

344   public abstract String JavaDoc getScheme();
345   /**
346    * Returns the hostname
347    */

348   public String JavaDoc getHost()
349   {
350     throw new UnsupportedOperationException JavaDoc();
351   }
352   /**
353    * Returns the port.
354    */

355   public int getPort()
356   {
357     throw new UnsupportedOperationException JavaDoc();
358   }
359   /**
360    * Returns the path. e.g. for HTTP, returns the part after the
361    * host and port.
362    */

363   public abstract String JavaDoc getPath();
364
365   /**
366    * Returns the last segment of the path.
367    *
368    * <p>e.g. for http://www.caucho.com/products/index.html, getTail()
369    * returns 'index.html'
370    */

371   public String JavaDoc getTail()
372   {
373     return "";
374   }
375   /**
376    * Returns the query string of the path.
377    */

378   public String JavaDoc getQuery()
379   {
380     throw new UnsupportedOperationException JavaDoc();
381   }
382
383   /**
384    * Returns the native representation of the path.
385    *
386    * On Windows, getNativePath() returns 'd:\\foo\bar.html',
387    * getPath() returns '/d:/foo/bar.html'
388    */

389   public String JavaDoc getNativePath()
390   {
391     return getFullPath();
392   }
393   /**
394    * Returns the last string used as a lookup, if available. This allows
395    * parsers to give intelligent error messages, with the user's path
396    * instead of the whole path.
397    *
398    * The following will print '../test.html':
399    * <code><pre>
400    * Path path = Pwd.lookup("/some/dir").lookup("../test.html");
401    * System.out.println(path.getUserPath());
402    * </pre></code>
403    *
404    */

405   public String JavaDoc getUserPath()
406   {
407     return getPath();
408   }
409
410   /**
411    * Sets the user path. Useful for temporary files caching another
412    * URL.
413    */

414   public void setUserPath(String JavaDoc userPath)
415   {
416   }
417   /**
418    * Returns the full path, including the restricted root.
419    *
420    * <p>For the following, path.getPath() returns '/file.html', while
421    * path.getFullPath() returns '/chroot/file.html'.
422    * <code><pre>
423    * Path chroot = Pwd.lookup("/chroot").createRoot();
424    * Path path = chroot.lookup("/file.html");
425    * </pre></code>
426    */

427   public String JavaDoc getFullPath()
428   {
429     return getPath();
430   }
431
432   /**
433    * For union paths like MergePath, return the relative path into
434    * that path.
435    */

436   public String JavaDoc getRelativePath()
437   {
438     return getPath();
439   }
440
441   /**
442    * Returns any signing certificates, e.g. for jar signing.
443    */

444   public Certificate JavaDoc []getCertificates()
445   {
446     return null;
447   }
448
449   /**
450    * Tests if the file exists.
451    */

452   public boolean exists()
453   {
454     return false;
455   }
456
457   /**
458    * Returns the mime-type of the file.
459    * <p>Mime-type ignorant filesystems return 'application/octet-stream'
460    */

461   public String JavaDoc getContentType()
462   {
463     return "application/octet-stream";
464   }
465
466   /**
467    * Tests if the path refers to a directory.
468    */

469   public boolean isDirectory()
470   {
471     return false;
472   }
473
474   /**
475    * Tests if the path refers to a file.
476    */

477   public boolean isFile()
478   {
479     return false;
480   }
481
482   /**
483    * Tests if the path refers to a symbolic link.
484    */

485   public boolean isLink()
486   {
487     return false;
488   }
489
490   /**
491    * Tests if the path refers to a socket.
492    */

493   public boolean isSocket()
494   {
495     return false;
496   }
497
498   /**
499    * Tests if the path refers to a FIFO.
500    */

501   public boolean isFIFO()
502   {
503     return false;
504   }
505
506   /**
507    * Tests if the path refers to a block device.
508    */

509   public boolean isBlockDevice()
510   {
511     return false;
512   }
513
514   /**
515    * Tests if the path refers to a block device.
516    */

517   public boolean isCharacterDevice()
518   {
519     return false;
520   }
521
522   /**
523    * Tests if the path is marked as executable
524    */

525   public boolean isExecutable()
526   {
527     return false;
528   }
529
530   /**
531    * Change the executable status of the of the oath.
532    *
533    * @throws UnsupportedOperationException
534    */

535   public boolean setExecutable(boolean isExecutable)
536   {
537     return false;
538   }
539
540   /**
541    * Tests if the path refers to a symbolic link.
542    */

543   public boolean isSymbolicLink()
544   {
545     return false;
546   }
547
548   /**
549    * Tests if the path refers to a hard link.
550    */

551   public boolean isHardLink()
552   {
553     return false;
554   }
555
556   /**
557    * Tests if the path refers to an object.
558    */

559   public boolean isObject()
560   {
561     return false;
562   }
563
564   /**
565    * Returns the length of the file in bytes.
566    * @return 0 for non-files
567    */

568   public long getLength()
569   {
570     return 0;
571   }
572
573   /**
574    * Returns the last modified time of the file. According to the jdk,
575    * this may not correspond to the system time.
576    * @return 0 for non-files.
577    */

578   public long getLastModified()
579   {
580     return 0;
581   }
582
583   public void setLastModified(long time)
584   {
585   }
586
587   /**
588    * Returns the last access time of the file.
589    *
590    * @return 0 for non-files.
591    */

592   public long getLastAccessTime()
593   {
594     return getLastModified();
595   }
596
597   /**
598    * Returns the create time of the file.
599    *
600    * @return 0 for non-files.
601    */

602   public long getCreateTime()
603   {
604     return getLastModified();
605   }
606
607   /**
608    * Tests if the file can be read.
609    */

610   public boolean canRead()
611   {
612     return false;
613   }
614
615   /**
616    * Tests if the file can be written.
617    */

618   public boolean canWrite()
619   {
620     return false;
621   }
622
623   //
624
// POSIX stat() related calls
625
//
626

627   /**
628    * Returns equivalent of struct stat.st_dev if appropriate.
629    */

630   public long getDevice()
631   {
632     return 0;
633   }
634
635   /**
636    * Returns equivalent of struct stat.st_ino if appropriate.
637    */

638   public long getInode()
639   {
640     return 0;
641   }
642
643   /**
644    * Returns equivalent of struct stat.st_mode if appropriate.
645    */

646   public int getMode()
647   {
648     return 0;
649   }
650
651   /**
652    * Returns equivalent of struct stat.st_nlink if appropriate.
653    */

654   public int getNumberOfLinks()
655   {
656     return 0;
657   }
658
659   /**
660    * Returns equivalent of struct stat.st_uid if appropriate.
661    */

662   public int getUser()
663   {
664     return 0;
665   }
666
667   /**
668    * Returns equivalent of struct stat.st_gid if appropriate.
669    */

670   public int getGroup()
671   {
672     return 0;
673   }
674
675   /**
676    * Returns equivalent of struct stat.st_rdev if appropriate.
677    */

678   public long getDeviceId()
679   {
680     return 0;
681   }
682
683   /**
684    * Returns equivalent of struct stat.st_blksize if appropriate.
685    */

686   public long getBlockSize()
687   {
688     return 0;
689   }
690
691   /**
692    * Returns equivalent of struct stat.st_blocks if appropriate.
693    */

694   public long getBlockCount()
695   {
696     return 0;
697   }
698
699   /**
700    * Returns equivalent of struct stat.st_ctime if appropriate.
701    */

702   public long getLastStatusChangeTime()
703   {
704     return 0;
705   }
706
707   /**
708    * Tests if the file can be read.
709    */

710   public boolean canExecute()
711   {
712     return canRead();
713   }
714
715   /**
716    * Changes the group
717    */

718   public boolean changeGroup(int gid)
719     throws IOException JavaDoc
720   {
721     return false;
722   }
723
724   /**
725    * Changes the group
726    */

727   public boolean changeGroup(String JavaDoc groupName)
728     throws IOException JavaDoc
729   {
730     return false;
731   }
732
733   /**
734    * Changes the permissions
735    *
736    * @return true if successful
737    */

738   public boolean chmod(int value)
739   {
740     return false;
741   }
742
743   public int getOwner()
744   {
745     return 0;
746   }
747
748   /**
749    * Changes the owner
750    *
751    * @return true if successful
752    */

753   public boolean changeOwner(int uid)
754     throws IOException JavaDoc
755   {
756     return false;
757   }
758
759   /**
760    * Changes the owner
761    *
762    * @return true if successful
763    */

764   public boolean changeOwner(String JavaDoc ownerName)
765     throws IOException JavaDoc
766   {
767     return false;
768   }
769
770   public long getDiskSpaceFree()
771   {
772     return 0;
773   }
774
775   public long getDiskSpaceTotal()
776   {
777     return 0;
778   }
779
780   /**
781    * @return The contents of this directory or null if the path does not
782    * refer to a directory.
783    */

784   public String JavaDoc []list() throws IOException JavaDoc
785   {
786     return new String JavaDoc[0];
787   }
788
789   /**
790    * Returns a jdk1.2 Iterator for the contents of this directory.
791    */

792   public Iterator JavaDoc<String JavaDoc> iterator() throws IOException JavaDoc
793   {
794     return new ArrayIterator(list());
795   }
796
797   /**
798    * Creates the directory named by this path.
799    * @return true if successful.
800    */

801   public boolean mkdir() throws IOException JavaDoc
802   {
803     return false;
804   }
805
806   /**
807    * Creates the directory named by this path and any parent directories.
808    * @return true if successful.
809    */

810   public boolean mkdirs() throws IOException JavaDoc
811   {
812     return false;
813   }
814
815   /**
816    * Removes the file or directory named by this path.
817    *
818    * @return true if successful
819    */

820   public boolean remove() throws IOException JavaDoc
821   {
822     return false;
823   }
824
825   /**
826    * Removes the all files and directories below this path.
827    *
828    * @return true if successful.
829    */

830   public boolean removeAll() throws IOException JavaDoc
831   {
832     if (isDirectory()) {
833       String JavaDoc []list = list();
834
835       for (int i = 0; i < list.length; i++) {
836         Path subpath = lookup(list[i]);
837         subpath.removeAll();
838       }
839     }
840
841     return remove();
842   }
843
844   /**
845    * Sets the length of the file to zero.
846    *
847    * @return true if successful
848    */

849   public boolean truncate()
850     throws IOException JavaDoc
851   {
852     return truncate(0);
853   }
854
855   /**
856    * Sets the length of the file.
857    *
858    * @return true if successful
859    */

860   public boolean truncate(long length)
861     throws IOException JavaDoc
862   {
863     if (length == 0) {
864       if (exists()) {
865     StreamImpl stream = openWriteImpl();
866     stream.close();
867
868     return true;
869       }
870       else
871     return false;
872     }
873     else
874       throw new UnsupportedOperationException JavaDoc(getClass().getName() + ": truncate");
875   }
876
877   /**
878    * Renames the file or directory to the name given by the path.
879    * @return true if successful
880    */

881   public boolean renameTo(Path path) throws IOException JavaDoc
882   {
883     return false;
884   }
885
886   /**
887    * Renames the file or directory to the name given by the path.
888    * @return true if successful
889    */

890   public final boolean renameTo(String JavaDoc path) throws IOException JavaDoc
891   {
892     return renameTo(lookup(path));
893   }
894
895   /**
896    * Creates a restricted root, like the Unix chroot call.
897    * Restricted roots cannot access schemes, so file:/etc/passwd cannot
898    * be used.
899    *
900    * <p>createRoot is useful for restricting JavaScript scripts without
901    * resorting to the dreadfully slow security manager.
902    */

903   public Path createRoot()
904   {
905     return createRoot(SchemeMap.getNullSchemeMap());
906   }
907
908   public Path createRoot(SchemeMap schemeMap)
909   {
910     throw new UnsupportedOperationException JavaDoc("createRoot");
911   }
912
913   /**
914    * Binds the context to the current path. Later lookups will return
915    * the new context instead of the current path. Essentially, this is a
916    * software symbolic link.
917    */

918   public void bind(Path context)
919   {
920     throw new UnsupportedOperationException JavaDoc("bind");
921   }
922
923   /**
924    * unbinds a link.
925    */

926   public void unbind()
927   {
928     throw new UnsupportedOperationException JavaDoc("unbind");
929   }
930
931   /**
932    * Gets the object at the path. Normal filesystems will generally
933    * typically return null.
934    *
935    * <p>A bean filesystem or a mime-type aware filesystem could deserialize
936    * the contents of the file.
937    */

938   public Object JavaDoc getValue() throws Exception JavaDoc
939   {
940     throw new UnsupportedOperationException JavaDoc("getValue");
941   }
942
943   /**
944    * Sets the object at the path.
945    *
946    * <p>Normal filesystems will generally do nothing. However, a bean
947    * filesystem or a mime-type aware filesystem could serialize the object
948    * and store it.
949    */

950   public void setValue(Object JavaDoc obj) throws Exception JavaDoc
951   {
952     throw new UnsupportedOperationException JavaDoc("setValue");
953   }
954
955   /**
956    * Gets an attribute of the object.
957    */

958   public Object JavaDoc getAttribute(String JavaDoc name) throws IOException JavaDoc
959   {
960     return null;
961   }
962
963   /**
964    * Returns a iterator of all attribute names set for this object.
965    * @return null if path has no attributes.
966    */

967   public Iterator JavaDoc getAttributeNames() throws IOException JavaDoc
968   {
969     return null;
970   }
971
972   /**
973    * Opens a resin ReadStream for reading.
974    */

975   public final ReadStream openRead() throws IOException JavaDoc
976   {
977     StreamImpl impl = openReadImpl();
978     impl.setPath(this);
979
980     return new ReadStream(impl);
981   }
982
983   /**
984    * Opens a resin WriteStream for writing.
985    */

986   public final WriteStream openWrite() throws IOException JavaDoc
987   {
988     StreamImpl impl = openWriteImpl();
989     impl.setPath(this);
990     return new WriteStream(impl);
991   }
992
993   /**
994    * Opens a resin ReadWritePair for reading and writing.
995    *
996    * <p>A chat channel, for example, would open its socket using this
997    * interface.
998    */

999   public ReadWritePair openReadWrite() throws IOException JavaDoc
1000  {
1001    StreamImpl impl = openReadWriteImpl();
1002    impl.setPath(this);
1003    WriteStream writeStream = new WriteStream(impl);
1004    ReadStream readStream = new ReadStream(impl, writeStream);
1005    return new ReadWritePair(readStream, writeStream);
1006  }
1007
1008  /**
1009   * Opens a resin ReadWritePair for reading and writing.
1010   *
1011   * <p>A chat channel, for example, would open its socket using this
1012   * interface.
1013   *
1014   * @param is pre-allocated ReadStream to be initialized
1015   * @param os pre-allocated WriteStream to be initialized
1016   */

1017  public void openReadWrite(ReadStream is, WriteStream os) throws IOException JavaDoc
1018  {
1019    StreamImpl impl = openReadWriteImpl();
1020    impl.setPath(this);
1021
1022    os.init(impl);
1023    is.init(impl, os);
1024  }
1025
1026  /**
1027   * Opens a resin stream for appending.
1028   */

1029  public WriteStream openAppend() throws IOException JavaDoc
1030  {
1031    StreamImpl impl = openAppendImpl();
1032    return new WriteStream(impl);
1033  }
1034
1035  /**
1036   * Opens a random-access stream.
1037   */

1038  public RandomAccessStream openRandomAccess() throws IOException JavaDoc
1039  {
1040    throw new UnsupportedOperationException JavaDoc(getClass().getName());
1041  }
1042
1043  /**
1044   * Creates the file named by this Path and returns true if the
1045   * file is new.
1046   */

1047  public boolean createNewFile() throws IOException JavaDoc
1048  {
1049    synchronized (LOCK) {
1050      if (! exists()) {
1051    WriteStream s = openWrite();
1052    s.close();
1053    return true;
1054      }
1055    }
1056
1057    return false;
1058  }
1059
1060  /**
1061   * Creates a unique temporary file as a child of this directory.
1062   *
1063   * @param prefix filename prefix
1064   * @param suffix filename suffix, defaults to .tmp
1065   * @return Path to the new file.
1066   */

1067  public Path createTempFile(String JavaDoc prefix, String JavaDoc suffix) throws IOException JavaDoc
1068  {
1069    if (prefix == null || prefix.length () < 3)
1070      throw new IllegalArgumentException JavaDoc("prefix too short: " + prefix);
1071
1072    if (suffix == null)
1073      suffix = ".tmp";
1074
1075    synchronized (LOCK) {
1076      for (int i = 0; i < 32768; i++) {
1077        int r = Math.abs((int) RandomUtil.getRandomLong());
1078        Path file = lookup(prefix + r + suffix);
1079
1080        if (file.createNewFile())
1081          return file;
1082      }
1083    }
1084
1085    throw new IOException JavaDoc("cannot create temp file");
1086  }
1087
1088  /**
1089   * Creates a link named by this path to another path.
1090   *
1091   * @param target the target of the link
1092   * @param hardLink true if the link should be a hard link
1093   */

1094  public boolean createLink(Path target, boolean hardLink)
1095    throws IOException JavaDoc
1096  {
1097    throw new UnsupportedOperationException JavaDoc(getScheme() + ": doesn't support createLink");
1098  }
1099
1100  /**
1101   * Utility to write the contents of this path to the destination stream.
1102   *
1103   * @param os destination stream.
1104   */

1105  public void writeToStream(OutputStream JavaDoc os)
1106    throws IOException JavaDoc
1107  {
1108    StreamImpl is = openReadImpl();
1109    TempBuffer tempBuffer = TempBuffer.allocate();
1110    try {
1111      byte []buffer = tempBuffer.getBuffer();
1112      int length = buffer.length;
1113      int len;
1114
1115      while ((len = is.read(buffer, 0, length)) > 0)
1116    os.write(buffer, 0, len);
1117    } finally {
1118      TempBuffer.free(tempBuffer);
1119
1120      is.close();
1121    }
1122  }
1123
1124  /**
1125   * Utility to write the contents of this path to the destination stream.
1126   *
1127   * @param os destination stream.
1128   */

1129  public void writeToStream(OutputStreamWithBuffer os)
1130    throws IOException JavaDoc
1131  {
1132    StreamImpl is = openReadImpl();
1133
1134    try {
1135      byte []buffer = os.getBuffer();
1136      int offset = os.getBufferOffset();
1137      int length = buffer.length;
1138
1139      while (true) {
1140    int sublen = length - offset;
1141
1142    if (sublen <= 0) {
1143      buffer = os.nextBuffer(offset);
1144      offset = 0;
1145      sublen = length;
1146    }
1147
1148    sublen = is.read(buffer, offset, sublen);
1149
1150    if (sublen <= 0) {
1151      os.setBufferOffset(offset);
1152      return;
1153    }
1154
1155    offset += sublen;
1156      }
1157    } finally {
1158      is.close();
1159    }
1160  }
1161
1162  /**
1163   * Returns the crc64 code.
1164   */

1165  public long getCrc64()
1166  {
1167    try {
1168      if (isDirectory()) {
1169    String JavaDoc []list = list();
1170
1171    long digest = 0;
1172
1173    for (int i = 0; i < list.length; i++) {
1174      digest = Crc64.generate(digest, list[i]);
1175    }
1176
1177    return digest;
1178      }
1179      else if (canRead()) {
1180    ReadStream is = openRead();
1181
1182    try {
1183      long digest = 0;
1184
1185      int ch;
1186
1187      while ((ch = is.read()) >= 0) {
1188        digest = Crc64.next(digest, ch);
1189      }
1190
1191      return digest;
1192    } finally {
1193      is.close();
1194    }
1195      }
1196      else {
1197    return -1; // Depend requires -1
1198
}
1199    } catch (IOException JavaDoc e) {
1200      // XXX: log
1201
e.printStackTrace();
1202
1203      return -1;
1204    }
1205  }
1206
1207  /**
1208   * Returns the object at this path. Normally, only paths like JNDI
1209   * will support this.
1210   */

1211  public Object JavaDoc getObject()
1212    throws IOException JavaDoc
1213  {
1214    throw new UnsupportedOperationException JavaDoc(getScheme() + ": doesn't support getObject");
1215  }
1216
1217  /**
1218   * Sets the object at this path. Normally, only paths like JNDI
1219   * will support this.
1220   */

1221  public void setObject(Object JavaDoc obj)
1222    throws IOException JavaDoc
1223  {
1224    throw new UnsupportedOperationException JavaDoc(getScheme() + ": doesn't support setObject");
1225  }
1226
1227  public int hashCode()
1228  {
1229    return toString().hashCode();
1230  }
1231
1232  public boolean equals(Object JavaDoc o)
1233  {
1234    if (this == o)
1235      return true;
1236    else if (! (o instanceof Path))
1237      return false;
1238    else
1239      return getPath().equals(((Path) o).getPath());
1240  }
1241
1242  public String JavaDoc toString()
1243  {
1244    return getPath();
1245  }
1246
1247  public StreamImpl openReadImpl() throws IOException JavaDoc
1248  {
1249    throw new UnsupportedOperationException JavaDoc("openRead:" + getClass().getName());
1250  }
1251
1252  public StreamImpl openWriteImpl() throws IOException JavaDoc
1253  {
1254    throw new UnsupportedOperationException JavaDoc("openWrite:" + getClass().getName());
1255  }
1256
1257  public StreamImpl openReadWriteImpl() throws IOException JavaDoc
1258  {
1259    throw new UnsupportedOperationException JavaDoc("openReadWrite:" + getClass().getName());
1260  }
1261
1262  public StreamImpl openAppendImpl() throws IOException JavaDoc
1263  {
1264    throw new UnsupportedOperationException JavaDoc("openAppend:" + getClass().getName());
1265  }
1266
1267  protected static String JavaDoc escapeURL(String JavaDoc rawURL)
1268  {
1269    CharBuffer cb = null;
1270    int length = rawURL.length();
1271
1272    for (int i = 0; i < length; i++) {
1273      char ch = rawURL.charAt(i);
1274
1275      switch (ch) {
1276      case ' ':
1277    if (cb == null) {
1278      cb = new CharBuffer();
1279      cb.append(rawURL, 0, i);
1280    }
1281    cb.append("%20");
1282    break;
1283    
1284      case '#':
1285    if (cb == null) {
1286      cb = new CharBuffer();
1287      cb.append(rawURL, 0, i);
1288    }
1289    cb.append("%23");
1290    break;
1291
1292      case '%':
1293    if (cb == null) {
1294      cb = new CharBuffer();
1295      cb.append(rawURL, 0, i);
1296    }
1297    cb.append("%25");
1298    break;
1299
1300      default:
1301    if (cb != null)
1302      cb.append(ch);
1303    break;
1304      }
1305    }
1306
1307    if (cb != null)
1308      return cb.toString();
1309    else
1310      return rawURL;
1311  }
1312
1313  protected Path copy()
1314  {
1315    return this;
1316  }
1317
1318  /**
1319   * Copy for caching.
1320   */

1321  protected Path cacheCopy()
1322  {
1323    return this;
1324  }
1325
1326  public static final void setDefaultSchemeMap(SchemeMap schemeMap)
1327  {
1328    _defaultSchemeMap = schemeMap;
1329    _pathLookupCache.clear();
1330  }
1331
1332  public static final boolean isWindows()
1333  {
1334    return _separatorChar == '\\' || _isTestWindows;
1335  }
1336
1337  protected static final char getSeparatorChar()
1338  {
1339    return _separatorChar;
1340  }
1341
1342  public static final char getFileSeparatorChar()
1343  {
1344    return _separatorChar;
1345  }
1346
1347  public static final char getPathSeparatorChar()
1348  {
1349    return _pathSeparatorChar;
1350  }
1351
1352  protected static String JavaDoc getUserDir()
1353  {
1354    return System.getProperty("user.dir");
1355  }
1356
1357  public static String JavaDoc getNewlineString()
1358  {
1359    if (_newline == null) {
1360      _newline = System.getProperty("line.separator");
1361      if (_newline == null)
1362        _newline = "\n";
1363    }
1364
1365    return _newline;
1366  }
1367
1368  private class ArrayIterator implements Iterator JavaDoc<String JavaDoc> {
1369    String JavaDoc []list;
1370    int index;
1371
1372    public boolean hasNext() { return index < list.length; }
1373    public String JavaDoc next() { return index < list.length ? list[index++] : null; }
1374    public void remove() { throw new UnsupportedOperationException JavaDoc(); }
1375
1376    ArrayIterator(String JavaDoc []list)
1377    {
1378      this.list = list;
1379      index = 0;
1380    }
1381  }
1382
1383  static class PathKey {
1384    private Path _parent;
1385    private String JavaDoc _lookup;
1386
1387    PathKey()
1388    {
1389    }
1390
1391    PathKey(Path parent, String JavaDoc lookup)
1392    {
1393      _parent = parent;
1394      _lookup = lookup;
1395    }
1396
1397    void init(Path parent, String JavaDoc lookup)
1398    {
1399      _parent = parent;
1400      _lookup = lookup;
1401    }
1402
1403    public int hashCode()
1404    {
1405      return System.identityHashCode(_parent) * 65521 + _lookup.hashCode();
1406    }
1407
1408    public boolean equals(Object JavaDoc test)
1409    {
1410      if (! (test instanceof PathKey))
1411        return false;
1412
1413      PathKey key = (PathKey) test;
1414
1415      return (_parent == key._parent && _lookup.equals(key._lookup));
1416    }
1417  }
1418
1419  static {
1420    DEFAULT_SCHEME_MAP.put("file", new FilePath(null));
1421    
1422    //DEFAULT_SCHEME_MAP.put("jar", new JarScheme(null));
1423
DEFAULT_SCHEME_MAP.put("http", new HttpPath("127.0.0.1", 0));
1424    DEFAULT_SCHEME_MAP.put("https", new HttpsPath("127.0.0.1", 0));
1425    DEFAULT_SCHEME_MAP.put("tcp", new TcpPath(null, null, null, "127.0.0.1", 0));
1426    DEFAULT_SCHEME_MAP.put("tcps", new TcpsPath(null, null, null, "127.0.0.1", 0));
1427
1428    StreamImpl stdout = StdoutStream.create();
1429    StreamImpl stderr = StderrStream.create();
1430    DEFAULT_SCHEME_MAP.put("stdout", stdout.getPath());
1431    DEFAULT_SCHEME_MAP.put("stderr", stderr.getPath());
1432    VfsStream nullStream = new VfsStream(null, null);
1433    DEFAULT_SCHEME_MAP.put("null", new ConstPath(null, nullStream));
1434    DEFAULT_SCHEME_MAP.put("jndi", new JndiPath());
1435  }
1436}
1437
Popular Tags