/** * Copyright (c) 2009 - 2011 AppWork UG(haftungsbeschränkt) <e-mail@appwork.org> * * This file is part of org.appwork.utils.net * * This software is licensed under the Artistic License 2.0, * see the LICENSE file or http://www.opensource.org/licenses/artistic-license-2.0.php * for details */ package org.appwork.utils.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @author daniel * */ public class Input2OutputStreamForwarder { private final InputStream in; private final OutputStream out; final byte[] buffer; long inC = 0; long outC = 0; int readP = 0; int writeF = 0; int readF = 0; int writeP = 0; int readS = 0; int writeS = 0; final Object LOCK = new Object(); protected Thread thread = null; private IOException outE = null; private volatile boolean eof = false; private volatile boolean readDone = false; public Input2OutputStreamForwarder(final InputStream in, final OutputStream out) { this.in = in; this.out = out; this.buffer = new byte[1 * 1024 * 1024]; this.createstartThread(); } public Input2OutputStreamForwarder(final InputStream in, final OutputStream out, final byte[] buffer) { this.in = in; this.out = out; if (buffer == null || buffer.length < 1024) { throw new IllegalArgumentException("invalid buffer"); } this.buffer = buffer; this.createstartThread(); } public Input2OutputStreamForwarder(final InputStream in, final OutputStream out, final int size) { this.in = in; this.out = out; if (size < 1024) { throw new IllegalArgumentException("invalid buffer size"); } this.buffer = new byte[size]; this.createstartThread(); } private void createstartThread() { this.thread = new Thread(new Runnable() { public void run() { try { while (!Input2OutputStreamForwarder.this.thread.isInterrupted()) { synchronized (Input2OutputStreamForwarder.this.LOCK) { if (Input2OutputStreamForwarder.this.writeF > Input2OutputStreamForwarder.this.readF) { Input2OutputStreamForwarder.this.readP = 0; Input2OutputStreamForwarder.this.readF = Input2OutputStreamForwarder.this.writeF; // System.out.println("writer flip"); } if (Input2OutputStreamForwarder.this.readP < Input2OutputStreamForwarder.this.writeP) { /* * write pointer > read pointer, there must be * data to get written */ Input2OutputStreamForwarder.this.readS = Input2OutputStreamForwarder.this.writeP - Input2OutputStreamForwarder.this.readP; // System.out.println("writer normal"); } else if (Input2OutputStreamForwarder.this.writeP < Input2OutputStreamForwarder.this.readP) { /* write pointer < read pointer */ Input2OutputStreamForwarder.this.readS = Input2OutputStreamForwarder.this.buffer.length - Input2OutputStreamForwarder.this.readP; // System.out.println("writer RestBuffer"); } else { /* read pointer=write pointer, no data available */ if (Input2OutputStreamForwarder.this.eof || Input2OutputStreamForwarder.this.readDone) { // System.out.println("writer normal end"); break; } // System.out.println("writer wait"); try { Input2OutputStreamForwarder.this.LOCK.wait(100); continue; } catch (final InterruptedException e) { break; } } } // System.out.println("Writer: " + // SizeFormatter.formatBytes(Input2OutputStreamForwarder.this.readS)); Input2OutputStreamForwarder.this.out.write(Input2OutputStreamForwarder.this.buffer, Input2OutputStreamForwarder.this.readP, Input2OutputStreamForwarder.this.readS); Input2OutputStreamForwarder.this.outC = Input2OutputStreamForwarder.this.outC + Input2OutputStreamForwarder.this.readS; System.out.println(thread.getName()+" : "+outC+" bytes"); synchronized (Input2OutputStreamForwarder.this.LOCK) { Input2OutputStreamForwarder.this.readP = Input2OutputStreamForwarder.this.readP + Input2OutputStreamForwarder.this.readS; Input2OutputStreamForwarder.this.LOCK.notifyAll(); } } } catch (final IOException e) { Input2OutputStreamForwarder.this.outE = e; } finally { synchronized (Input2OutputStreamForwarder.this.LOCK) { Input2OutputStreamForwarder.this.LOCK.notifyAll(); } } } },this.in+" >> "+out); } public void forward() throws IOException, InterruptedException { this.forward(null); } public void forward(final Runnable runAfter) throws IOException, InterruptedException { try { this.thread.start(); int read = 0; while (!this.thread.isInterrupted() && this.thread.isAlive()) { /* * TODO: lets fill at the beginning, when writer is still in * progress */ synchronized (this.LOCK) { if (this.readP == this.buffer.length && this.readF == this.writeF) { /* read pointer at the end, set write pointer to start */ this.writeP = 0; this.writeF++; // System.out.println("reader flip"); } if (this.writeP < this.buffer.length) { /* we still have buffer left to use */ this.writeS = this.buffer.length - this.writeP; // System.out.println("read restbuffer"); } else { /* no buffer left, wait for signal */ // System.out.println("read wait"); this.LOCK.notifyAll(); try { if (!this.thread.isAlive() || this.thread.isInterrupted()) { break; } this.LOCK.wait(100); continue; } catch (final InterruptedException e) { break; } } } /* read into buffer */ read = this.in.read(this.buffer, this.writeP, this.writeS); // System.out.println("Reader: " + this.writeP + " " + // this.writeS + " read " + read); if (read == -1) { // System.out.println("reader normal end"); this.eof = true; break; } this.inC = this.inC + read; synchronized (this.LOCK) { /* set new write pointer to next position */ this.writeP = this.writeP + read; } } if (this.outE != null) { throw this.outE; } }catch(IOException e){ throw e; } finally { try { this.readDone = true; synchronized (this.LOCK) { this.LOCK.notifyAll(); } /* wait for thread to finish */ while (this.thread.isAlive()) { synchronized (this.LOCK) { this.LOCK.wait(100); } } } finally { if (runAfter != null) { runAfter.run(); } } } } public long getInC() { return this.inC; } public long getOutC() { return this.outC; } }