1 /*
   2  * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.nio.file.*;
  25 import java.nio.file.attribute.*;
  26 import java.nio.file.spi.FileSystemProvider;
  27 import java.nio.channels.SeekableByteChannel;
  28 import java.net.URI;
  29 import java.util.*;
  30 import java.io.*;
  31 
  32 /**
  33  * A "pass through" file system implementation that passes through, or delegates,
  34  * everything to the default file system.
  35  */
  36 
  37 class PassThroughFileSystem extends FileSystem {
  38     private final FileSystemProvider provider;
  39     private final FileSystem delegate;
  40 
  41     PassThroughFileSystem(FileSystemProvider provider, FileSystem delegate) {
  42         this.provider = provider;
  43         this.delegate = delegate;
  44     }
  45 
  46     /**
  47      * Creates a new "pass through" file system. Useful for test environments
  48      * where the provider might not be deployed.
  49      */
  50     static FileSystem create() throws IOException {
  51         FileSystemProvider provider = new PassThroughProvider();
  52         Map<String,?> env = Collections.emptyMap();
  53         URI uri = URI.create("pass:///");
  54         return provider.newFileSystem(uri, env);
  55     }
  56 
  57     static Path unwrap(Path wrapper) {
  58         if (wrapper == null)
  59             throw new NullPointerException();
  60         if (!(wrapper instanceof PassThroughPath))
  61             throw new ProviderMismatchException();
  62         return ((PassThroughPath)wrapper).delegate;
  63     }
  64 
  65     @Override
  66     public FileSystemProvider provider() {
  67         return provider;
  68     }
  69 
  70     @Override
  71     public void close() throws IOException {
  72         delegate.close();
  73     }
  74 
  75     @Override
  76     public boolean isOpen() {
  77         return delegate.isOpen();
  78     }
  79 
  80     @Override
  81     public boolean isReadOnly() {
  82         return delegate.isReadOnly();
  83     }
  84 
  85     @Override
  86     public String getSeparator() {
  87         return delegate.getSeparator();
  88     }
  89 
  90     @Override
  91     public Iterable<Path> getRootDirectories() {
  92         final Iterable<Path> roots = delegate.getRootDirectories();
  93         return new Iterable<Path>() {
  94             @Override
  95             public Iterator<Path> iterator() {
  96                 final Iterator<Path> itr = roots.iterator();
  97                 return new Iterator<Path>() {
  98                     @Override
  99                     public boolean hasNext() {
 100                         return itr.hasNext();
 101                     }
 102                     @Override
 103                     public Path next() {
 104                         return new PassThroughPath(delegate, itr.next());
 105                     }
 106                     @Override
 107                     public void remove() {
 108                         itr.remove();
 109                     }
 110                 };
 111             }
 112         };
 113     }
 114 
 115     @Override
 116     public Iterable<FileStore> getFileStores() {
 117         // assume that unwrapped objects aren't exposed
 118         return delegate.getFileStores();
 119     }
 120 
 121     @Override
 122     public Set<String> supportedFileAttributeViews() {
 123         // assume that unwrapped objects aren't exposed
 124         return delegate.supportedFileAttributeViews();
 125     }
 126 
 127     @Override
 128     public Path getPath(String first, String... more) {
 129         return new PassThroughPath(this, delegate.getPath(first, more));
 130     }
 131 
 132     @Override
 133     public PathMatcher getPathMatcher(String syntaxAndPattern) {
 134         final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern);
 135         return new PathMatcher() {
 136             @Override
 137             public boolean matches(Path path) {
 138                 return matcher.matches(unwrap(path));
 139             }
 140         };
 141     }
 142 
 143     @Override
 144     public UserPrincipalLookupService getUserPrincipalLookupService() {
 145         // assume that unwrapped objects aren't exposed
 146         return delegate.getUserPrincipalLookupService();
 147     }
 148 
 149     @Override
 150     public WatchService newWatchService() throws IOException {
 151         // to keep it simple
 152         throw new UnsupportedOperationException();
 153     }
 154 
 155     static class PassThroughProvider extends FileSystemProvider {
 156         private static final String SCHEME = "pass";
 157         private static volatile PassThroughFileSystem delegate;
 158 
 159         public PassThroughProvider() { }
 160 
 161         @Override
 162         public String getScheme() {
 163             return SCHEME;
 164         }
 165 
 166         private void checkScheme(URI uri) {
 167             if (!uri.getScheme().equalsIgnoreCase(SCHEME))
 168                 throw new IllegalArgumentException();
 169         }
 170 
 171         private void checkUri(URI uri) {
 172             checkScheme(uri);
 173             if (!uri.getSchemeSpecificPart().equals("///"))
 174                 throw new IllegalArgumentException();
 175         }
 176 
 177         @Override
 178         public FileSystem newFileSystem(URI uri, Map<String,?> env)
 179             throws IOException
 180         {
 181             checkUri(uri);
 182             synchronized (PassThroughProvider.class) {
 183                 if (delegate != null)
 184                     throw new FileSystemAlreadyExistsException();
 185                 PassThroughFileSystem result =
 186                     new PassThroughFileSystem(this, FileSystems.getDefault());
 187                 delegate = result;
 188                 return result;
 189             }
 190         }
 191 
 192         @Override
 193         public FileSystem getFileSystem(URI uri) {
 194             checkUri(uri);
 195             FileSystem result = delegate;
 196             if (result == null)
 197                 throw new FileSystemNotFoundException();
 198             return result;
 199         }
 200 
 201         @Override
 202         public Path getPath(URI uri) {
 203             checkScheme(uri);
 204             if (delegate == null)
 205                 throw new FileSystemNotFoundException();
 206             uri = URI.create(delegate.provider().getScheme() + ":" +
 207                              uri.getSchemeSpecificPart());
 208             return new PassThroughPath(delegate, delegate.provider().getPath(uri));
 209         }
 210 
 211         @Override
 212         public void setAttribute(Path file, String attribute, Object value, LinkOption... options)
 213             throws IOException
 214         {
 215             Files.setAttribute(unwrap(file), attribute, value, options);
 216         }
 217 
 218         @Override
 219         public Map<String,Object> readAttributes(Path file, String attributes, LinkOption... options)
 220             throws IOException
 221         {
 222             return Files.readAttributes(unwrap(file), attributes, options);
 223         }
 224 
 225         @Override
 226         public <V extends FileAttributeView> V getFileAttributeView(Path file,
 227                                                                     Class<V> type,
 228                                                                     LinkOption... options)
 229         {
 230             return Files.getFileAttributeView(unwrap(file), type, options);
 231         }
 232 
 233         @Override
 234         public <A extends BasicFileAttributes> A readAttributes(Path file,
 235                                                                 Class<A> type,
 236                                                                 LinkOption... options)
 237             throws IOException
 238         {
 239             return Files.readAttributes(unwrap(file), type, options);
 240         }
 241 
 242         @Override
 243         public void delete(Path file) throws IOException {
 244             Files.delete(unwrap(file));
 245         }
 246 
 247         @Override
 248         public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
 249             throws IOException
 250         {
 251             Files.createSymbolicLink(unwrap(link), unwrap(target), attrs);
 252         }
 253 
 254         @Override
 255         public void createLink(Path link, Path existing) throws IOException {
 256             Files.createLink(unwrap(link), unwrap(existing));
 257         }
 258 
 259         @Override
 260         public Path readSymbolicLink(Path link) throws IOException {
 261             Path target = Files.readSymbolicLink(unwrap(link));
 262             return new PassThroughPath(delegate, target);
 263         }
 264 
 265 
 266         @Override
 267         public void copy(Path source, Path target, CopyOption... options) throws IOException {
 268             Files.copy(unwrap(source), unwrap(target), options);
 269         }
 270 
 271         @Override
 272         public void move(Path source, Path target, CopyOption... options) throws IOException {
 273             Files.move(unwrap(source), unwrap(target), options);
 274         }
 275 
 276         private DirectoryStream<Path> wrap(final DirectoryStream<Path> stream) {
 277             return new DirectoryStream<Path>() {
 278                 @Override
 279                 public Iterator<Path> iterator() {
 280                     final Iterator<Path> itr = stream.iterator();
 281                     return new Iterator<Path>() {
 282                         @Override
 283                         public boolean hasNext() {
 284                             return itr.hasNext();
 285                         }
 286                         @Override
 287                         public Path next() {
 288                             return new PassThroughPath(delegate, itr.next());
 289                         }
 290                         @Override
 291                         public void remove() {
 292                             itr.remove();
 293                         }
 294                     };
 295                 }
 296                 @Override
 297                 public void close() throws IOException {
 298                     stream.close();
 299                 }
 300             };
 301         }
 302 
 303         @Override
 304         public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter)
 305             throws IOException
 306         {
 307             return wrap(Files.newDirectoryStream(dir, filter));
 308         }
 309 
 310         @Override
 311         public void createDirectory(Path dir, FileAttribute<?>... attrs)
 312             throws IOException
 313         {
 314             Files.createDirectory(unwrap(dir), attrs);
 315         }
 316 
 317         @Override
 318         public SeekableByteChannel newByteChannel(Path file,
 319                                                   Set<? extends OpenOption> options,
 320                                                   FileAttribute<?>... attrs)
 321             throws IOException
 322         {
 323             return Files.newByteChannel(unwrap(file), options, attrs);
 324         }
 325 
 326 
 327         @Override
 328         public boolean isHidden(Path file) throws IOException {
 329             return Files.isHidden(unwrap(file));
 330         }
 331 
 332         @Override
 333         public FileStore getFileStore(Path file) throws IOException {
 334             return Files.getFileStore(unwrap(file));
 335         }
 336 
 337         @Override
 338         public boolean isSameFile(Path file, Path other) throws IOException {
 339             return Files.isSameFile(unwrap(file), unwrap(other));
 340         }
 341 
 342         @Override
 343         public void checkAccess(Path file, AccessMode... modes)
 344             throws IOException
 345         {
 346             // hack
 347             if (modes.length == 0) {
 348                 if (Files.exists(unwrap(file)))
 349                     return;
 350                 else
 351                     throw new NoSuchFileException(file.toString());
 352             }
 353             throw new RuntimeException("not implemented yet");
 354         }
 355     }
 356 
 357     static class PassThroughPath implements Path {
 358         private final FileSystem fs;
 359         private final Path delegate;
 360 
 361         PassThroughPath(FileSystem fs, Path delegate) {
 362             this.fs = fs;
 363             this.delegate = delegate;
 364         }
 365 
 366         private Path wrap(Path path) {
 367             return (path != null) ? new PassThroughPath(fs, path) : null;
 368         }
 369 
 370         @Override
 371         public FileSystem getFileSystem() {
 372             return fs;
 373         }
 374 
 375         @Override
 376         public boolean isAbsolute() {
 377             return delegate.isAbsolute();
 378         }
 379 
 380         @Override
 381         public Path getRoot() {
 382             return wrap(delegate.getRoot());
 383         }
 384 
 385         @Override
 386         public Path getParent() {
 387             return wrap(delegate.getParent());
 388         }
 389 
 390         @Override
 391         public int getNameCount() {
 392             return delegate.getNameCount();
 393         }
 394 
 395         @Override
 396         public Path getFileName() {
 397             return wrap(delegate.getFileName());
 398         }
 399 
 400         @Override
 401         public Path getName(int index) {
 402             return wrap(delegate.getName(index));
 403         }
 404 
 405         @Override
 406         public Path subpath(int beginIndex, int endIndex) {
 407             return wrap(delegate.subpath(beginIndex, endIndex));
 408         }
 409 
 410         @Override
 411         public boolean startsWith(Path other) {
 412             return delegate.startsWith(unwrap(other));
 413         }
 414 
 415         @Override
 416         public boolean startsWith(String other) {
 417             return delegate.startsWith(other);
 418         }
 419 
 420         @Override
 421         public boolean endsWith(Path other) {
 422             return delegate.endsWith(unwrap(other));
 423         }
 424 
 425         @Override
 426         public boolean endsWith(String other) {
 427             return delegate.endsWith(other);
 428         }
 429 
 430         @Override
 431         public Path normalize() {
 432             return wrap(delegate.normalize());
 433         }
 434 
 435         @Override
 436         public Path resolve(Path other) {
 437             return wrap(delegate.resolve(unwrap(other)));
 438         }
 439 
 440         @Override
 441         public Path resolve(String other) {
 442             return wrap(delegate.resolve(other));
 443         }
 444 
 445         @Override
 446         public Path resolveSibling(Path other) {
 447             return wrap(delegate.resolveSibling(unwrap(other)));
 448         }
 449 
 450         @Override
 451         public Path resolveSibling(String other) {
 452             return wrap(delegate.resolveSibling(other));
 453         }
 454 
 455         @Override
 456         public Path relativize(Path other) {
 457             return wrap(delegate.relativize(unwrap(other)));
 458         }
 459 
 460         @Override
 461         public boolean equals(Object other) {
 462             if (!(other instanceof PassThroughPath))
 463                 return false;
 464             return delegate.equals(unwrap((PassThroughPath)other));
 465         }
 466 
 467         @Override
 468         public int hashCode() {
 469             return delegate.hashCode();
 470         }
 471 
 472         @Override
 473         public String toString() {
 474             return delegate.toString();
 475         }
 476 
 477         @Override
 478         public URI toUri() {
 479             String ssp = delegate.toUri().getSchemeSpecificPart();
 480             return URI.create(fs.provider().getScheme() + ":" + ssp);
 481         }
 482 
 483         @Override
 484         public Path toAbsolutePath() {
 485             return wrap(delegate.toAbsolutePath());
 486         }
 487 
 488         @Override
 489         public Path toRealPath(LinkOption... options) throws IOException {
 490             return wrap(delegate.toRealPath(options));
 491         }
 492 
 493         @Override
 494         public File toFile() {
 495             return delegate.toFile();
 496         }
 497 
 498         @Override
 499         public Iterator<Path> iterator() {
 500             final Iterator<Path> itr = delegate.iterator();
 501             return new Iterator<Path>() {
 502                 @Override
 503                 public boolean hasNext() {
 504                     return itr.hasNext();
 505                 }
 506                 @Override
 507                 public Path next() {
 508                     return wrap(itr.next());
 509                 }
 510                 @Override
 511                 public void remove() {
 512                     itr.remove();
 513                 }
 514             };
 515         }
 516 
 517         @Override
 518         public int compareTo(Path other) {
 519             return delegate.compareTo(unwrap(other));
 520         }
 521 
 522         @Override
 523         public WatchKey register(WatchService watcher,
 524                                       WatchEvent.Kind<?>[] events,
 525                                       WatchEvent.Modifier... modifiers)
 526         {
 527             throw new UnsupportedOperationException();
 528         }
 529 
 530         @Override
 531         public  WatchKey register(WatchService watcher,
 532                                       WatchEvent.Kind<?>... events)
 533         {
 534             throw new UnsupportedOperationException();
 535         }
 536     }
 537 }