Resolved issue: NETTY-90 (Add life cycle listener methods to ChannelHandler)
This commit is contained in:
parent
e8b1a2862e
commit
49a0b8dbdb
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -106,9 +106,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext oldHead = head;
|
DefaultChannelHandlerContext oldHead = head;
|
||||||
DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler);
|
DefaultChannelHandlerContext newHead = new DefaultChannelHandlerContext(null, oldHead, name, handler);
|
||||||
|
|
||||||
|
callBeforeAdd(newHead);
|
||||||
|
|
||||||
oldHead.prev = newHead;
|
oldHead.prev = newHead;
|
||||||
head = newHead;
|
head = newHead;
|
||||||
name2ctx.put(name, newHead);
|
name2ctx.put(name, newHead);
|
||||||
|
|
||||||
|
callAfterAdd(newHead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +124,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext oldTail = tail;
|
DefaultChannelHandlerContext oldTail = tail;
|
||||||
DefaultChannelHandlerContext newTail = new DefaultChannelHandlerContext(oldTail, null, name, handler);
|
DefaultChannelHandlerContext newTail = new DefaultChannelHandlerContext(oldTail, null, name, handler);
|
||||||
|
|
||||||
|
callBeforeAdd(newTail);
|
||||||
|
|
||||||
oldTail.next = newTail;
|
oldTail.next = newTail;
|
||||||
tail = newTail;
|
tail = newTail;
|
||||||
name2ctx.put(name, newTail);
|
name2ctx.put(name, newTail);
|
||||||
|
|
||||||
|
callAfterAdd(newTail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +142,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
} else {
|
} else {
|
||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx.prev, ctx, name, handler);
|
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx.prev, ctx, name, handler);
|
||||||
|
|
||||||
|
callBeforeAdd(newCtx);
|
||||||
|
|
||||||
ctx.prev.next = newCtx;
|
ctx.prev.next = newCtx;
|
||||||
ctx.prev = newCtx;
|
ctx.prev = newCtx;
|
||||||
name2ctx.put(name, newCtx);
|
name2ctx.put(name, newCtx);
|
||||||
|
|
||||||
|
callAfterAdd(newCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,9 +160,14 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
} else {
|
} else {
|
||||||
checkDuplicateName(name);
|
checkDuplicateName(name);
|
||||||
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx, ctx.next, name, handler);
|
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(ctx, ctx.next, name, handler);
|
||||||
|
|
||||||
|
callBeforeAdd(newCtx);
|
||||||
|
|
||||||
ctx.next.prev = newCtx;
|
ctx.next.prev = newCtx;
|
||||||
ctx.next = newCtx;
|
ctx.next = newCtx;
|
||||||
name2ctx.put(name, newCtx);
|
name2ctx.put(name, newCtx);
|
||||||
|
|
||||||
|
callAfterAdd(newCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,11 +193,15 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
} else if (ctx == tail) {
|
} else if (ctx == tail) {
|
||||||
removeLast();
|
removeLast();
|
||||||
} else {
|
} else {
|
||||||
|
callBeforeRemove(ctx);
|
||||||
|
|
||||||
DefaultChannelHandlerContext prev = ctx.prev;
|
DefaultChannelHandlerContext prev = ctx.prev;
|
||||||
DefaultChannelHandlerContext next = ctx.next;
|
DefaultChannelHandlerContext next = ctx.next;
|
||||||
prev.next = next;
|
prev.next = next;
|
||||||
next.prev = prev;
|
next.prev = prev;
|
||||||
name2ctx.remove(ctx.getName());
|
name2ctx.remove(ctx.getName());
|
||||||
|
|
||||||
|
callAfterRemove(ctx);
|
||||||
}
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@ -191,6 +215,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
if (oldHead == null) {
|
if (oldHead == null) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callBeforeRemove(oldHead);
|
||||||
|
|
||||||
if (oldHead.next == null) {
|
if (oldHead.next == null) {
|
||||||
head = tail = null;
|
head = tail = null;
|
||||||
name2ctx.clear();
|
name2ctx.clear();
|
||||||
@ -199,6 +226,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
head = oldHead.next;
|
head = oldHead.next;
|
||||||
name2ctx.remove(oldHead.getName());
|
name2ctx.remove(oldHead.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callAfterRemove(oldHead);
|
||||||
|
|
||||||
return oldHead.getHandler();
|
return oldHead.getHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,6 +241,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
if (oldTail == null) {
|
if (oldTail == null) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callBeforeRemove(oldTail);
|
||||||
|
|
||||||
if (oldTail.prev == null) {
|
if (oldTail.prev == null) {
|
||||||
head = tail = null;
|
head = tail = null;
|
||||||
name2ctx.clear();
|
name2ctx.clear();
|
||||||
@ -219,6 +252,9 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
tail = oldTail.prev;
|
tail = oldTail.prev;
|
||||||
name2ctx.remove(oldTail.getName());
|
name2ctx.remove(oldTail.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callBeforeRemove(oldTail);
|
||||||
|
|
||||||
return oldTail.getHandler();
|
return oldTail.getHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,19 +284,139 @@ public class DefaultChannelPipeline implements ChannelPipeline {
|
|||||||
if (!sameName) {
|
if (!sameName) {
|
||||||
checkDuplicateName(newName);
|
checkDuplicateName(newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultChannelHandlerContext prev = ctx.prev;
|
DefaultChannelHandlerContext prev = ctx.prev;
|
||||||
DefaultChannelHandlerContext next = ctx.next;
|
DefaultChannelHandlerContext next = ctx.next;
|
||||||
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(prev, next, newName, newHandler);
|
DefaultChannelHandlerContext newCtx = new DefaultChannelHandlerContext(prev, next, newName, newHandler);
|
||||||
|
|
||||||
|
callBeforeRemove(ctx);
|
||||||
|
callBeforeAdd(newCtx);
|
||||||
|
|
||||||
prev.next = newCtx;
|
prev.next = newCtx;
|
||||||
next.prev = newCtx;
|
next.prev = newCtx;
|
||||||
|
|
||||||
if (!sameName) {
|
if (!sameName) {
|
||||||
name2ctx.remove(ctx.getName());
|
name2ctx.remove(ctx.getName());
|
||||||
name2ctx.put(newName, newCtx);
|
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();
|
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() {
|
public synchronized ChannelHandler getFirst() {
|
||||||
DefaultChannelHandlerContext head = this.head;
|
DefaultChannelHandlerContext head = this.head;
|
||||||
if (head == null) {
|
if (head == null) {
|
||||||
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user