Package org.w3c.www.protocol.http.cache

Source Code of org.w3c.www.protocol.http.cache.ActiveStream

// ActiveStream.java
// $Id: ActiveStream.java,v 1.29 2004/11/04 16:28:33 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.www.protocol.http.cache;

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

import org.w3c.util.ThreadCache;

import org.w3c.www.protocol.http.Request;
import org.w3c.www.protocol.http.Reply;

class ActiveInputStream extends InputStream {
    private static final int buflen  = 2048;
    private static final int halflen = (buflen / 2);

    byte buffer[] = new byte[2048];
    int  off      = 0;
    int  len      = 0;

    boolean closed      = false;
    boolean interrupted = false;

    private synchronized void waitForInput()
  throws IOException
    {
  while ( true ) {
      // Interruption of some sort ?
      if ( interrupted )
    throw new IOException("Broken active pipe.");
      int avail = len - off;
      if (closed || (avail > 0))
    return;
      // Wait for something to happen:
      try {
    wait();
      } catch (InterruptedException ex) {
      }
  }
    }

    /**
     * We wait for half buffer size to be available before pushing data.
     * This is to prevent a silly window syndrom problem, where the pusher
     * and the puller would exachnge single bytes of data.
     */

    public synchronized void receive(byte buf[], int boff, int blen)
  throws IOException
    {
  // Push all data:
  while ( boff < blen ) {
      // Has this stream been closed ?
      if ( closed )
    throw new IOException("Write to closed stream.");
      // Push data:
      int space = buffer.length - len;
      if ((space >= (blen-boff)) || (space > halflen)) {
    int push = Math.min(blen-boff, space);
    System.arraycopy(buf, boff, buffer, len, push);
    len  += push;
    boff += push;
    notifyAll();
      } else {
    try {
        wait();
    } catch (InterruptedException ex) {
    }
      }
  }
    }

    public synchronized void close() {
  closed = true;
  notifyAll();
    }

    public synchronized void interrupt() {
  interrupted = true;
  closed      = true;
  notifyAll();
    }

    public synchronized int read()
  throws IOException
    {
  waitForInput();
  // Have we reached end of stream ?
  if (closed && ((len-off) == 0))
      return -1;
  // Read as quickly as possible:
  int b = (buffer[off++] & 0xff);
  if ( off >= len ) {
      off = 0;
      len = 0;
      notifyAll();
  }
  return b;
    }

    public synchronized int read(byte to[], int toff, int tlen)
  throws IOException
    {
  waitForInput();
  // Check for exhausted stream:
  int avail = len-off;
  if (closed && (avail == 0)) {
      return -1;
  }
  // Send the appropriate stuff:
  if (tlen >= avail) {
      int snd = avail;
      System.arraycopy(buffer, off, to, toff, avail);
      off = 0;
      len = 0;
      notifyAll();
      return snd ;
  } else {
      System.arraycopy(buffer, off, to, toff, tlen);
      if ((off += tlen) > halflen) {
    // Shift buffer:
    System.arraycopy(buffer, off, buffer, 0, len-off);
    len -= off;
    off  = 0;
    notifyAll();
      }
      return tlen;
  }
    }

    public synchronized int available() {
  return (closed || interrupted) ? -1 : len-off;
    }

}

/**
* ActiveStream is used to tee a stream to the client, while caching it.
* This class basically mimics the piped streams provided in the java library
* in a more efficient manner (well, sort of).
* <p>If any error occurs while writing data back to the client, then the
* active thread finishes it works, but only streaming data into the sink,
*/

public class ActiveStream implements Runnable {
    private static ThreadCache threadcache = null;

    ActiveInputStream pout       = null;
    boolean           poutClosed = false;
    InputStream       src        = null;
    boolean           srcClosed  = false;
    OutputStream      dst        = null;
    boolean           dstClosed  = false;
    TeeMonitor        monitor    = null;

    public void run() {

  byte    buffer[] = new byte[2048];
  int     chunksz  = 256;
  boolean notified = false;
  int total = 0;
     
  try {
      int count = 0;
      while ((count = src.read(buffer, 0, chunksz)) >= 0) {
    // Try to write to the pipe, if still valid:
    if ( ! poutClosed ) {
        try {
      pout.receive(buffer, 0, count);
        } catch (IOException ex) {
      try { pout.close(); } catch (Exception e) {}
      poutClosed = true;
        }
    }
    // Always write to destination:
    dst.write(buffer, 0, count);
    total += count;
    // Increment the chunk size, for improved performance:
    chunksz = Math.min(buffer.length, (chunksz*2));
      }
      src.close();
      srcClosed = true;
      dst.close();
      dstClosed = true;
      if ( ! poutClosed ) {
    pout.close();
    poutClosed = true;
      }
      monitor.notifyTeeSuccess(total);
      notified = true;
  } catch (IOException ex) {
      ex.printStackTrace();
      try {
    monitor.notifyTeeFailure(total);
      } catch (Exception nex) {
    // a duplicate notifyTeeFailure
      }
      notified = true;
  } finally {
      if ( ! srcClosed ) {
    try { src.close(); } catch (Exception ex) {}
    srcClosed = true;
      }
      if ( ! dstClosed ) {
    try { dst.close(); } catch (Exception ex) {}
    dstClosed = true;
      }
      if ( ! poutClosed ) {
    try { pout.interrupt(); } catch (Exception ex) {}
    poutClosed = true;
      }
      if ( ! notified )
    monitor.notifyTeeFailure(total);
  }
    }

    public static InputStream createTee(TeeMonitor monitor
          , InputStream src
          , OutputStream dst)
    {
  // Allocate a new tee stream:
  ActiveStream tee = new ActiveStream();
  tee.monitor = monitor;
  tee.pout    = new ActiveInputStream();
  tee.src     = src;
  tee.dst     = dst;
  // Allocate a thread for this tee stream:
  if ( ! threadcache.getThread(tee, false) ) {
      return null;
  } else {
      return tee.pout;
  }
    }

    public static synchronized void initialize() {
  if ( threadcache == null ) {
      threadcache = new ThreadCache("active-streams");
      threadcache.setCachesize(10);
      threadcache.initialize();
  }
    }

    ActiveStream() {
    }
}
TOP

Related Classes of org.w3c.www.protocol.http.cache.ActiveStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.