
/* **************************************************************************

  $Archive: /njcl_v2/src/com/novell/service/nds/net/NetStream.java $
  $Revision: 12 $
  $Modtime: 3/15/04 2:47p $
 
  Copyright (c) 1998 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

package com.novell.service.nds.net;


import java.io.*;
import java.io.Serializable;

import com.novell.service.nds.*;
import com.novell.java.io.*;
import com.novell.java.io.spi.*;
import com.novell.service.jncp.*;
import com.novell.service.session.Session;
import com.novell.service.session.SessionException;
import com.novell.service.jncpv2.net.*;
import com.novell.service.file.nw.calls.NativeDeviceAccessor;
import com.novell.service.toolkit.jcl.NWInteger;


/**
 * @internal
 * NetStream is an Adapter for NdsStream.
 * This class converts to/from
 * the NWNet Stream_T.
 *
 * API Data Structure:
 *    typedef struct
 *    {
 *       NWLEN     length;(always 0)
 *       pnuint8   data;
 *    } Stream_T;
 */
public final class NetStream
   extends NdsStream
   implements NetAttributeValue, DataAccessable, Serializable
{
   private static final String serviceKey    = BasicNetService.KEY;

   protected boolean initialized = false;

   protected String objectName;
   protected String attrName;

   protected Session session;
   protected NetService service;

   protected int bufferSize = 4096;


   /**
    * Constructs a Stream from the "API Data Structure".
    *
    * @param   value   byte[] containing a Stream_T
    */
   protected NetStream (
         Session session,
         NetService service,
         String objectName,
         String attrName)
      throws NSIException
   {
      this (session, service, objectName, attrName, null);
   }

   /**
    * Constructs a Stream from the "API Data Structure".
    *
    * @param   value   byte[] containing a Stream_T
    */
   private NetStream (
         Session session,
         NetService service,
         String objectName,
         String attrName,
         InputStream streamToWrite)
      throws NSIException
   {
         this.initialized = true;

         this.session = session;
         this.service = service;
         this.objectName = objectName;
         this.attrName = attrName;

         this.streamToWrite = streamToWrite;

   } /* NetStream () */

   /**
    * Constructs a NetStream adapter for an NdsStream.
    *
    * @param   value   an NdsStream object.
    */
   protected NetStream (
         NdsStream value)
      throws NSIException
   {
      super (value);

      if (value instanceof NetStream)
      {
         this.initialized = true;

         NetStream st = (NetStream) value;

         this.session = st.session;
         this.service = st.service;
         this.objectName = st.objectName;
         this.attrName = st.attrName;

         this.bufferSize = st.bufferSize;
      }
      else
      {
         this.initialized = false;
      }

   } /* NetStream () */

   public void initialize (
         Session session,
         NetService service,
         String objectName,
         String attrName,
         int bufferSize)
      throws NSIException
   {
      this.initialized = true;

      this.session = session;
      this.service = service;
      this.objectName = objectName;
      this.attrName = attrName;

      this.bufferSize = bufferSize;

   } /* initialize () */

   /**
    *
    */
   public NetMemory toCStruct ()
   {
      return (null);
   }

   /**
    * Returns a Stream "API Data Structure".
    *
    * @return   byte[] containing Stream_T.
    */
   public byte[] toByte ()
      throws NSIException
   {
     return (null);
   }

   public Object clone()
   {
      return (new NetStream (this));
   }

   public DataAccessor openStream (int type)
      throws NSIException
   {
      if (!initialized)
         throw new NSIException ();

      NWInteger nativeFileHandle = new NWInteger(0);

      int openFlags = 1;   // default to opening in read mode

      if (type == DataAccessor.READ)
         openFlags = 0x01; // read-only

      if (type == DataAccessor.WRITE)
         openFlags = 0x02; // write-only

      if (type == DataAccessor.RANDOM)
         openFlags = 0x01 | 0x02;   // read, write

      try
      {
         service.openStream (
                     objectName,
                     attrName,
                     openFlags,
                     nativeFileHandle);

         return new NativeDeviceAccessor(nativeFileHandle.getValue(),
            session, ((openFlags == 1)?true:false));
      }
      catch (NSIException e)
      {
         try
         {
         if (e.getCCode () == NDSErrors.ERR_NO_SUCH_VALUE)
         {
            createStreamAttribute (openFlags, nativeFileHandle);

            return new NativeDeviceAccessor(nativeFileHandle.getValue(),
               session, ((openFlags == 1)?true:false));
         }
         else
         {
            throw (e);
         }
         }
         catch (IOException ioe)
         {
            NSIException ne = new NSIException ();

            ne.setRootCause (ioe);
            throw (ne);
         }
      }
      catch (SessionException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }
      catch (IOException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }

   } /* openStream () */

   private void createStreamAttribute (
         int openFlags,
         NWInteger nativeFileHandle)
      throws NSIException
   {
      // pass a NULL attribute value into PutAttrVal
      NetBuffer buf = new NetBuffer (service);

      buf.initBuf (NetJNI.DSV_MODIFY_ENTRY);
      buf.putChange (NetJNI.DS_ADD_VALUE, attrName);
      buf.putAttributeValue (getNdsSyntaxId (), null);

      NetIterationHandle iter = new NetIterationHandle (service,
            NetJNI.DSV_MODIFY_ENTRY);

      try
      {
         service.modifyObject (
                        objectName,
                        iter,
                        false,
                        buf.getHandle ());

         service.openStream (
                        objectName,
                        attrName,
                        openFlags,
                        nativeFileHandle);
      }
      catch (SessionException e)
      {
         NSIException ne = new NSIException ();

         ne.setRootCause (e);
         throw (ne);
      }

   } /* createStreamAttribute () */

   public DataAccessor openStream (int type, Object custom)
      throws NSIException
   {
      if (custom instanceof Integer)
         return (openStream (((Integer) custom).intValue ()));

      throw new NSIException();
   }

   /**
    *
    */
   public DataAccessor openStream(String name, int type)
      throws IOException
   {
      throw new NoSubordinateAccessException ();
   }

   /**
    *
    */
   public DataAccessor openStream (String name, int type, Object custom)
      throws IOException
   {
      throw new NoSubordinateAccessException ();
   }

   public InputStream getInputStream()
      throws IOException
   {
      return (new NInputStream(this));
   }

   public boolean supportsRandomAccess()
   {
      return true;
   }

   public boolean supportsSubordinateRandomAccess ()
   {
      return false;
   }

   public boolean supportsInputStream ()
   {
      return true;
   }

   public boolean supportsOutputStream ()
   {
      return true;
   }

   public boolean supportsSubordinateInputStream ()
   {
      return false;
   }

   public boolean supportsSubordinateOutputStream ()
   {
      return false;
   }

   public void transferStreamToWriteBytes()
      throws IOException
   {
      if (this.streamToWrite == null)
         return;

      InputStream in = null;
      RandomAccess out = null;
      boolean ignoreCloseException = false;

      try
      {
         in = this.streamToWrite;
         out = new RandomAccess(this);
         byte[] buf = new byte[bufferSize];
         int bytesRead;

       //  out.setLength(0); //the code is commented to fix Encana issue // first truncate the stream

         for ( ; ; )
         {
            bytesRead = in.read(buf);

            if (bytesRead != -1)
               out.write(buf, 0, bytesRead);
            else
               break;
         }
      }
      catch (IOException e)
      {
         ignoreCloseException = true;

         throw (e);
      }
      finally
      {
         try
         {
            if (in != null)
               in.close();

            if (out != null)
               out.close();
         }
         catch (IOException subE)
         {
            if (!ignoreCloseException)
               throw (subE);
         }
      }
   }

} /* NetStream */


