Resolved issue: NETTY-90 (Add life cycle listener methods to ChannelHandler)

This commit is contained in:
Trustin Lee 2008-12-01 10:07:54 +00:00
parent e8b1a2862e
commit 49a0b8dbdb
3 changed files with 261 additions and 0 deletions

View File

@ -0,0 +1,67 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.channel;
/**
* A {@link RuntimeException} which is thrown when a {@link LifeCycleAwareChannelHandler}
* throws an {@link Exception} in its handler methods.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
* @apiviz.hidden
*/
public class ChannelHandlerLifeCycleException extends RuntimeException {
private static final long serialVersionUID = 8764799996088850672L;
/**
* Creates a new exception.
*/
public ChannelHandlerLifeCycleException() {
super();
}
/**
* Creates a new exception.
*/
public ChannelHandlerLifeCycleException(String message, Throwable cause) {
super(message, cause);
}
/**
* Creates a new exception.
*/
public ChannelHandlerLifeCycleException(String message) {
super(message);
}
/**
* Creates a new exception.
*/
public ChannelHandlerLifeCycleException(Throwable cause) {
super(cause);
}
}

View File

@ -106,9 +106,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
checkDuplicateName(name);
DefaultChannelHandlerContext oldHead = head;
DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler);
callBeforeAdd(newHead);
oldHead.prev = newHead;
head = newHead;
name2ctx.put(name, newHead);
callAfterAdd(newHead);
}
}
@ -119,9 +124,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
checkDuplicateName(name);
DefaultChannelHandlerContext oldTail = tail;
DefaultChannelHandlerContext newTail = new DefaultChannelHandlerContext(oldTail, null, name, handler);
callBeforeAdd(newTail);
oldTail.next = newTail;
tail = newTail;
name2ctx.put(name, newTail);
callAfterAdd(newTail);
}
}
@ -132,9 +142,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} else {
checkDuplicateName(name);
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx.prev, ctx, name, handler);
callBeforeAdd(newCtx);
ctx.prev.next = newCtx;
ctx.prev = newCtx;
name2ctx.put(name, newCtx);
callAfterAdd(newCtx);
}
}
@ -145,9 +160,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} else {
checkDuplicateName(name);
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx, ctx.next, name, handler);
callBeforeAdd(newCtx);
ctx.next.prev = newCtx;
ctx.next = newCtx;
name2ctx.put(name, newCtx);
callAfterAdd(newCtx);
}
}
@ -173,11 +193,15 @@ public class DefaultChannelPipeline implements ChannelPipeline {
} else if (ctx == tail) {
removeLast();
} else {
callBeforeRemove(ctx);
DefaultChannelHandlerContext prev = ctx.prev;
DefaultChannelHandlerContext next = ctx.next;
prev.next = next;
next.prev = prev;
name2ctx.remove(ctx.getName());
callAfterRemove(ctx);
}
return ctx;
}
@ -191,6 +215,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
if (oldHead == null) {
throw new NoSuchElementException();
}
callBeforeRemove(oldHead);
if (oldHead.next == null) {
head = tail = null;
name2ctx.clear();
@ -199,6 +226,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
head = oldHead.next;
name2ctx.remove(oldHead.getName());
}
callAfterRemove(oldHead);
return oldHead.getHandler();
}
@ -211,6 +241,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
if (oldTail == null) {
throw new NoSuchElementException();
}
callBeforeRemove(oldTail);
if (oldTail.prev == null) {
head = tail = null;
name2ctx.clear();
@ -219,6 +252,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
tail = oldTail.prev;
name2ctx.remove(oldTail.getName());
}
callBeforeRemove(oldTail);
return oldTail.getHandler();
}
@ -248,19 +284,139 @@ public class DefaultChannelPipeline implements ChannelPipeline {
if (!sameName) {
checkDuplicateName(newName);
}
DefaultChannelHandlerContext prev = ctx.prev;
DefaultChannelHandlerContext next = ctx.next;
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(prev, next, newName, newHandler);
callBeforeRemove(ctx);
callBeforeAdd(newCtx);
prev.next = newCtx;
next.prev = newCtx;
if (!sameName) {
name2ctx.remove(ctx.getName());
name2ctx.put(newName, newCtx);
}
ChannelHandlerLifeCycleException removeException = null;
ChannelHandlerLifeCycleException addException = null;
boolean removed = false;
try {
callAfterRemove(ctx);
removed = true;
} catch (ChannelHandlerLifeCycleException e) {
removeException = e;
}
boolean added = false;
try {
callAfterAdd(newCtx);
added = true;
} catch (ChannelHandlerLifeCycleException e) {
addException = e;
}
if (!removed && !added) {
logger.warn(removeException.getMessage(), removeException);
logger.warn(addException.getMessage(), addException);
throw new ChannelHandlerLifeCycleException(
"Both " + ctx.getHandler().getClass().getName() +
".afterRemove() and " + newCtx.getHandler().getClass().getName() +
".afterAdd() failed; see logs.");
} else if (!removed) {
throw removeException;
} else if (!added) {
throw addException;
}
}
return ctx.getHandler();
}
private void callBeforeAdd(ChannelHandlerContext ctx) {
if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) {
return;
}
LifeCycleAwareChannelHandler h =
(LifeCycleAwareChannelHandler) ctx.getHandler();
try {
h.beforeAdd(ctx);
} catch (Throwable t) {
throw new ChannelHandlerLifeCycleException(
h.getName() +
".beforeAdd() has thrown an exception; not adding.", t);
}
}
private void callAfterAdd(ChannelHandlerContext ctx) {
if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) {
return;
}
LifeCycleAwareChannelHandler h =
(LifeCycleAwareChannelHandler) ctx.getHandler();
try {
h.afterAdd(ctx);
} catch (Throwable t) {
boolean removed = false;
try {
remove((DefaultChannelHandlerContext) ctx);
removed = true;
} catch (Throwable t2) {
logger.warn("Failed to remove a handler: " + ctx.getName(), t2);
}
if (removed) {
throw new ChannelHandlerLifeCycleException(
h.getName() +
".afterAdd() has thrown an exception; removed.", t);
} else {
throw new ChannelHandlerLifeCycleException(
h.getName() +
".afterAdd() has thrown an exception; also failed to remove.", t);
}
}
}
private void callBeforeRemove(ChannelHandlerContext ctx) {
if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) {
return;
}
LifeCycleAwareChannelHandler h =
(LifeCycleAwareChannelHandler) ctx.getHandler();
try {
h.beforeRemove(ctx);
} catch (Throwable t) {
throw new ChannelHandlerLifeCycleException(
h.getName() +
".beforeRemove() has thrown an exception; not removing.", t);
}
}
private void callAfterRemove(ChannelHandlerContext ctx) {
if (!(ctx.getHandler() instanceof LifeCycleAwareChannelHandler)) {
return;
}
LifeCycleAwareChannelHandler h =
(LifeCycleAwareChannelHandler) ctx.getHandler();
try {
h.afterRemove(ctx);
} catch (Throwable t) {
throw new ChannelHandlerLifeCycleException(
h.getName() +
".afterRemove() has thrown an exception.", t);
}
}
public synchronized ChannelHandler getFirst() {
DefaultChannelHandlerContext head = this.head;
if (head == null) {

View File

@ -0,0 +1,38 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.channel;
/**
* A {@link ChannelHandler} that is notified when it is added to or removed from
* a {@link ChannelPipeline}.
*
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
* @version $Rev$, $Date$
*/
public interface LifeCycleAwareChannelHandler extends ChannelHandlerContext {
void beforeAdd(ChannelHandlerContext ctx) throws Exception;
void afterAdd(ChannelHandlerContext ctx) throws Exception;
void beforeRemove(ChannelHandlerContext ctx) throws Exception;
void afterRemove(ChannelHandlerContext ctx) throws Exception;
}