All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.netty.channel.ChannelHandler Maven / Gradle / Ivy

Go to download

The Netty project is an effort to provide an asynchronous event-driven network application framework and tools for rapid development of maintainable high performance and high scalability protocol servers and clients. In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

There is a newer version: 4.0.0.Alpha8
Show newest version
/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you 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.jboss.netty.channel;

import org.jboss.netty.bootstrap.Bootstrap;
import org.jboss.netty.channel.group.ChannelGroup;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Handles or intercepts a {@link ChannelEvent}, and sends a
 * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}.
 *
 * 

Sub-types

*

* {@link ChannelHandler} itself does not provide any method. To handle a * {@link ChannelEvent} you need to implement its sub-interfaces. There are * two sub-interfaces which handles a received event, one for upstream events * and the other for downstream events: *

    *
  • {@link ChannelUpstreamHandler} handles and intercepts an upstream {@link ChannelEvent}.
  • *
  • {@link ChannelDownstreamHandler} handles and intercepts a downstream {@link ChannelEvent}.
  • *
* * You will also find more detailed explanation from the documentation of * each sub-interface on how an event is interpreted when it goes upstream and * downstream respectively. * *

The context object

*

* A {@link ChannelHandler} is provided with a {@link ChannelHandlerContext} * object. A {@link ChannelHandler} is supposed to interact with the * {@link ChannelPipeline} it belongs to via a context object. Using the * context object, the {@link ChannelHandler} can pass events upstream or * downstream, modify the pipeline dynamically, or store the information * (attachment) which is specific to the handler. * *

State management

* * A {@link ChannelHandler} often needs to store some stateful information. * The simplest and recommended approach is to use member variables: *
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     private boolean loggedIn;
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             loggedIn = true;
 *         } else (o instanceof GetDataMessage) {
 *             if (loggedIn) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 * 
* Because the handler instance has a state variable which is dedicated to * one connection, you have to create a new handler instance for each new * channel to avoid a race condition where a unauthenticated client can get * the confidential information: *
 * // Create a new handler instance per channel.
 * // See {@link Bootstrap#setPipelineFactory(ChannelPipelineFactory)}.
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(new DataServerHandler());
 *     }
 * }
 * 
* *

Using an attachment

* * Although it's recommended to use member variables to store the state of a * handler, for some reason you might not want to create many handler instances. * In such a case, you can use an attachment which is provided by * {@link ChannelHandlerContext}: *
 * {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         {@link Channel} ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             ctx.setAttachment(true);
 *         } else (o instanceof GetDataMessage) {
 *             if (Boolean.TRUE.equals(ctx.getAttachment())) {
 *                 ch.write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 * 
* Now that the state of the handler is stored as an attachment, you can add the * same handler instance to different pipelines: *
 * public class DataServerPipelineFactory implements {@link ChannelPipelineFactory} {
 *
 *     private static final DataServerHandler SHARED = new DataServerHandler();
 *
 *     public {@link ChannelPipeline} getPipeline() {
 *         return {@link Channels}.pipeline(SHARED);
 *     }
 * }
 * 
* *

Using a {@link ChannelLocal}

* * If you have a state variable which needs to be accessed either from other * handlers or outside handlers, you can use {@link ChannelLocal}: *
 * public final class DataServerState {
 *
 *     public static final {@link ChannelLocal}<Boolean> loggedIn = new {@link ChannelLocal}<>() {
 *         protected Boolean initialValue(Channel channel) {
 *             return false;
 *         }
 *     }
 *     ...
 * }
 *
 * {@code @Sharable}
 * public class DataServerHandler extends {@link SimpleChannelHandler} {
 *
 *     {@code @Override}
 *     public void messageReceived({@link ChannelHandlerContext} ctx, {@link MessageEvent} e) {
 *         Channel ch = e.getChannel();
 *         Object o = e.getMessage();
 *         if (o instanceof LoginMessage) {
 *             authenticate((LoginMessage) o);
 *             DataServerState.loggedIn.set(ch, true);
 *         } else (o instanceof GetDataMessage) {
 *             if (DataServerState.loggedIn.get(ch)) {
 *                 ctx.getChannel().write(fetchSecret((GetDataMessage) o));
 *             } else {
 *                 fail();
 *             }
 *         }
 *     }
 *     ...
 * }
 *
 * // Print the remote addresses of the authenticated clients:
 * {@link ChannelGroup} allClientChannels = ...;
 * for ({@link Channel} ch: allClientChannels) {
 *     if (DataServerState.loggedIn.get(ch)) {
 *         System.out.println(ch.getRemoteAddress());
 *     }
 * }
 * 
* *

The {@code @Sharable} annotation

*

* In the examples above which used an attachment or a {@link ChannelLocal}, * you might have noticed the {@code @Sharable} annotation. *

* If a {@link ChannelHandler} is annotated with the {@code @Sharable} * annotation, it means you can create an instance of the handler just once and * add it to one or more {@link ChannelPipeline}s multiple times without * a race condition. *

* If this annotation is not specified, you have to create a new handler * instance every time you add it to a pipeline because it has unshared state * such as member variables. *

* This annotation is provided for documentation purpose, just like * the JCIP annotations. * *

Additional resources worth reading

*

* Please refer to the {@link ChannelEvent} and {@link ChannelPipeline} to find * out what a upstream event and a downstream event are, what fundamental * differences they have, and how they flow in a pipeline. * * @apiviz.landmark * @apiviz.exclude ^org\.jboss\.netty\.handler\..*$ */ public interface ChannelHandler { /** * Indicates that the same instance of the annotated {@link ChannelHandler} * can be added to one or more {@link ChannelPipeline}s multiple times * without a race condition. *

* If this annotation is not specified, you have to create a new handler * instance every time you add it to a pipeline because it has unshared * state such as member variables. *

* This annotation is provided for documentation purpose, just like * the JCIP annotations. */ @Inherited @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Sharable { // no value } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy