// Determine the system version.
 int getSystemVRM() // @B3A @C1c
     {
   if (!determinedSystemVRM_) {
     // The version number is in the high 16 bits of VRM.
     // High 16 bits represent version next 8 bits represent release,
     // low 8 bits represent modification.
     // Thus Version 4, release 5, modification level 0 is 0x00040500.
     systemVRM_ = system_.getVRM(); // @B4C
     determinedSystemVRM_ = true;
   }
   return systemVRM_;
 }
 /**
  * Disconnects from the byte stream server.
  *
  * @exception ConnectionDroppedException If the connection is dropped unexpectedly.
  */
 void connectionDropped(
     ConnectionDroppedException e) // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
     throws ConnectionDroppedException {
   if (server_ != null) {
     system_.disconnectServer(server_);
     server_ = null;
     try {
       close();
     } catch (Exception exc) {
     } // Note: Not relevant for IFSFileImplRemote.
   }
   Trace.log(Trace.ERROR, "Byte stream connection lost.");
   throw e;
 }
  /**
   * Establishes communications with the server.
   *
   * @exception AS400SecurityException If a security or authority error occurs.
   * @exception IOException If an error occurs while communicating with the server.
   */
  void connect() // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      throws IOException, AS400SecurityException {
    // Connect to the byte stream server if not already connected.
    if (server_ == null) {
      // Ensure that the system has been set.
      if (system_ == null) {
        throw new ExtendedIllegalStateException(
            "system", ExtendedIllegalStateException.PROPERTY_NOT_SET);
      }

      try {
        server_ = system_.getConnection(AS400.FILE, false);
      } catch (AS400SecurityException e) {
        Trace.log(
            Trace.ERROR,
            "Access to byte stream server on '" + system_.getSystemName() + "' denied.",
            e);
        throw e;
      }

      // Exchange attributes with the server.
      exchangeServerAttributes();
    }
  }
  /**
   * Exchanges server attributes.
   *
   * @exception IOException If an error occurs while communicating with the server.
   */
  void exchangeServerAttributes() // @B2A - code relocated from IFSFileOutputStreamImplRemote,etc.
      throws IOException, AS400SecurityException {
    synchronized (server_) {
      DataStream ds = server_.getExchangeAttrReply();
      IFSExchangeAttrRep rep = null;
      try {
        rep = (IFSExchangeAttrRep) ds;
      } catch (ClassCastException e) {
        if (ds instanceof IFSReturnCodeRep) {
          int rc = ((IFSReturnCodeRep) ds).getReturnCode();
          throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
          Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
          throw new ExtendedIOException(path_, rc);
        } else {
          String className = (ds == null ? "null" : ds.getClass().getName());
          Trace.log(Trace.ERROR, "Unexpected reply from Exchange Server Attributes: " + className);
          throw new InternalErrorException(InternalErrorException.DATA_STREAM_UNKNOWN);
        }
      }

      // Note: For releases after V5R4, we ask for Datastream Level 16;
      // for V5R3 thru V5R4, we ask for Datastream Level 8;
      // for V4R5 thru V5R2, we ask for Datastream Level 2;
      // for earlier systems, we ask for Datastream Level 0.    // @B6c
      if (getSystemVRM() >= 0x00060100) requestedDatastreamLevel_ = 16;
      else if (getSystemVRM() >= 0x00050300) requestedDatastreamLevel_ = 8;
      else if (getSystemVRM() >= 0x00040500) // @B3A @B4C
      requestedDatastreamLevel_ = 2;
      else requestedDatastreamLevel_ = 0;
      if (rep == null) {
        ds = null;
        try {
          int[] preferredCcsids; // @A2A
          // Datastream level 8 was introduced in release V5R3.
          if (getSystemVRM() >= 0x00050300) { // System is post-V5R2.
            preferredCcsids = new int[] {0x04b0, 0x34b0, 0xf200}; // UTF-16, new or old Unicode.
          }
          // Note: Pre-V4R5 systems hang when presented with multiple
          // preferred CCSIDs in the exchange of attributes.   @B3A @B4C
          else if (getSystemVRM() >= 0x00040500) // @B3A @B4C
          { // System is V4R5 or later.  We can present a list of preferred CCSIDs.
            preferredCcsids = new int[] {0x34b0, 0xf200}; // New or old Unicode.
          } else { // System is pre-V4R5.  Exchange attr's the old way.
            preferredCcsids = new int[] {0xf200}; // Old Unicode only.
          }

          // Use GMT date/time, don't use posix style return codes,
          // use PC pattern matching semantics,
          // maximum data transfer size of 0xffffffff.
          ds =
              server_.sendExchangeAttrRequest( // @B3A
                  new IFSExchangeAttrReq(
                      true,
                      false,
                      IFSExchangeAttrReq.PC_PATTERN_MATCH,
                      0xffffffff,
                      requestedDatastreamLevel_,
                      preferredCcsids)); // @A2C
          rep = (IFSExchangeAttrRep) ds;
        } catch (ConnectionDroppedException e) {
          Trace.log(Trace.ERROR, "Byte stream server connection lost");
          connectionDropped(e);
        } catch (InterruptedException e) {
          Trace.log(Trace.ERROR, "Interrupted", e);
          system_.disconnectServer(server_);
          server_ = null;
          throw new InterruptedIOException(e.getMessage());
        } catch (IOException e) {
          Trace.log(Trace.ERROR, "I/O error during attribute exchange.");
          system_.disconnectServer(server_);
          server_ = null;
          throw e;
        } catch (ClassCastException e) {
          if (ds instanceof IFSReturnCodeRep) {
            int rc = ((IFSReturnCodeRep) ds).getReturnCode();
            throwSecurityExceptionIfAccessDenied(path_, rc); // check for "access denied"
            Trace.log(Trace.ERROR, "IFSReturnCodeRep return code", descriptionForReturnCode(rc));
            throw new ExtendedIOException(path_, rc);
          } else {
            String className = (ds == null ? "null" : ds.getClass().getName());
            Trace.log(
                Trace.ERROR, "Unexpected reply from Exchange Server Attributes: " + className);
            throw new InternalErrorException(InternalErrorException.DATA_STREAM_UNKNOWN);
          }
        }
      }

      // Process the exchange attributes reply.
      if (rep != null) {
        maxDataBlockSize_ = ((IFSExchangeAttrRep) rep).getMaxDataBlockSize();
        preferredServerCCSID_ = rep.getPreferredCCSID();
        serverDatastreamLevel_ = rep.getDataStreamLevel();
        setConverter(ConverterImplRemote.getConverter(preferredServerCCSID_, system_));
        if (DEBUG) {
          System.out.println(
              "DEBUG: IFSFileDescriptorImplRemote.exchangeServerAttributes(): "
                  + "preferredServerCCSID_ == "
                  + preferredServerCCSID_);
          int[] list = rep.getPreferredCCSIDs();
          for (int i = 0; i < list.length; i++)
            System.out.println("-- Server's preferred CCSID (#" + i + 1 + "): " + list[i]);
          System.out.println(
              "-- Server's dataStreamLevel : " + Integer.toHexString(serverDatastreamLevel_));
        }
      } else {
        // Should never happen.
        if (rep != null) {
          Trace.log(Trace.ERROR, "Unknown reply data stream", rep.data_);
          system_.disconnectServer(server_);
          server_ = null;
          throw new InternalErrorException(
              Integer.toHexString(rep.getReqRepID()), InternalErrorException.DATA_STREAM_UNKNOWN);
        } else {
          Trace.log(Trace.ERROR, "Null reply data stream");
          system_.disconnectServer(server_);
          server_ = null;
          throw new InternalErrorException(InternalErrorException.DATA_STREAM_UNKNOWN);
        }
      }
    }
  }