/**
*
* 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.codehaus.activemq.transport.ember;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.message.Packet;
import org.codehaus.activemq.message.WireFormat;
import org.codehaus.activemq.transport.TransportChannelSupport;
import pyrasun.eio.EIOGlobalContext;
import pyrasun.eio.services.EmberServiceController;
import pyrasun.eio.services.EmberServiceException;
import pyrasun.eio.services.bytearray.ByteArrayServerClient;
import pyrasun.eio.services.bytearray.ByteArrayServerClientListener;
import javax.jms.JMSException;
import java.io.IOException;
/**
* An EmberIO (using NIO) implementation of a TransportChannel
*
* @version $Revision: 1.15 $
*/
public class EmberTransportChannel extends TransportChannelSupport implements ByteArrayServerClientListener {
private static final Log log = LogFactory.getLog(EmberTransportChannel.class);
private WireFormat wireFormat;
private EIOGlobalContext context;
private EmberServiceController controller;
private ByteArrayServerClient client;
private SynchronizedBoolean closed;
private SynchronizedBoolean started;
/**
* Construct basic helpers
*/
protected EmberTransportChannel(WireFormat wireFormat) {
this.wireFormat = wireFormat;
closed = new SynchronizedBoolean(false);
started = new SynchronizedBoolean(false);
}
/**
* Connect to a remote Node - e.g. a Broker
*/
public EmberTransportChannel(WireFormat wireFormat, EIOGlobalContext context, EmberServiceController controller, ByteArrayServerClient client) {
this(wireFormat);
this.context = context;
this.client = client;
this.controller = controller;
client.setListener(this);
}
/**
* close the channel
*/
public void stop() {
super.stop();
if (closed.commit(false, true)) {
try {
// on the server side don't shut down the controller, the server does that
if (controller != null) {
controller.stopAll();
}
if (context != null) {
context.stop();
}
}
catch (EmberServiceException e) {
log.error("Caught while closing: " + e, e);
}
}
}
/**
* start listeneing for events
*
* @throws JMSException if an error occurs
*/
public void start() throws JMSException {
if (started.commit(false, true)) {
try {
// when using a transport channel created from a server
// we don't need to initialise these things
if (context != null) {
context.start();
}
if (controller != null) {
controller.startAll();
}
}
catch (EmberServiceException e) {
JMSException jmsEx = new JMSException("Error starting NIO client: " + e.getMessage());
jmsEx.setLinkedException(e);
throw jmsEx;
}
}
}
/**
* Asynchronously send a Packet
*
* @param packet
* @throws JMSException
*/
public void asyncSend(Packet packet) throws JMSException {
try {
byte[] bytes = wireFormat.toBytes(packet);
// lets sync for now to avoid multiple threads writing to the same socket
synchronized (client) {
client.write(bytes);
}
}
catch (IOException e) {
throw createJMSException("Failed to write packet: " + packet + ". ", e);
}
}
public boolean isMulticast() {
return false;
}
/**
* Factory method to create a JMSException which is linked to the base exception
*/
protected JMSException createJMSException(String message, Exception ex) {
JMSException jmsEx = new JMSException(message + ex.getMessage());
jmsEx.setLinkedException(ex);
return jmsEx;
}
/**
* pretty print for object
*
* @return String representation of this object
*/
public String toString() {
return "EmberTransportChannel: " + client;
}
public void newMessage(ByteArrayServerClient client, Object msg) {
byte[] bytes = (byte[]) msg;
Packet packet = null;
try {
packet = wireFormat.fromBytes(bytes);
doConsumePacket(packet);
}
catch (IOException e) {
log.error("Could not parse byte[] of size: " + bytes.length + ". Reason: " + e, e);
}
}
/**
* Can this wireformat process packets of this version
* @param version the version number to test
* @return true if can accept the version
*/
public boolean canProcessWireFormatVersion(int version){
return wireFormat.canProcessWireFormatVersion(version);
}
/**
* @return the current version of this wire format
*/
public int getCurrentWireFormatVersion(){
return wireFormat.getCurrentWireFormatVersion();
}
}