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    package org.apache.hadoop.fs;
019    
020    import java.io.*;
021    import java.io.DataOutputStream;
022    import java.io.FilterOutputStream;
023    import java.io.IOException;
024    import java.io.OutputStream;
025    
026    import org.apache.hadoop.classification.InterfaceAudience;
027    import org.apache.hadoop.classification.InterfaceStability;
028    
029    /** Utility that wraps a {@link OutputStream} in a {@link DataOutputStream},
030     * buffers output through a {@link BufferedOutputStream} and creates a checksum
031     * file. */
032    @InterfaceAudience.Public
033    @InterfaceStability.Stable
034    public class FSDataOutputStream extends DataOutputStream
035        implements Syncable, CanSetDropBehind {
036      private final OutputStream wrappedStream;
037    
038      private static class PositionCache extends FilterOutputStream {
039        private FileSystem.Statistics statistics;
040        long position;
041    
042        public PositionCache(OutputStream out, 
043                             FileSystem.Statistics stats,
044                             long pos) throws IOException {
045          super(out);
046          statistics = stats;
047          position = pos;
048        }
049    
050        public void write(int b) throws IOException {
051          out.write(b);
052          position++;
053          if (statistics != null) {
054            statistics.incrementBytesWritten(1);
055          }
056        }
057        
058        public void write(byte b[], int off, int len) throws IOException {
059          out.write(b, off, len);
060          position += len;                            // update position
061          if (statistics != null) {
062            statistics.incrementBytesWritten(len);
063          }
064        }
065          
066        public long getPos() throws IOException {
067          return position;                            // return cached position
068        }
069        
070        public void close() throws IOException {
071          out.close();
072        }
073      }
074    
075      @Deprecated
076      public FSDataOutputStream(OutputStream out) throws IOException {
077        this(out, null);
078      }
079    
080      public FSDataOutputStream(OutputStream out, FileSystem.Statistics stats)
081        throws IOException {
082        this(out, stats, 0);
083      }
084    
085      public FSDataOutputStream(OutputStream out, FileSystem.Statistics stats,
086                                long startPosition) throws IOException {
087        super(new PositionCache(out, stats, startPosition));
088        wrappedStream = out;
089      }
090      
091      /**
092       * Get the current position in the output stream.
093       *
094       * @return the current position in the output stream
095       */
096      public long getPos() throws IOException {
097        return ((PositionCache)out).getPos();
098      }
099    
100      /**
101       * Close the underlying output stream.
102       */
103      public void close() throws IOException {
104        out.close(); // This invokes PositionCache.close()
105      }
106    
107      /**
108       * Get a reference to the wrapped output stream. Used by unit tests.
109       *
110       * @return the underlying output stream
111       */
112      @InterfaceAudience.LimitedPrivate({"HDFS"})
113      public OutputStream getWrappedStream() {
114        return wrappedStream;
115      }
116    
117      @Override  // Syncable
118      @Deprecated
119      public void sync() throws IOException {
120        if (wrappedStream instanceof Syncable) {
121          ((Syncable)wrappedStream).sync();
122        }
123      }
124      
125      @Override  // Syncable
126      public void hflush() throws IOException {
127        if (wrappedStream instanceof Syncable) {
128          ((Syncable)wrappedStream).hflush();
129        } else {
130          wrappedStream.flush();
131        }
132      }
133      
134      @Override  // Syncable
135      public void hsync() throws IOException {
136        if (wrappedStream instanceof Syncable) {
137          ((Syncable)wrappedStream).hsync();
138        } else {
139          wrappedStream.flush();
140        }
141      }
142    
143      @Override
144      public void setDropBehind(Boolean dropBehind) throws IOException {
145        try {
146          ((CanSetDropBehind)wrappedStream).setDropBehind(dropBehind);
147        } catch (ClassCastException e) {
148          throw new UnsupportedOperationException("the wrapped stream does " +
149              "not support setting the drop-behind caching setting.");
150        }
151      }
152    }