001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.fs;
020
021import java.io.*;
022import java.net.URI;
023import java.net.URISyntaxException;
024import java.util.EnumSet;
025import org.apache.hadoop.classification.InterfaceAudience;
026import org.apache.hadoop.classification.InterfaceStability;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.fs.permission.FsPermission;
029import org.apache.hadoop.fs.ContentSummary;
030import org.apache.hadoop.fs.Options.ChecksumOpt;
031import org.apache.hadoop.util.Progressable;
032
033/****************************************************************
034 * A <code>FilterFileSystem</code> contains
035 * some other file system, which it uses as
036 * its  basic file system, possibly transforming
037 * the data along the way or providing  additional
038 * functionality. The class <code>FilterFileSystem</code>
039 * itself simply overrides all  methods of
040 * <code>FileSystem</code> with versions that
041 * pass all requests to the contained  file
042 * system. Subclasses of <code>FilterFileSystem</code>
043 * may further override some of  these methods
044 * and may also provide additional methods
045 * and fields.
046 *
047 *****************************************************************/
048@InterfaceAudience.Public
049@InterfaceStability.Stable
050public class FilterFileSystem extends FileSystem {
051  
052  protected FileSystem fs;
053  protected String swapScheme;
054  
055  /*
056   * so that extending classes can define it
057   */
058  public FilterFileSystem() {
059  }
060  
061  public FilterFileSystem(FileSystem fs) {
062    this.fs = fs;
063    this.statistics = fs.statistics;
064  }
065
066  /**
067   * Get the raw file system 
068   * @return FileSystem being filtered
069   */
070  public FileSystem getRawFileSystem() {
071    return fs;
072  }
073
074  /** Called after a new FileSystem instance is constructed.
075   * @param name a uri whose authority section names the host, port, etc.
076   *   for this FileSystem
077   * @param conf the configuration
078   */
079  public void initialize(URI name, Configuration conf) throws IOException {
080    super.initialize(name, conf);
081    // this is less than ideal, but existing filesystems sometimes neglect
082    // to initialize the embedded filesystem
083    if (fs.getConf() == null) {
084      fs.initialize(name, conf);
085    }
086    String scheme = name.getScheme();
087    if (!scheme.equals(fs.getUri().getScheme())) {
088      swapScheme = scheme;
089    }
090  }
091
092  /** Returns a URI whose scheme and authority identify this FileSystem.*/
093  public URI getUri() {
094    return fs.getUri();
095  }
096
097  /**
098   * Returns a qualified URI whose scheme and authority identify this
099   * FileSystem.
100   */
101  @Override
102  protected URI getCanonicalUri() {
103    return fs.getCanonicalUri();
104  }
105  
106  /** Make sure that a path specifies a FileSystem. */
107  public Path makeQualified(Path path) {
108    Path fqPath = fs.makeQualified(path);
109    // swap in our scheme if the filtered fs is using a different scheme
110    if (swapScheme != null) {
111      try {
112        // NOTE: should deal with authority, but too much other stuff is broken 
113        fqPath = new Path(
114            new URI(swapScheme, fqPath.toUri().getSchemeSpecificPart(), null)
115        );
116      } catch (URISyntaxException e) {
117        throw new IllegalArgumentException(e);
118      }
119    }
120    return fqPath;
121  }
122  
123  ///////////////////////////////////////////////////////////////
124  // FileSystem
125  ///////////////////////////////////////////////////////////////
126
127  /** Check that a Path belongs to this FileSystem. */
128  protected void checkPath(Path path) {
129    fs.checkPath(path);
130  }
131
132  public BlockLocation[] getFileBlockLocations(FileStatus file, long start,
133    long len) throws IOException {
134      return fs.getFileBlockLocations(file, start, len);
135  }
136
137  @Override
138  public Path resolvePath(final Path p) throws IOException {
139    return fs.resolvePath(p);
140  }
141  /**
142   * Opens an FSDataInputStream at the indicated Path.
143   * @param f the file name to open
144   * @param bufferSize the size of the buffer to be used.
145   */
146  public FSDataInputStream open(Path f, int bufferSize) throws IOException {
147    return fs.open(f, bufferSize);
148  }
149
150  /** {@inheritDoc} */
151  public FSDataOutputStream append(Path f, int bufferSize,
152      Progressable progress) throws IOException {
153    return fs.append(f, bufferSize, progress);
154  }
155
156  /** {@inheritDoc} */
157  @Override
158  public FSDataOutputStream create(Path f, FsPermission permission,
159      boolean overwrite, int bufferSize, short replication, long blockSize,
160      Progressable progress) throws IOException {
161    return fs.create(f, permission,
162        overwrite, bufferSize, replication, blockSize, progress);
163  }
164
165  /**
166   * Set replication for an existing file.
167   * 
168   * @param src file name
169   * @param replication new replication
170   * @throws IOException
171   * @return true if successful;
172   *         false if file does not exist or is a directory
173   */
174  public boolean setReplication(Path src, short replication) throws IOException {
175    return fs.setReplication(src, replication);
176  }
177  
178  /**
179   * Renames Path src to Path dst.  Can take place on local fs
180   * or remote DFS.
181   */
182  public boolean rename(Path src, Path dst) throws IOException {
183    return fs.rename(src, dst);
184  }
185  
186  /** Delete a file */
187  public boolean delete(Path f, boolean recursive) throws IOException {
188    return fs.delete(f, recursive);
189  }
190  
191  /** List files in a directory. */
192  public FileStatus[] listStatus(Path f) throws IOException {
193    return fs.listStatus(f);
194  }
195
196  /**
197   * {@inheritDoc}
198   */
199  @Override
200  public RemoteIterator<Path> listCorruptFileBlocks(Path path)
201    throws IOException {
202    return fs.listCorruptFileBlocks(path);
203  }
204
205  /** List files and its block locations in a directory. */
206  public RemoteIterator<LocatedFileStatus> listLocatedStatus(Path f)
207  throws IOException {
208    return fs.listLocatedStatus(f);
209  }
210  
211  public Path getHomeDirectory() {
212    return fs.getHomeDirectory();
213  }
214
215
216  /**
217   * Set the current working directory for the given file system. All relative
218   * paths will be resolved relative to it.
219   * 
220   * @param newDir
221   */
222  public void setWorkingDirectory(Path newDir) {
223    fs.setWorkingDirectory(newDir);
224  }
225  
226  /**
227   * Get the current working directory for the given file system
228   * 
229   * @return the directory pathname
230   */
231  public Path getWorkingDirectory() {
232    return fs.getWorkingDirectory();
233  }
234  
235  protected Path getInitialWorkingDirectory() {
236    return fs.getInitialWorkingDirectory();
237  }
238  
239  /** {@inheritDoc} */
240  @Override
241  public FsStatus getStatus(Path p) throws IOException {
242    return fs.getStatus(p);
243  }
244  
245  /** {@inheritDoc} */
246  @Override
247  public boolean mkdirs(Path f, FsPermission permission) throws IOException {
248    return fs.mkdirs(f, permission);
249  }
250
251
252  /**
253   * The src file is on the local disk.  Add it to FS at
254   * the given dst name.
255   * delSrc indicates if the source should be removed
256   */
257  public void copyFromLocalFile(boolean delSrc, Path src, Path dst)
258    throws IOException {
259    fs.copyFromLocalFile(delSrc, src, dst);
260  }
261  
262  /**
263   * The src files are on the local disk.  Add it to FS at
264   * the given dst name.
265   * delSrc indicates if the source should be removed
266   */
267  public void copyFromLocalFile(boolean delSrc, boolean overwrite, 
268                                Path[] srcs, Path dst)
269    throws IOException {
270    fs.copyFromLocalFile(delSrc, overwrite, srcs, dst);
271  }
272  
273  /**
274   * The src file is on the local disk.  Add it to FS at
275   * the given dst name.
276   * delSrc indicates if the source should be removed
277   */
278  public void copyFromLocalFile(boolean delSrc, boolean overwrite, 
279                                Path src, Path dst)
280    throws IOException {
281    fs.copyFromLocalFile(delSrc, overwrite, src, dst);
282  }
283
284  /**
285   * The src file is under FS, and the dst is on the local disk.
286   * Copy it from FS control to the local dst name.
287   * delSrc indicates if the src will be removed or not.
288   */   
289  public void copyToLocalFile(boolean delSrc, Path src, Path dst)
290    throws IOException {
291    fs.copyToLocalFile(delSrc, src, dst);
292  }
293  
294  /**
295   * Returns a local File that the user can write output to.  The caller
296   * provides both the eventual FS target name and the local working
297   * file.  If the FS is local, we write directly into the target.  If
298   * the FS is remote, we write into the tmp local area.
299   */
300  public Path startLocalOutput(Path fsOutputFile, Path tmpLocalFile)
301    throws IOException {
302    return fs.startLocalOutput(fsOutputFile, tmpLocalFile);
303  }
304
305  /**
306   * Called when we're all done writing to the target.  A local FS will
307   * do nothing, because we've written to exactly the right place.  A remote
308   * FS will copy the contents of tmpLocalFile to the correct target at
309   * fsOutputFile.
310   */
311  public void completeLocalOutput(Path fsOutputFile, Path tmpLocalFile)
312    throws IOException {
313    fs.completeLocalOutput(fsOutputFile, tmpLocalFile);
314  }
315
316  /** Return the total size of all files in the filesystem.*/
317  public long getUsed() throws IOException{
318    return fs.getUsed();
319  }
320  
321  @Override
322  public long getDefaultBlockSize() {
323    return fs.getDefaultBlockSize();
324  }
325  
326  @Override
327  public short getDefaultReplication() {
328    return fs.getDefaultReplication();
329  }
330
331  @Override
332  public FsServerDefaults getServerDefaults() throws IOException {
333    return fs.getServerDefaults();
334  }
335
336  // path variants delegate to underlying filesystem 
337  @Override
338  public ContentSummary getContentSummary(Path f) throws IOException {
339    return fs.getContentSummary(f);
340  }
341
342  @Override
343  public long getDefaultBlockSize(Path f) {
344    return fs.getDefaultBlockSize(f);
345  }
346
347  @Override
348  public short getDefaultReplication(Path f) {
349    return fs.getDefaultReplication(f);
350  }
351
352  @Override
353  public FsServerDefaults getServerDefaults(Path f) throws IOException {
354    return fs.getServerDefaults(f);
355  }
356
357  /**
358   * Get file status.
359   */
360  public FileStatus getFileStatus(Path f) throws IOException {
361    return fs.getFileStatus(f);
362  }
363
364  /** {@inheritDoc} */
365  public FileChecksum getFileChecksum(Path f) throws IOException {
366    return fs.getFileChecksum(f);
367  }
368  
369  /** {@inheritDoc} */
370  public void setVerifyChecksum(boolean verifyChecksum) {
371    fs.setVerifyChecksum(verifyChecksum);
372  }
373  
374  @Override
375  public void setWriteChecksum(boolean writeChecksum) {
376    fs.setWriteChecksum(writeChecksum);
377  }
378
379  @Override
380  public Configuration getConf() {
381    return fs.getConf();
382  }
383  
384  @Override
385  public void close() throws IOException {
386    super.close();
387    fs.close();
388  }
389
390  /** {@inheritDoc} */
391  @Override
392  public void setOwner(Path p, String username, String groupname
393      ) throws IOException {
394    fs.setOwner(p, username, groupname);
395  }
396
397  /** {@inheritDoc} */
398  @Override
399  public void setTimes(Path p, long mtime, long atime
400      ) throws IOException {
401    fs.setTimes(p, mtime, atime);
402  }
403
404  /** {@inheritDoc} */
405  @Override
406  public void setPermission(Path p, FsPermission permission
407      ) throws IOException {
408    fs.setPermission(p, permission);
409  }
410
411  @Override
412  protected FSDataOutputStream primitiveCreate(Path f,
413      FsPermission absolutePermission, EnumSet<CreateFlag> flag,
414      int bufferSize, short replication, long blockSize,
415      Progressable progress, ChecksumOpt checksumOpt)
416      throws IOException {
417    return fs.primitiveCreate(f, absolutePermission, flag,
418        bufferSize, replication, blockSize, progress, checksumOpt);
419  }
420
421  @Override
422  @SuppressWarnings("deprecation")
423  protected boolean primitiveMkdir(Path f, FsPermission abdolutePermission)
424      throws IOException {
425    return fs.primitiveMkdir(f, abdolutePermission);
426  }
427  
428  @Override // FileSystem
429  public FileSystem[] getChildFileSystems() {
430    return new FileSystem[]{fs};
431  }
432}