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

src.com.ibm.as400.access.SpooledFileOutputStreamImplRemote Maven / Gradle / Ivy

There is a newer version: 11.1
Show newest version
///////////////////////////////////////////////////////////////////////////////
//                                                                             
// JTOpen (IBM Toolbox for Java - OSS version)                              
//                                                                             
// Filename: SpooledFileOutputStreamImplRemote.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-2000 International Business Machines Corporation and     
// others. All rights reserved.                                                
//                                                                             
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.OutputStream;
import java.io.IOException;

/**
  * The SpooledFileOutputStream class is used to write data into a server spooled file.
  **/
class SpooledFileOutputStreamImplRemote
implements SpooledFileOutputStreamImpl
{   
    static final String DT_AUTO = "*AUTO";
    static final String DT_PRTF = "*PRTF";

    private byte[] buffer_ = new byte[4096];  // we'll buffer up to 4K before sending

    private NPConversation conversation_;

    private NPCPAttribute  cpAttr_;             // attributes to create spooled file with
    private NPCPAttribute  cpCPFMsg_;           // any error messages come back here
    private NPCPIDSplF     cpIDSplF_;           // ID codepoint of spooled file created
    private NPCPIDOutQ     cpIDOutQ_;           // output queue ID (may be null)
    private NPCPIDPrinterFile  cpIDPrtrFile_;   // printer file ID (may be null)
    private NPCPSplFHandle cpSplFHndl_;         // handle used for writes and close request

    private boolean        fCreatePending_;
    private NPSystem       npSystem_;
    private int            offset_ = 0;                  // current offset into buffer
    private AS400ImplRemote sys_;

    /**
      * Constructs a SpooledFileOutputStream object.
      * Use this object to create a new spooled file on the given system
      * with the specified parameters.
      * @param system The system on which to create the spooled file.
      * @param options       Optional.  A print parameter list that contains
      *                          a list of attributes with which to create the spooled file.
      *                          The attributes set in options will
      *                          override those attributes in the printer file that is used.
      *                          The printer file used will be the one specified with the
      *                          printerFile parameter, or if that parameter is null,
      *                          it will be the default network print server printer file (QPNPSPRTF).
      *                          If the output queue is specified in options, it
      *                          will override any output queue passed in the outputQueue
      *                          parameter.
      *                          The following parameters may be set:
      * 
      * Note 1: Code page and graphical character set are dependent upon each
      *  other.  If you set one you must set the other.
      * 
* Note 2: The special value of *FILE is not allowed when creating a new * spooled file. *
* Note 3: Up to 4 user-defined options may be specified. *

* @param printerFile Optional. The printer file that should be used * to create the spooled file. This printer file * must reside on the same server system that the * spooled file is being created on. * @param outputQueue Optional. The output queue on which to create the * spooled file. The output queue must reside on * the same server system that the spooled file * is being created on. * @exception AS400Exception If the server returns an error message. * @exception AS400SecurityException If a security or authority error occurs. * @exception ErrorCompletingRequestException If an error occurs before the request is completed. * @exception IOException If an error occurs while communicating with the server. * @exception InterruptedException If this thread is interrupted. **/ public synchronized void createSpooledFileOutputStream(AS400Impl system, PrintParameterList options, PrinterFileImpl printerFile, OutputQueueImpl outputQueue) throws AS400Exception, AS400SecurityException, ErrorCompletingRequestException, InterruptedException, IOException { // Force the system param to connect if it isn't already // so that we can check its system name against the // system outputQueue and printerFile are on // NPSystem npSystem = NPSystem.getSystem(system); // NPConversation conv = npSystem.getConversation(); // npSystem.returnConversation(conv); // we're done with it fCreatePending_ = true; // we haven't issued the create yet sys_ = (AS400ImplRemote) system; npSystem_ = NPSystem.getSystem(sys_); conversation_ = npSystem_.getConversation(); cpCPFMsg_ = new NPCPAttribute(); cpIDSplF_ = new NPCPIDSplF(); cpSplFHndl_ = new NPCPSplFHandle(); // if the user passed in a printer file, get its ID if (printerFile != null) { cpIDPrtrFile_ = (NPCPIDPrinterFile)((PrinterFileImplRemote) printerFile).getIDCodePoint(); } // if the user passed in an output queue, get its ID if (outputQueue != null) { cpIDOutQ_ = (NPCPIDOutQ)((OutputQueueImplRemote) outputQueue).getIDCodePoint(); } //------------------------------------------------------------- // figure out what data type we're using. // If the user has specified nothing or *AUTO // delay the open until we get some data to analyze. // If the user has specified *PRTF, change it to be nothing and the server // will use what is in the printer file. //------------------------------------------------------------- String strDataType = null; cpAttr_ = new NPCPAttribute(); // we need our own copy because we may change things if (options != null) { cpAttr_.addUpdateAttributes(options.getAttrCodePoint()); } strDataType = cpAttr_.getStringValue(PrintObject.ATTR_PRTDEVTYPE); if (strDataType == null) { // datastream type not specified, so use *AUTO strDataType = DT_AUTO; } else { //------------------------------------------------------------- // strip trailing nulls & uppercase user specified value. //------------------------------------------------------------- strDataType = strDataType.toUpperCase().trim(); } //------------------------------------------------------------- // strDataType now contains the data type to use, whether the user // explicitly set it or we defaulted it. // Need to see if we should delay the create here // IF not // Need to change *PRTF to "" // IF pAttrs specified, change it to "". // ELSE // set create pending flag on // ENDIF //------------------------------------------------------------- if (strDataType.equals(DT_AUTO)) { fCreatePending_ = true; // data type is automatic so wait for create } else { if (strDataType.equals(DT_PRTF)) { strDataType = ""; } makeCreateRequest(strDataType); } } /** * Closes the stream. * It must be called to release any resources associated with the stream. * @exception IOException If an error occurs while communicating with the server. **/ public synchronized void close() throws IOException { if (conversation_ == null) { Trace.log(Trace.ERROR, "Conversation is null."); throw new IOException(); } // if there is any data pending. write it out if (offset_ != 0) { makeWriteRequest(buffer_, 0, offset_); offset_ = 0; } // if create is still pending here, then we have an empty spooled // file, send it up anyway... if (fCreatePending_) { makeCreateRequest(null); } NPDataStream closeReq = new NPDataStream(NPConstants.SPOOLED_FILE); NPDataStream closeRep = new NPDataStream(NPConstants.SPOOLED_FILE); // setup the close request data stream closeReq.setAction(NPDataStream.CLOSE); closeReq.addCodePoint(cpSplFHndl_); // setup the close reply to catch the return codepoints closeRep.addCodePoint(cpCPFMsg_); try { // make the request conversation_.makeRequest(closeReq, closeRep); } catch (Exception e) { Trace.log(Trace.ERROR, "Caught an Exception." + e.toString()); throw new IOException(e.toString()); } finally { // if we still have a conversation, return it if (conversation_ != null) { npSystem_.returnConversation(conversation_); conversation_ = null; } } } // close() /** * Closes the stream when garbage is collected. * @exception Throwable If an error occurs. **/ protected void finalize() throws Throwable { // We must be very careful here to not try to receive a // reply from the server - we are being called by the // garbage collector which could be running on the // background thread of the AS400Server object in our // conversation. If we were to call back to the AS400Server // to wait for a reply we could end up in a deadlock situation // Any requests we make we'll discard the reply on // if we still have a conversation // they must not have sent the close yet if (conversation_ != null) { // if we have sent the create request if (!fCreatePending_) { // send up a close request and ignore the reply NPDataStream closeReq = new NPDataStream(NPConstants.SPOOLED_FILE); // setup the close request data stream closeReq.setAction(NPDataStream.CLOSE); closeReq.addCodePoint(cpSplFHndl_); AS400Server server= conversation_.getServer(); if (server != null) { // @D closeReq.setHostCCSID(conversation_.getHostCCSID()); closeReq.setConverter(conversation_.getConverter()); server.sendAndDiscardReply(closeReq); } } npSystem_.returnConversation(conversation_); } super.finalize(); // always call super.finalize()! } /** Flushes the stream. This will write any buffered output bytes. * @exception IOException If an error occurs while communicating with the server. **/ public synchronized void flush() throws IOException { // send what we have, if any if (offset_ != 0) { makeWriteRequest(buffer_, 0, offset_); offset_ = 0; } } /** Returns the spooled file that was created (or is being created) with * this output stream. * @return A reference to the spooled file object. **/ public synchronized NPCPIDSplF getSpooledFile() throws IOException { // @D SpooledFile sf = null; NPCPIDSplF sfID = null; // flush any data we have first // if the file hasn't been closed already if (conversation_ != null) { flush(); } // if we've issued the create already if (!fCreatePending_) { // return the spooled file that we created // sf = new SpooledFile(sys_, cpIDSplF_, null); // @D (see below) // The call to create the SpooledFile will be made on the proxy side sfID = cpIDSplF_; } else { Trace.log(Trace.ERROR, "Spooled File has not been created."); throw new ExtendedIllegalStateException(ExtendedIllegalStateException.OBJECT_MUST_BE_OPEN); } // return sf; // @D return sfID; } /** * Generates the create request. * @param strDataType The PRTDEVTYPE to use (*SCS, *AFPDS, *USERASCII)... * @exception IOException If an error occurs while communicating with the server. **/ private synchronized void makeCreateRequest(String strDataType) throws IOException { if (conversation_ == null) { Trace.log(Trace.ERROR, "Conversation is null."); throw new IOException(); } //------------------------------------------------------------- // if datatype is something (override the printer file // set the datatype in the attributes //------------------------------------------------------------- if ((strDataType != null) && (!strDataType.equals(""))) // if strDataType is something { if (cpAttr_ == null) { cpAttr_ = new NPCPAttribute(); } cpAttr_.setAttrValue(PrintObject.ATTR_PRTDEVTYPE, strDataType); } NPDataStream createReq = new NPDataStream(NPConstants.SPOOLED_FILE); NPDataStream createRep = new NPDataStream(NPConstants.SPOOLED_FILE); // setup the create request data stream createReq.setAction(NPDataStream.CREATE); if (cpAttr_ != null) { createReq.addCodePoint(cpAttr_); } if (cpIDOutQ_ != null) { createReq.addCodePoint(cpIDOutQ_); } if (cpIDPrtrFile_ != null) { createReq.addCodePoint(cpIDPrtrFile_); } // setup the create reply to catch the return codepoints createRep.addCodePoint(cpSplFHndl_); createRep.addCodePoint(cpCPFMsg_); createRep.addCodePoint(cpIDSplF_); try { // make the request conversation_.makeRequest(createReq, createRep); } catch (Exception e) { Trace.log(Trace.ERROR, "Caught an Exception." + e.toString()); throw new IOException(e.toString()); } fCreatePending_ = false; // reset the create flag } // makeCreateRequest() /** * Generates the write request. * @param buf The array of bytes to write. * @param length The length of data to write. * @exception IOException If an error occurs while communicating with the server. **/ private synchronized void makeWriteRequest(byte[] buf, int offset, int len) throws IOException { if (conversation_ == null) { Trace.log(Trace.ERROR, "Conversation is null."); throw new IOException(); } // if the create is still pending here then // we should sniff the data and then issue the create // request with the correct data type if (fCreatePending_) { String strDataType = NPDataAnalyzer.sniff(buf, offset, len); makeCreateRequest(strDataType); } // // now make the write request // NPDataStream writeReq = new NPDataStream(NPConstants.SPOOLED_FILE); NPDataStream writeRep = new NPDataStream(NPConstants.SPOOLED_FILE); NPCPData cpData = new NPCPData(); cpData.setDataBuffer(buf, len, offset); // setup the write request data stream writeReq.setAction(NPDataStream.WRITE); writeReq.addCodePoint(cpSplFHndl_); writeReq.addCodePoint(cpData); // setup the create reply to catch the return codepoints writeRep.addCodePoint(cpCPFMsg_); try { // make the request conversation_.makeRequest(writeReq, writeRep); } catch (Exception e) { Trace.log(Trace.ERROR, "Caught an Exception." + e.toString()); throw new IOException(e.toString()); } } /** * Writes up to length bytes of data from the byte array data, * starting at offset, to this spooled file. * * @param data The data to be written. * @param offset The start offset in the data. * @param length The number of bytes that are written. * * @exception IOException If an error occurs while communicating with the server. **/ public synchronized void write(byte data[], int offset, int length) throws IOException { if (conversation_ == null) { Trace.log(Trace.ERROR, "SpooledFileOutputStream already closed."); throw new IOException(); } int currentSourceOffset = offset; int dataLeftToSend = length; while(dataLeftToSend > 0) { //------------------------------------------------------------- // calculate the available buffer space left in the current // buffer //------------------------------------------------------------- int availLen = buffer_.length - offset_; if (availLen >= dataLeftToSend) { //------------------------------------------------------------- // If we have enough to hold it all // Move it all to the current buffer //------------------------------------------------------------- System.arraycopy(data, currentSourceOffset, buffer_, offset_, dataLeftToSend); currentSourceOffset += dataLeftToSend; offset_ += dataLeftToSend; dataLeftToSend = 0; } else { if (availLen != 0) { //------------------------------------------------------------- // If we have ANY room at all // Move what we can from the callers buffer to // the current write bitstream //------------------------------------------------------------- System.arraycopy(data, currentSourceOffset, buffer_, offset_, availLen); currentSourceOffset += availLen; offset_ += availLen; dataLeftToSend -= availLen; } //------------------------------------------------------------- // if there is any data in the bytestream, send it out //------------------------------------------------------------- if (offset_ != 0) { makeWriteRequest(buffer_, 0, offset_); offset_ = 0; } } } // end while } // write(byte[], int, int) }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy