src.com.ibm.as400.access.IFSFileOutputStreamImplRemote Maven / Gradle / Ivy
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: IFSFileOutputStreamImplRemote.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2004 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
// @A1 2008-02-22 Change write() method to pass 'long' rather than 'int' to
// the fd_.setFileOffset() method which accepts a long parameter.
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.OutputStream;
/**
Provides a full remote implementation for the IFSFileOutputStream and
IFSTextFileOutputStream classes.
**/
class IFSFileOutputStreamImplRemote
extends OutputStream
implements IFSFileOutputStreamImpl
{
private boolean append_ = false;
private IFSFileDescriptorImplRemote fd_; // file info
// Variables needed by subclass IFSTextFileOutputStream:
transient private ConverterImplRemote converter_; // @B3a
// Used for debugging only. This should always be false for production.
// When this is false, all debug code will theoretically compile out.
private static final boolean DEBUG = false; // @B2A
// Static initialization code.
static
{
// Add all byte stream reply data streams of interest to the
// AS400 server's reply data stream hash table.
AS400Server.addReplyStream(new IFSListAttrsRep(), AS400.FILE);
AS400Server.addReplyStream(new IFSOpenRep(), AS400.FILE);
AS400Server.addReplyStream(new IFSReturnCodeRep(), AS400.FILE);
}
/**
Closes this file output stream and releases any system resources associated
with this stream.
@exception IOException If an error occurs while communicating with the server.
**/
public void close()
throws IOException
{
// Close the OutputStream.
fd_.close0(); // @B4a
}
public void connectAndOpen(int ccsid)
throws AS400SecurityException, IOException
{
fd_.connect();
if (ccsid == -1)
open(fd_.getPreferredCCSID());
else
open(ccsid);
}
/**
Ensures that the file output stream is closed when there are no more
references to it.
@exception IOException If an error occurs while communicating with the server.
**/
protected void finalize()
throws Throwable
{
try
{
if (fd_ != null)
fd_.finalize0(); // @B2C
}
catch(Throwable e)
{
Trace.log(Trace.ERROR, "Error during finalization.", e);
}
finally
{
super.finalize();
}
}
/**
Forces any buffered output bytes to be written.
@exception IOException If an error occurs while communicating with the server.
**/
public void flush()
throws IOException
{
// Flush the OutputStream.
open(fd_.getPreferredCCSID()); // @B4a
try {
fd_.flush(); // @B4a
}
catch (AS400SecurityException e) {
IOException throwException = new IOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
}
/**
Places a lock on the file at the current position for the specified number
of bytes.
@param length The number of bytes to lock.
@return A key for undoing this lock.
@exception IOException If an error occurs while communicating with the server.
@see IFSKey
@see #unlock
**/
public IFSKey lock(long length)
throws IOException
{
// Assume the argument has been validated by the public class.
// Ensure that the file is open.
open(fd_.getPreferredCCSID());
try {
return fd_.lock(length); // @B2C
}
catch (AS400SecurityException e) {
IOException throwException = new IOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
}
/**
Opens the specified file.
@exception IOException If an error occurs while communicating with the server.
**/
public void open(int fileDataCCSID)
throws IOException
{
// If the file is already open, do nothing.
if (fd_.isOpen_)
{
return;
}
// Throw ConnectionDroppedException if attempting to open the file
// after it has been closed.
if (!fd_.isOpenAllowed_)
{
throw new ConnectionDroppedException(ConnectionDroppedException.CONNECTION_NOT_ACTIVE);
}
// Ensure that the path has been set.
String path = fd_.getPath();
if (path.length() == 0)
{
throw new ExtendedIllegalStateException("path",
ExtendedIllegalStateException.PROPERTY_NOT_SET);
}
// Ensure that we are connected to the byte stream server.
try
{
fd_.connect();
}
catch(AS400SecurityException e)
{
Trace.log(Trace.ERROR, "Security exception", e);
throw new ExtendedIOException(ExtendedIOException.ACCESS_DENIED);
}
// Convert the path name to the server CCSID.
byte[] pathname = fd_.getConverter().stringToByteArray(path);
// Request that the file be created if it doesn't exist, opened
// if it does.
if (fileDataCCSID == -1)
{
fileDataCCSID = fd_.getPreferredCCSID();
}
IFSOpenReq req = new IFSOpenReq(pathname, fd_.getPreferredCCSID(),
fileDataCCSID,
IFSOpenReq.WRITE_ACCESS,
~fd_.getShareOption(),
IFSOpenReq.NO_CONVERSION,
(append_ ? 1 : 2),
fd_.serverDatastreamLevel_);
ClientAccessDataStream ds = null;
try
{
ds = (ClientAccessDataStream) fd_.getServer().sendAndReceive(req);
}
catch(ConnectionDroppedException e)
{
Trace.log(Trace.ERROR, "Byte stream server connection lost");
fd_.connectionDropped(e);
}
catch(InterruptedException e)
{
Trace.log(Trace.ERROR, "Interrupted", e);
InterruptedIOException throwException = new InterruptedIOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
// Verify that the open request was successful.
if (ds instanceof IFSOpenRep)
{
// Get the file information.
IFSOpenRep rep = (IFSOpenRep) ds;
fd_.setOpen(true, rep.getFileHandle());
fd_.setOpenAllowed(false);
if (append_)
{
// We must append to the file.
fd_.setFileOffset(rep.getFileSize(fd_.serverDatastreamLevel_)); // @B7c
}
}
else if (ds instanceof IFSReturnCodeRep)
{
// If the file can't be opened because another open instance of
// this file isn't allowing file sharing, then the byte stream
// server returns file-in-use. In this case, throw an IOException
// with a detail message of 32 (sharing-violation).
int rc = ((IFSReturnCodeRep) ds).getReturnCode();
if (rc == IFSReturnCodeRep.FILE_IN_USE)
{
Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", rc);
throw new ExtendedIOException(ExtendedIOException.SHARING_VIOLATION);
}
else
{
Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", rc);
throw new ExtendedIOException(rc);
}
}
else
{
// Unknown data stream.
Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
throw new
InternalErrorException(Integer.toHexString(ds.getReqRepID()),
InternalErrorException.DATA_STREAM_UNKNOWN);
}
}
public void setAppend(boolean append)
{
append_ = append;
}
/**
Sets the file descriptor.
@param fd The file descriptor.
**/
public void setFD(IFSFileDescriptorImpl fd)
{
// Assume the argument has been validated by the public class.
// Cast the argument to an xxxImplRemote.
fd_ = IFSFileDescriptorImplRemote.castImplToImplRemote(fd); // @B2C
}
/**
Undoes a lock on this file.
@param key The key for the lock.
@exception IOException If an error occurs while communicating with the server.
@see IFSKey
@see #lock
**/
public void unlock(IFSKey key)
throws IOException
{
// Assume the argument has been validated by the public class.
// Ensure that the file is open.
open(fd_.getPreferredCCSID());
try {
fd_.unlock(key); // @B2C
}
catch (AS400SecurityException e) {
IOException throwException = new IOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
}
/**
Writes the specified byte to this file output stream.
This method is implemented to qualify this class as an OutputStream.
@param b The byte to be written.
@exception IOException If an error occurs while communicating with the server.
**/
public void write(int b)
throws IOException
{
byte[] data = new byte[1];
data[0] = (byte) b;
write(data, 0, 1);
}
/**
Writes data.length bytes of data from the byte array data
to this file output stream.
This method is implemented to qualify this class as an OutputStream.
@param data The data to be written.
@exception IOException If an error occurs while communicating with the server.
**/
public void write(byte[] data)
throws IOException
{
write(data, 0, data.length);
}
/**
Writes length bytes of data from the byte array data, starting
at offset, to this file output stream.
@param data The data to be written.
@param offset The start offset in the data.
@param length The number of bytes to write.
@exception IOException If an error occurs while communicating with the server.
**/
public void write(byte[] data,
int dataOffset,
int length)
throws IOException
{
// Assume the arguments have been validated by the public class.
// Ensure that the file is open.
open(fd_.getPreferredCCSID());
int fileHandle = fd_.getFileHandle();
// @A4A (beginning of code block)
if (append_) // We must append to the very end of the file.
{
IFSListAttrsReq req = new IFSListAttrsReq(fileHandle);
// Send the request.
ClientAccessDataStream ds = null;
try
{
// Send the request and receive the response.
ds = (ClientAccessDataStream) fd_.getServer().sendAndReceive(req);
}
catch(ConnectionDroppedException e)
{
Trace.log(Trace.ERROR, "Byte stream server connection lost");
fd_.connectionDropped(e);
}
catch(InterruptedException e)
{
Trace.log(Trace.ERROR, "Interrupted", e);
InterruptedIOException throwException = new InterruptedIOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
if (ds instanceof IFSListAttrsRep)
{
// Get the file information.
IFSListAttrsRep rep = (IFSListAttrsRep) ds;
fd_.setFileOffset(rep.getSize(fd_.serverDatastreamLevel_)); // @B7c //@A1C remove (int) cast
}
else if (ds instanceof IFSReturnCodeRep)
{
int rc = ((IFSReturnCodeRep) ds).getReturnCode();
if (rc != IFSReturnCodeRep.SUCCESS)
{
Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", rc);
throw new ExtendedIOException(rc);
}
}
else
{
// Unknown data stream.
Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
throw new
InternalErrorException(Integer.toHexString(ds.getReqRepID()),
InternalErrorException.DATA_STREAM_UNKNOWN);
}
}
// @A4A (end of code block)
try {
fd_.writeBytes(data, dataOffset, length); // @B2C
}
catch (AS400SecurityException e) {
IOException throwException = new IOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
}
// Used by IFSTextFileOutputStream.write(String) only:
/**
Writes characters to this text file output stream.
The characters that are written to the file are converted to the
specified CCSID.
@param data The characters to write to the stream.
@param ccsid The CCSID for the data.
@exception IOException If an error occurs while communicating with the server.
**/
public void writeText(String data, int ccsid)
throws IOException
{
// Assume the arguments have been validated by the public class.
// Ensure that the file is open.
open(ccsid);
// Create the OutputStreamWriter if we don't already have one.
if (converter_ == null) // @B4c
{
int fileCCSID = 0; // @B2C - formerly codePage
// Determine the file character encoding if the CCSID property
// value has not been set.
if (ccsid == -1)
{
// Issue a List File Attributes request to obtain the CCSID (or code page)
// of the file.
try
{
ClientAccessDataStream ds = null;
// Issue the "list attributes" request.
IFSListAttrsReq req =
new IFSListAttrsReq(fd_.getFileHandle(), IFSListAttrsReq.OA2, 0, 0);
// We need to get an OA2 structure in the reply, since it contains the CCSID field.
ds = (ClientAccessDataStream) fd_.getServer().sendAndReceive(req);
boolean done = false;
boolean gotCCSID = false;
do
{
if (ds instanceof IFSListAttrsRep)
{
if (Trace.traceOn_ && gotCCSID)
Trace.log(Trace.DIAGNOSTIC, "Received multiple replies " +
"from ListAttributes request.");
fileCCSID = ((IFSListAttrsRep) ds).getCCSID(fd_.serverDatastreamLevel_);
if (DEBUG)
System.out.println("DEBUG: IFSFileOutputStreamImplRemote.writeText(): " +
"Reported CCSID for file is " + fileCCSID); // @B2A
gotCCSID = true;
}
else if (ds instanceof IFSReturnCodeRep)
{
// If the return code is NO_MORE_FILES then all files
// that match the specification have been returned.
int rc = ((IFSReturnCodeRep) ds).getReturnCode();
if (rc != IFSReturnCodeRep.NO_MORE_FILES &&
rc != IFSReturnCodeRep.SUCCESS)
{
Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", rc);
throw new ExtendedIOException(rc);
}
}
else
{
// Unknown data stream.
Trace.log(Trace.ERROR, "Unknown reply data stream", ds.data_);
throw new
InternalErrorException(Integer.toHexString(ds.getReqRepID()),
InternalErrorException.DATA_STREAM_UNKNOWN);
}
// Fetch the next reply if not already done.
done = ((IFSDataStream) ds).isEndOfChain();
if (!done)
{
try
{
ds = (ClientAccessDataStream) fd_.getServer().receive(req.getCorrelation());
}
catch(ConnectionDroppedException e)
{
Trace.log(Trace.ERROR, "Byte stream server connection lost.");
fd_.connectionDropped(e);
}
catch(InterruptedException e)
{
Trace.log(Trace.ERROR, "Interrupted");
InterruptedIOException throwException = new InterruptedIOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
}
}
while (!done);
if (!gotCCSID || fileCCSID == 0)
{
Trace.log(Trace.ERROR, "Unable to determine CCSID of file " + fd_.path_);
throw new ExtendedIOException(ExtendedIOException.UNKNOWN_ERROR);
}
}
catch(ConnectionDroppedException e)
{
fd_.connectionDropped(e);
}
catch(InterruptedException e)
{
Trace.log(Trace.ERROR, "Interrupted", e);
InterruptedIOException throwException = new InterruptedIOException(e.getMessage());
try {
throwException.initCause(e);
} catch (Throwable t) {}
throw throwException;
}
ccsid = fileCCSID;
}
converter_ = ConverterImplRemote.getConverter(ccsid, fd_.getSystem()); //@B3a
}
// Write the characters of the String.
this.write(converter_.stringToByteArray(data)); //@B3a
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy