/**
*
*/
package vnet.sms.gateway.nettysupport;
import java.io.Serializable;
import java.net.SocketAddress;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelDownstreamHandler;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChannelUpstreamHandler;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.WriteCompletionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vnet.sms.common.messages.GsmPdu;
import vnet.sms.common.wme.acknowledge.SendLoginRequestAckEvent;
import vnet.sms.common.wme.acknowledge.SendLoginRequestNackEvent;
import vnet.sms.common.wme.acknowledge.SendSmsAckContainer;
import vnet.sms.common.wme.acknowledge.SendSmsAckEvent;
import vnet.sms.common.wme.acknowledge.SendSmsNackContainer;
import vnet.sms.common.wme.acknowledge.SendSmsNackEvent;
import vnet.sms.common.wme.receive.ReceivedLoginRequestAcknowledgementEvent;
import vnet.sms.common.wme.receive.ReceivedLoginRequestEvent;
import vnet.sms.common.wme.receive.ReceivedPingRequestAcknowledgementEvent;
import vnet.sms.common.wme.receive.ReceivedPingRequestEvent;
import vnet.sms.common.wme.receive.ReceivedSmsEvent;
import vnet.sms.common.wme.send.SendPingRequestEvent;
import vnet.sms.common.wme.send.SendSmsContainer;
import vnet.sms.common.wme.send.SendSmsEvent;
import vnet.sms.gateway.nettysupport.login.incoming.ChannelAuthenticationFailedEvent;
import vnet.sms.gateway.nettysupport.login.incoming.ChannelSuccessfullyAuthenticatedEvent;
import vnet.sms.gateway.nettysupport.login.incoming.NonLoginMessageReceivedOnUnauthenticatedChannelEvent;
import vnet.sms.gateway.nettysupport.ping.outgoing.PingResponseTimeoutExpiredEvent;
import vnet.sms.gateway.nettysupport.ping.outgoing.StartedToPingEvent;
import vnet.sms.gateway.nettysupport.window.FailedToReleaseAcknowledgedMessageEvent;
import vnet.sms.gateway.nettysupport.window.NoWindowForIncomingMessageAvailableEvent;
import vnet.sms.gateway.nettysupport.window.PendingWindowedMessagesDiscardedEvent;
/**
* @author obergner
*
*/
public class WindowedChannelHandler<ID extends Serializable> implements
ChannelUpstreamHandler, ChannelDownstreamHandler {
private final Logger log = LoggerFactory.getLogger(getClass());
// ------------------------------------------------------------------------
// Upstream
// ------------------------------------------------------------------------
/**
* {@inheritDoc} Down-casts the received upstream event into more meaningful
* sub-type event and calls an appropriate handler method with the
* down-casted event.
*/
@Override
public final void handleUpstream(final ChannelHandlerContext ctx,
final ChannelEvent e) throws Exception {
getLog().debug("Processing {} ...", e);
if (e instanceof ReceivedLoginRequestEvent) {
loginRequestReceived(ctx, (ReceivedLoginRequestEvent<ID>) e);
} else if (e instanceof ReceivedLoginRequestAcknowledgementEvent) {
loginResponseReceived(ctx,
(ReceivedLoginRequestAcknowledgementEvent<ID>) e);
} else if (e instanceof ReceivedPingRequestEvent) {
pingRequestReceived(ctx, (ReceivedPingRequestEvent<ID>) e);
} else if (e instanceof ReceivedPingRequestAcknowledgementEvent) {
pingResponseReceived(ctx,
(ReceivedPingRequestAcknowledgementEvent<ID>) e);
} else if (e instanceof ReceivedSmsEvent) {
smsReceived(ctx, (ReceivedSmsEvent<ID>) e);
} else if (e instanceof ChannelAuthenticationFailedEvent) {
channelAuthenticationFailed(ctx,
(ChannelAuthenticationFailedEvent) e);
} else if (e instanceof ChannelSuccessfullyAuthenticatedEvent) {
channelSuccessfullyAuthenticated(ctx,
(ChannelSuccessfullyAuthenticatedEvent) e);
} else if (e instanceof StartedToPingEvent) {
startedToPing(ctx, (StartedToPingEvent) e);
} else if (e instanceof PingResponseTimeoutExpiredEvent) {
pingResponseTimeoutExpired(ctx, (PingResponseTimeoutExpiredEvent) e);
} else if (e instanceof NoWindowForIncomingMessageAvailableEvent) {
noWindowForIncomingMessageAvailable(ctx,
(NoWindowForIncomingMessageAvailableEvent) e);
} else if (e instanceof PendingWindowedMessagesDiscardedEvent) {
pendingWindowedMessagesDiscarded(ctx,
(PendingWindowedMessagesDiscardedEvent<ID>) e);
} else if (e instanceof FailedToReleaseAcknowledgedMessageEvent) {
failedToReleaseAcknowledgedMessage(
ctx,
(FailedToReleaseAcknowledgedMessageEvent<ID, ? extends GsmPdu>) e);
} else if (e instanceof WriteCompletionEvent) {
final WriteCompletionEvent evt = (WriteCompletionEvent) e;
writeComplete(ctx, evt);
} else if (e instanceof ChildChannelStateEvent) {
final ChildChannelStateEvent evt = (ChildChannelStateEvent) e;
if (evt.getChildChannel().isOpen()) {
childChannelOpen(ctx, evt);
} else {
childChannelClosed(ctx, evt);
}
} else if (e instanceof ChannelStateEvent) {
final ChannelStateEvent evt = (ChannelStateEvent) e;
switch (evt.getState()) {
case OPEN:
if (Boolean.TRUE.equals(evt.getValue())) {
channelOpen(ctx, evt);
} else {
channelClosed(ctx, evt);
}
break;
case BOUND:
if (evt.getValue() != null) {
channelBound(ctx, evt);
} else {
channelUnbound(ctx, evt);
}
break;
case CONNECTED:
if (evt.getValue() != null) {
channelConnected(ctx, evt);
} else {
channelDisconnected(ctx, evt);
}
break;
case INTEREST_OPS:
channelInterestChanged(ctx, evt);
break;
default:
ctx.sendUpstream(e);
}
} else if (e instanceof ExceptionEvent) {
exceptionCaught(ctx, (ExceptionEvent) e);
} else {
throw new IllegalStateException("Unsupported ChannelEvent [" + e
+ "] of type [" + e.getClass().getName()
+ "] - please add a handler method in "
+ WindowedChannelHandler.class.getName());
}
getLog().debug("Finished processing {}", e);
}
/**
* @param ctx
* @param e
*/
protected void loginRequestReceived(final ChannelHandlerContext ctx,
final ReceivedLoginRequestEvent<ID> e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
*/
protected void loginResponseReceived(final ChannelHandlerContext ctx,
final ReceivedLoginRequestAcknowledgementEvent<ID> e)
throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
*/
protected void pingRequestReceived(final ChannelHandlerContext ctx,
final ReceivedPingRequestEvent<ID> e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
*/
protected void pingResponseReceived(final ChannelHandlerContext ctx,
final ReceivedPingRequestAcknowledgementEvent<ID> e)
throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
*/
protected void smsReceived(final ChannelHandlerContext ctx,
final ReceivedSmsEvent<ID> e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void channelAuthenticationFailed(final ChannelHandlerContext ctx,
final ChannelAuthenticationFailedEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void channelSuccessfullyAuthenticated(
final ChannelHandlerContext ctx,
final ChannelSuccessfullyAuthenticatedEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void startedToPing(final ChannelHandlerContext ctx,
final StartedToPingEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void pingResponseTimeoutExpired(final ChannelHandlerContext ctx,
final PingResponseTimeoutExpiredEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void noWindowForIncomingMessageAvailable(
final ChannelHandlerContext ctx,
final NoWindowForIncomingMessageAvailableEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void pendingWindowedMessagesDiscarded(
final ChannelHandlerContext ctx,
final PendingWindowedMessagesDiscardedEvent<ID> e) throws Exception {
ctx.sendUpstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void failedToReleaseAcknowledgedMessage(
final ChannelHandlerContext ctx,
final FailedToReleaseAcknowledgedMessageEvent<ID, ? extends GsmPdu> e)
throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} is open, but not bound nor connected. <br/>
*
* <strong>Be aware that this event is fired from within the Boss-Thread so
* you should not execute any heavy operation in there as it will block the
* dispatching to other workers!</strong>
*/
protected void channelOpen(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} is open and bound to a local address, but
* not connected. <br/>
*
* <strong>Be aware that this event is fired from within the Boss-Thread so
* you should not execute any heavy operation in there as it will block the
* dispatching to other workers!</strong>
*/
protected void channelBound(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} is open, bound to a local address, and
* connected to a remote address. <br/>
*
* <strong>Be aware that this event is fired from within the Boss-Thread so
* you should not execute any heavy operation in there as it will block the
* dispatching to other workers!</strong>
*/
protected void channelConnected(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel}'s {@link Channel#getInterestOps()
* interestOps} was changed.
*/
protected void channelInterestChanged(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} was disconnected from its remote peer.
*/
protected void channelDisconnected(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} was unbound from the current local
* address.
*/
protected void channelUnbound(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link Channel} was closed and all its related resources
* were released.
*/
protected void channelClosed(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when something was written into a {@link Channel}.
*/
protected void writeComplete(final ChannelHandlerContext ctx,
final WriteCompletionEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a child {@link Channel} was open. (e.g. a server channel
* accepted a connection)
*/
protected void childChannelOpen(final ChannelHandlerContext ctx,
final ChildChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when a child {@link Channel} was closed. (e.g. the accepted
* connection was closed)
*/
protected void childChannelClosed(final ChannelHandlerContext ctx,
final ChildChannelStateEvent e) throws Exception {
ctx.sendUpstream(e);
}
/**
* Invoked when an exception was raised by an I/O thread or a
* {@link ChannelHandler}.
*/
protected void exceptionCaught(final ChannelHandlerContext ctx,
final ExceptionEvent e) throws Exception {
if (this == ctx.getPipeline().getLast()) {
getLog().warn(
"EXCEPTION, please implement " + getClass().getName()
+ ".exceptionCaught() for proper handling.",
e.getCause());
}
ctx.sendUpstream(e);
}
// ------------------------------------------------------------------------
// Downstream
// ------------------------------------------------------------------------
/**
* {@inheritDoc} Down-casts the received downstream event into more
* meaningful sub-type event and calls an appropriate handler method with
* the down-casted event.
*/
@Override
public final void handleDownstream(final ChannelHandlerContext ctx,
final ChannelEvent e) throws Exception {
getLog().debug("Processing {} ...", e);
if (e instanceof SendPingRequestEvent) {
writePingRequestRequested(ctx, (SendPingRequestEvent<ID>) e);
} else if (e instanceof SendLoginRequestAckEvent) {
writeLoginRequestAcceptedRequested(ctx,
(SendLoginRequestAckEvent<ID>) e);
} else if (e instanceof SendLoginRequestNackEvent) {
writeLoginRequestRejectedRequested(ctx,
(SendLoginRequestNackEvent<ID>) e);
} else if (e instanceof NonLoginMessageReceivedOnUnauthenticatedChannelEvent) {
writeNonLoginMessageReceivedOnUnauthenticatedChannelRequested(
ctx,
(NonLoginMessageReceivedOnUnauthenticatedChannelEvent<ID, ?>) e);
} else if (e instanceof SendPingRequestEvent) {
writePingRequestRequested(ctx, (SendPingRequestEvent<ID>) e);
} else if ((e instanceof MessageEvent)
&& (MessageEvent.class.cast(e).getMessage() instanceof SendSmsContainer)) {
final SendSmsEvent sendSmsEvent = SendSmsEvent
.convert(MessageEvent.class.cast(e));
ctx.sendDownstream(sendSmsEvent);
} else if (e instanceof SendSmsEvent) {
writeSmsRequested(ctx, (SendSmsEvent) e);
} else if ((e instanceof MessageEvent)
&& (MessageEvent.class.cast(e).getMessage() instanceof SendSmsAckContainer)) {
final SendSmsAckEvent<ID> receivedSmsAckedEvent = SendSmsAckEvent
.convert(MessageEvent.class.cast(e));
ctx.sendDownstream(receivedSmsAckedEvent);
} else if (e instanceof SendSmsAckEvent) {
writeReceivedSmsAckedRequested(ctx, (SendSmsAckEvent) e);
} else if ((e instanceof MessageEvent)
&& (MessageEvent.class.cast(e).getMessage() instanceof SendSmsNackContainer)) {
final SendSmsNackEvent<ID> receivedSmsNackedEvent = SendSmsNackEvent
.convert(MessageEvent.class.cast(e));
ctx.sendDownstream(receivedSmsNackedEvent);
} else if (e instanceof SendSmsNackEvent) {
writeReceivedSmsNackedRequested(ctx, (SendSmsNackEvent) e);
} else if (e instanceof ChannelStateEvent) {
final ChannelStateEvent evt = (ChannelStateEvent) e;
switch (evt.getState()) {
case OPEN:
if (!Boolean.TRUE.equals(evt.getValue())) {
closeRequested(ctx, evt);
}
break;
case BOUND:
if (evt.getValue() != null) {
bindRequested(ctx, evt);
} else {
unbindRequested(ctx, evt);
}
break;
case CONNECTED:
if (evt.getValue() != null) {
connectRequested(ctx, evt);
} else {
disconnectRequested(ctx, evt);
}
break;
case INTEREST_OPS:
setInterestOpsRequested(ctx, evt);
break;
default:
ctx.sendDownstream(e);
}
} else {
throw new IllegalStateException("Unsupported ChannelEvent [" + e
+ "] of type [" + e.getClass().getName()
+ "] - please add a handler method in "
+ WindowedChannelHandler.class.getName());
}
getLog().debug("Finished processing {}", e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writePingRequestRequested(final ChannelHandlerContext ctx,
final SendPingRequestEvent<ID> e) throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeLoginRequestAcceptedRequested(
final ChannelHandlerContext ctx,
final SendLoginRequestAckEvent<ID> e) throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeLoginRequestRejectedRequested(
final ChannelHandlerContext ctx,
final SendLoginRequestNackEvent<ID> e) throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeNonLoginMessageReceivedOnUnauthenticatedChannelRequested(
final ChannelHandlerContext ctx,
final NonLoginMessageReceivedOnUnauthenticatedChannelEvent<ID, ?> e)
throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeSmsRequested(final ChannelHandlerContext ctx,
final SendSmsEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeReceivedSmsAckedRequested(
final ChannelHandlerContext ctx, final SendSmsAckEvent<ID> e)
throws Exception {
ctx.sendDownstream(e);
}
/**
* @param ctx
* @param e
* @throws Exception
*/
protected void writeReceivedSmsNackedRequested(
final ChannelHandlerContext ctx, final SendSmsNackEvent<ID> e)
throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#bind(SocketAddress)} was called.
*/
public void bindRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#connect(SocketAddress)} was called.
*/
public void connectRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#setInterestOps(int)} was called.
*/
public void setInterestOpsRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#disconnect()} was called.
*/
public void disconnectRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#unbind()} was called.
*/
public void unbindRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
/**
* Invoked when {@link Channel#close()} was called.
*/
public void closeRequested(final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
ctx.sendDownstream(e);
}
protected Logger getLog() {
return this.log;
}
}