/**
*
* Copyright 2004 Protique Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.activemq.streams;
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import org.activemq.message.ActiveMQBytesMessage;
/**
* OutputStream that writes on to JMS via the supplied JMS MessageProducer
*
* @version $Revision: 1.1.1.1 $
*/
public class JMSOutputStream extends OutputStream {
private final static int BUFFER_SIZE = 16 * 1024;
private byte[] buf;
private int count;
private boolean closed;
private MessageProducer producer;
/**
* Creates a new output stream to write data using the supplied JMS MessageProducer
* @param producer
*/
public JMSOutputStream(MessageProducer producer) {
this(producer,BUFFER_SIZE);
}
/**
* Creates a new output stream to write data using the supplied JMS MessageProducer
* @param producer
* @param size the buffer size.
* @throws IllegalArgumentException if size <= 0.
*/
public JMSOutputStream(MessageProducer producer, int size) {
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
this.producer = producer;
}
/**
* write a byte on to the stream
*
* @param b - byte to write
* @throws IOException
*/
public void write(int b) throws IOException {
checkClosed();
if (availableBufferToWrite() < 1) {
flush();
}
buf[count++] = (byte) b;
}
/**
* write a byte array to the stream
*
* @param b the byte buffer
* @param off the offset into the buffer
* @param len the length of data to write
* @throws IOException
*/
public void write(byte b[], int off, int len) throws IOException {
checkClosed();
if (availableBufferToWrite() < len) {
flush();
}
if (buf.length >= len) {
System.arraycopy(b, off, buf, count, len);
count += len;
}
else {
writeBuffer(b, off, len);
}
}
/**
* flush the data to the output stream
* This doesn't call flush on the underlying outputstream, because
* Tcp is particularly efficent at doing this itself ....
*
* @throws IOException
*/
public void flush() throws IOException {
checkClosed();
if (count > 0 ) {
writeBuffer(buf, 0, count);
count = 0;
}
}
/**
* close this stream
*
* @throws IOException
*/
public void close() throws IOException {
if (!closed) {
write(-1);
flush();
super.close();
closed = true;
try {
producer.close();
}
catch (JMSException jmsEx) {
IOException ioEx = new IOException(jmsEx.getMessage());
throw ioEx;
}
}
}
/**
* Checks that the stream has not been closed
*
* @throws IOException
*/
protected void checkClosed() throws IOException {
if (closed) {
throw new EOFException("Cannot write to the stream any more it has already been closed");
}
}
/**
* @return the amount free space in the buffer
*/
private int availableBufferToWrite() {
return buf.length - count;
}
private void writeBuffer(byte[] buf,int offset, int length) throws IOException{
try {
BytesMessage message = new ActiveMQBytesMessage();
message.writeBytes(buf,offset,length);
producer.send(message);
}catch(JMSException jmsEx){
IOException ioEx = new IOException(jmsEx.getMessage());
throw ioEx;
}
}
}