/**
*
* Copyright 2004 Hiram Chirino
*
* 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.codehaus.activemq.transport.activeio;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.SocketException;
import javax.jms.JMSException;
import org.activeio.AsynchChannel;
import org.activeio.AsynchChannelListener;
import org.activeio.adapter.PacketByteArrayOutputStream;
import org.activeio.adapter.PacketInputStream;
import org.activeio.net.SocketMetadata;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.io.WireFormat;
import org.codehaus.activemq.message.Packet;
import org.codehaus.activemq.transport.TransportChannelSupport;
import org.codehaus.activemq.transport.TransportStatusEvent;
import org.codehaus.activemq.util.JMSExceptionHelper;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
/**
* A tcp implementation of a TransportChannel
*
* @version $Revision: 1.8 $
*/
public class ActiveIOTransportChannel extends TransportChannelSupport implements AsynchChannelListener {
private static final Log log = LogFactory.getLog(ActiveIOTransportChannel.class);
private final Object writeLock = new Object();
private final AsynchChannel asynchChannel;
private final SynchronizedBoolean closed = new SynchronizedBoolean(false);
private final PacketByteArrayOutputStream outputBuffer = new PacketByteArrayOutputStream();
private final DataOutputStream dataOut = new DataOutputStream(outputBuffer);
private final PacketAggregator aggregator = new PacketAggregator() {
protected void packetAssembled(org.activeio.Packet packet) {
try {
Packet p = getWireFormat().readPacket(new DataInputStream(new PacketInputStream(packet)));
if( p!=null ) {
doConsumePacket(p);
}
} catch (IOException e) {
onPacketError(e);
}
}
};
public ActiveIOTransportChannel(WireFormat wireFormat, AsynchChannel asynchChannel) {
super(wireFormat);
this.asynchChannel = asynchChannel;
asynchChannel.setAsynchChannelListener(this);
// Enable TcpNoDelay if possible
SocketMetadata socket = (SocketMetadata) asynchChannel.narrow(SocketMetadata.class);
if(socket!=null) {
try {
socket.setTcpNoDelay(true);
} catch (SocketException e) {
}
}
}
public void start() throws JMSException {
try {
asynchChannel.start();
} catch (IOException e) {
throw JMSExceptionHelper.newJMSException(e.getMessage(),e);
}
}
public void stop() {
if (closed.commit(false, true)) {
super.stop();
asynchChannel.dispose();
}
}
public void forceDisconnect() {
log.debug("Forcing disconnect");
asynchChannel.dispose();
}
public void asyncSend(Packet packet) throws JMSException {
doAsyncSend(packet);
}
protected Packet doAsyncSend(Packet packet) throws JMSException {
Packet response = null;
try {
synchronized (writeLock) {
response = getWireFormat().writePacket(packet, dataOut);
dataOut.flush();
asynchChannel.write( outputBuffer.getPacket() );
asynchChannel.flush();
outputBuffer.reset();
}
}
catch (IOException e) {
if (closed.get()) {
log.trace("Caught exception while closed: " + e, e);
}
else {
throw JMSExceptionHelper.newJMSException("asyncSend failed: " + e, e);
}
}
catch (JMSException e) {
if (closed.get()) {
log.trace("Caught exception while closed: " + e, e);
}
else {
throw e;
}
}
return response;
}
public void onPacket(org.activeio.Packet packet) {
try {
aggregator.addRawPacket(packet);
} catch (IOException e) {
onPacketError(e);
}
}
public void onPacketError(IOException ex) {
if (!closed.get()) {
if (!pendingStop){
setPendingStop(true);
if (ex instanceof EOFException && isServerSide() == false) {
log.warn("Peer closed connection", ex);
}
else {
onAsyncException(JMSExceptionHelper.newJMSException("Error reading socket: " + ex, ex));
}
fireStatusEvent(new TransportStatusEvent(this,TransportStatusEvent.DISCONNECTED));
}
stop();
}
}
public AsynchChannel getAsynchChannel() {
return asynchChannel;
}
/**
* @return the current version of this wire format
*/
public int getCurrentWireFormatVersion() {
return getWireFormat().getCurrentWireFormatVersion();
}
}