All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.emc.ecs.nfsclient.nfs.io.NfsFileOutputStream Maven / Gradle / Ivy

Go to download

NFS Client for Java - provides read/write access to data on NFS servers. The current implementation supports only NFS version 3.

There is a newer version: 1.1.0
Show newest version
/**
 * Copyright 2016 EMC Corporation. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.emc.ecs.nfsclient.nfs.io;

import com.emc.ecs.nfsclient.nfs.NfsCreateMode;
import com.emc.ecs.nfsclient.nfs.NfsSetAttributes;
import com.emc.ecs.nfsclient.nfs.NfsWriteRequest;
import com.emc.ecs.nfsclient.nfs.NfsWriteResponse;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The NFS equivalent of java.io.FileOutputStream.
 * 
 * @author seibed
 */
public class NfsFileOutputStream extends OutputStream {

    /**
     * The usual logger.
     */
    private static final Logger LOG = LoggerFactory.getLogger(NfsFileOutputStream.class);

    private NfsFile _nfsFile;

    /**
     * The file offset used to write data that has not been committed. This is
     * advanced after each commit.
     */
    private long _offset;

    /**
     * The current value of the file offset to which we have written data. This
     * is advanced after each write.
     */
    private long _currentOffset;

    /**
     * How the NFS server should write to the file.
     * 
    *
  • UNSTABLE = 0 - Best effort, no promises.
  • *
  • DATA_SYNC = 1 - Commit all data to stable storage, plus enough * metadata for retrieval, before returning.
  • *
  • FILE_SYNC = 2 - Commit all data and metadata to stable storage before * returning.
  • *
*/ private final int _syncType; /** * The data currently being buffered. */ private final byte[] _buffer; /** * The next position for writing in the buffer. */ private int _bufferOffset = 0; /** * Flag to make sure operations are not run after closing the stream. */ private boolean _closed = false; /** * Creates a file output stream to write to the file represented by the * specified NfsFile object, starting at * offset = 0 and using syncType = FILE_SYNC * (commit all data and metadata to stable storage before returning). *

* If the file does not exist, it will first be created. * * @param nfsFile * The file to be opened for writing. * @throws IOException * If the file exists but is a directory rather than a regular * file, does not exist but cannot be created, or cannot be * opened for any other reason */ public NfsFileOutputStream(NfsFile nfsFile) throws IOException { this(nfsFile, 0, NfsWriteRequest.FILE_SYNC); } /** * Creates a file output stream to write to the file represented by the * specified NfsFile object, starting at * offset = 0 and using syncType behavior. *

* If the file does not exist, it will first be created. * * @param nfsFile * The file to be opened for writing. * @param syncType * One of the values below. *

    *
  • UNSTABLE = 0 - Best effort, no promises.
  • *
  • DATA_SYNC = 1 - Commit all data to stable storage, plus * enough metadata for retrieval, before returning.
  • *
  • FILE_SYNC = 2 - Commit all data and metadata to stable * storage before returning.
  • *
* @throws IOException * If the file exists but is a directory rather than a regular * file, does not exist but cannot be created, or cannot be * opened for any other reason */ public NfsFileOutputStream(NfsFile nfsFile, int syncType) throws IOException { this(nfsFile, 0, syncType); } /** * Creates a file output stream to write to the file represented by the * specified NfsFile object, starting at offset * and using syncType behavior. *

* If the file does not exist, it will first be created. * * @param nfsFile * The file to be opened for writing. * @param offset * Where to start writing to the file. * @param syncType * One of the values below. *

    *
  • UNSTABLE = 0 - Best effort, no promises.
  • *
  • DATA_SYNC = 1 - Commit all data to stable storage, plus * enough metadata for retrieval, before returning.
  • *
  • FILE_SYNC = 2 - Commit all data and metadata to stable * storage before returning.
  • *
* @throws IOException * If the file exists but is a directory rather than a regular * file, does not exist but cannot be created, or cannot be * opened for any other reason */ public NfsFileOutputStream(NfsFile nfsFile, long offset, int syncType) throws IOException { // Validate the offset. if (offset < 0) { throw new IllegalArgumentException("Cannot start writing before offset 0: " + offset); } // Validate the syncType value. switch (syncType) { case NfsWriteRequest.DATA_SYNC: case NfsWriteRequest.FILE_SYNC: case NfsWriteRequest.UNSTABLE: break; // do nothing, these are fine. default: throw new IllegalArgumentException("The value of syncType is undefined: " + syncType); } _nfsFile = nfsFile; if (_nfsFile.exists()) { // Validate the file. if (!(_nfsFile.canExtend() && _nfsFile.canModify())) { throw new IllegalArgumentException( "The file must be writable by the client: " + nfsFile.getAbsolutePath()); } } else { // Create the file. NfsSetAttributes attributes = new NfsSetAttributes(); attributes.setMode(NfsFile.ownerReadModeBit | NfsFile.ownerWriteModeBit); _nfsFile.create(NfsCreateMode.GUARDED, attributes, null); } _offset = offset; _currentOffset = offset; _syncType = syncType; _buffer = new byte[(int) Math.min(_nfsFile.fsinfo().getFsInfo().wtpref, Integer.MAX_VALUE)]; } /* * (non-Javadoc) * * @see java.io.OutputStream#close() */ public void close() throws IOException { if (!_closed) { try { flush(); } catch (Throwable t) { LOG.debug(t.getMessage(), t); } _closed = true; super.close(); } } /* * (non-Javadoc) * * @see java.io.OutputStream#flush() */ public void flush() throws IOException { checkForClosed(); writeBufferToFile(); if (_currentOffset > _offset) { // something to commit _nfsFile.commit(_offset, (int) (_currentOffset - _offset)); _offset = _currentOffset; } super.flush(); } /* * (non-Javadoc) * * @see java.io.OutputStream#write(int) */ public void write(int b) throws IOException { write(new byte[] { (byte) b }, 0, 1); } /* * (non-Javadoc) * * @see java.io.OutputStream#write(byte[]) */ public void write(byte[] b) throws IOException { write(b, 0, b.length); } /* * (non-Javadoc) * * @see java.io.OutputStream#write(byte[], int, int) */ public void write(byte[] b, int off, int len) throws IOException { checkForClosed(); if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (len < 0) || ((off + len) > b.length)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } if (len > bytesLeftInBuffer()) { int bytesToWrite = bytesLeftInBuffer(); write(b, off, bytesToWrite); write(b, off + bytesToWrite, len - bytesToWrite); } else { System.arraycopy(b, off, _buffer, _bufferOffset, len); _bufferOffset += len; if (bytesLeftInBuffer() == 0) { writeBufferToFile(); } } } /** * @return The number of bytes that can be written to the buffer before * overflow occurs. */ private int bytesLeftInBuffer() { return _buffer.length - _bufferOffset; } /** * Convenience function. * * @throws IOException * If the stream has been closed. */ private void checkForClosed() throws IOException { if (_closed) { throw new IOException("This stream has been closed."); } } /** * Write the buffer contents to the file and reset the buffer afterwards. * * @throws IOException */ private void writeBufferToFile() throws IOException { if (_bufferOffset > 0) { List payload = new ArrayList(1); payload.add(ByteBuffer.wrap(_buffer, 0, _bufferOffset)); NfsWriteResponse response = _nfsFile.write(_currentOffset, payload, _syncType); int bytesWritten = response.getCount(); _currentOffset += bytesWritten; _bufferOffset -= bytesWritten; if (0 != _bufferOffset) { // Everything was not written. // _bufferOffset should be the number of unwritten bytes. // Copy the unwritten bytes to the beginning of the buffer. System.arraycopy(_buffer, bytesWritten, _buffer, 0, _bufferOffset); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy