Package freenet.client.async

Source Code of freenet.client.async.BinaryBlobWriter$BinaryBlobAlreadyClosedException

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.client.async;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;

import freenet.keys.ClientKeyBlock;
import freenet.keys.Key;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
import freenet.support.io.BucketTools;

/**
* Helper class to write FBlobs. Threadsafe, allows multiple getters to
* write to the same BinaryBlobWriter.
*
* @author saces
*/
public final class BinaryBlobWriter {
   
    private static volatile boolean logMINOR;

    static {
        Logger.registerClass(BinaryBlobWriter.class);
    }
   
  private final HashSet<Key> _binaryBlobKeysAddedAlready;
  private final BucketFactory _bf;
  private final ArrayList<Bucket> _buckets;
  private final Bucket _out;
  private final boolean _isSingleBucket;

  private boolean _started = false;
  private boolean _finalized = false;

  private transient DataOutputStream _stream_cache = null;

  /**
   * Persistent/'BigFile' constructor
   * @param bf BucketFactory to generate internal buckets from
   */
  public BinaryBlobWriter(BucketFactory bf) {
    _binaryBlobKeysAddedAlready = new HashSet<Key>();
    _buckets = new ArrayList<Bucket>();
    _bf = bf;
    _out = null;
    _isSingleBucket = false;
  }

  /**
   * Transient constructor
   * @param out Bucket to write the result to
   */
  public BinaryBlobWriter(Bucket out) {
    _binaryBlobKeysAddedAlready = new HashSet<Key>();
    _buckets = null;
    _bf = null;
    _out = out;
    _isSingleBucket = true;
  }

  private DataOutputStream getOutputStream() throws IOException, BinaryBlobAlreadyClosedException {
    if (_finalized) {
      throw new BinaryBlobAlreadyClosedException("Already finalized (getting final data) on "+this);
    }
    if (_stream_cache==null) {
      if (_isSingleBucket) {
        _stream_cache = new DataOutputStream(_out.getOutputStream());
      } else {
        Bucket newBucket = _bf.makeBucket(-1);
        _buckets.add(newBucket);
        _stream_cache = new DataOutputStream(newBucket.getOutputStream());
      }
    }
    if (!_started) {
      BinaryBlob.writeBinaryBlobHeader(_stream_cache);
      _started = true;
    }
    return _stream_cache;
  }

  /**
   * Add a block to the binary blob.
   * @throws IOException
   * @throws BinaryBlobAlreadyClosedException
   */
  public synchronized void addKey(ClientKeyBlock block, ClientContext context) throws IOException, BinaryBlobAlreadyClosedException {
    Key key = block.getKey();
    if(_binaryBlobKeysAddedAlready.contains(key)) return;
    BinaryBlob.writeKey(getOutputStream(), block.getBlock(), key);
    _binaryBlobKeysAddedAlready.add(key);
  }

  /**
   * finalize the return bucket
   * @return
   * @throws IOException
   * @throws BinaryBlobAlreadyClosedException
   */
  public void finalizeBucket() throws IOException, BinaryBlobAlreadyClosedException {
    if (_finalized) {
      throw new BinaryBlobAlreadyClosedException("Already finalized (closing blob).");
    }
    finalizeBucket(true);
  }

  private void finalizeBucket(boolean mark) throws IOException, BinaryBlobAlreadyClosedException {
    if (_finalized) throw new BinaryBlobAlreadyClosedException("Already finalized (closing blob - 2).");
    if(logMINOR) Logger.minor(this, "Finalizing binary blob "+this, new Exception("debug"));
    if (!_isSingleBucket) {
      if (!mark && (_buckets.size()==1)) {
        return;
      }
      Bucket out = _bf.makeBucket(-1);
      getSnapshot(out, mark);
      for (int i=0,n=_buckets.size(); i<n;i++) {
        _buckets.get(i).free();
      }
      if (mark) {
        out.setReadOnly();
      }
      _buckets.clear();
      _buckets.add(0, out);
    } else if (mark){
      DataOutputStream out = new DataOutputStream(getOutputStream());
      try {
      BinaryBlob.writeEndBlob(out);
      } finally {
      out.close();
      }
    }
    if (mark) {
      _finalized = true;
    }
  }

  public synchronized void getSnapshot(Bucket bucket) throws IOException, BinaryBlobAlreadyClosedException {
    if (_buckets.isEmpty()) return;
    if (_finalized) {
      BucketTools.copy(_buckets.get(0), bucket);
      return;
    }
    getSnapshot(bucket, true);
  }

  private void getSnapshot(Bucket bucket, boolean addEndmarker) throws IOException, BinaryBlobAlreadyClosedException {
    if (_buckets.isEmpty()) return;
    if (_finalized) {
      throw new BinaryBlobAlreadyClosedException("Already closed (getting final data snapshot)");
    }
    OutputStream out = bucket.getOutputStream();
    try {
    for (int i=0,n=_buckets.size(); i<n;i++) {
      BucketTools.copyTo(_buckets.get(i), out, -1);
    }
    if (addEndmarker) {
      DataOutputStream dout = new DataOutputStream(out);
      BinaryBlob.writeEndBlob(dout);
      dout.flush();
    }
    } finally {
      out.close();
    }
  }

  public synchronized Bucket getFinalBucket() {
    if (!_finalized) {
      throw new IllegalStateException("Not finalized!");
    }
    if (_isSingleBucket) {
      return _out;
    } else {
      return _buckets.get(0);
    }
  }

  public static class BinaryBlobAlreadyClosedException extends Exception {

    private static final long serialVersionUID = -1L;

    public BinaryBlobAlreadyClosedException(String message) {
      super(message);
    }
   
  }

  public boolean isFinalized() {
    return _finalized;
  }
}
TOP

Related Classes of freenet.client.async.BinaryBlobWriter$BinaryBlobAlreadyClosedException

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.