1 /*
2 * Copyright 2009 Red Hat, Inc.
3 *
4 * Red Hat licenses this file to you under the Apache License, version 2.0
5 * (the "License"); you may not use this file except in compliance with the
6 * License. You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package org.jboss.netty.handler.traffic;
17
18
19 import org.jboss.netty.channel.ChannelHandlerContext;
20 import org.jboss.netty.channel.ChannelPipelineFactory;
21 import org.jboss.netty.channel.ChannelStateEvent;
22 import org.jboss.netty.handler.execution.ExecutionHandler;
23 import org.jboss.netty.handler.execution.MemoryAwareThreadPoolExecutor;
24 import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
25 import org.jboss.netty.util.ObjectSizeEstimator;
26 import org.jboss.netty.util.Timer;
27
28 /**
29 * This implementation of the {@link AbstractTrafficShapingHandler} is for channel
30 * traffic shaping, that is to say a per channel limitation of the bandwidth.<br><br>
31 *
32 * The general use should be as follow:<br>
33 * <ul>
34 * <li>Add in your pipeline a new ChannelTrafficShapingHandler, before a recommended {@link ExecutionHandler} (like
35 * {@link OrderedMemoryAwareThreadPoolExecutor} or {@link MemoryAwareThreadPoolExecutor}).<br>
36 * <tt>ChannelTrafficShapingHandler myHandler = new ChannelTrafficShapingHandler(timer);</tt><br>
37 * timer could be created using <tt>HashedWheelTimer<tt><br>
38 * <tt>pipeline.addLast("CHANNEL_TRAFFIC_SHAPING", myHandler);</tt><br><br>
39 *
40 * <b>Note that this handler has a Pipeline Coverage of "one" which means a new handler must be created
41 * for each new channel as the counter cannot be shared among all channels.</b> For instance, if you have a
42 * {@link ChannelPipelineFactory}, you should create a new ChannelTrafficShapingHandler in this
43 * {@link ChannelPipelineFactory} each time getPipeline() method is called.<br><br>
44 *
45 * Other arguments can be passed like write or read limitation (in bytes/s where 0 means no limitation)
46 * or the check interval (in millisecond) that represents the delay between two computations of the
47 * bandwidth and so the call back of the doAccounting method (0 means no accounting at all).<br><br>
48 *
49 * A value of 0 means no accounting for checkInterval. If you need traffic shaping but no such accounting,
50 * it is recommended to set a positive value, even if it is high since the precision of the
51 * Traffic Shaping depends on the period where the traffic is computed. The highest the interval,
52 * the less precise the traffic shaping will be. It is suggested as higher value something close
53 * to 5 or 10 minutes.<br>
54 * </li>
55 * <li>When you shutdown your application, release all the external resources (except the timer internal itself)
56 * by calling:<br>
57 * <tt>myHandler.releaseExternalResources();</tt><br>
58 * </li>
59 * </ul><br>
60 *
61 * @author The Netty Project (netty-dev@lists.jboss.org)
62 * @author Frederic Bregier
63 */
64 public class ChannelTrafficShapingHandler extends AbstractTrafficShapingHandler {
65
66 /**
67 * @param timer
68 * @param writeLimit
69 * @param readLimit
70 * @param checkInterval
71 */
72 public ChannelTrafficShapingHandler(Timer timer, long writeLimit,
73 long readLimit, long checkInterval) {
74 super(timer, writeLimit, readLimit, checkInterval);
75 }
76
77 /**
78 * @param timer
79 * @param writeLimit
80 * @param readLimit
81 */
82 public ChannelTrafficShapingHandler(Timer timer, long writeLimit,
83 long readLimit) {
84 super(timer, writeLimit, readLimit);
85 }
86
87 /**
88 * @param timer
89 * @param checkInterval
90 */
91 public ChannelTrafficShapingHandler(Timer timer, long checkInterval) {
92 super(timer, checkInterval);
93 }
94
95 /**
96 * @param timer
97 */
98 public ChannelTrafficShapingHandler(Timer timer) {
99 super(timer);
100 }
101
102 /**
103 * @param objectSizeEstimator
104 * @param timer
105 * @param writeLimit
106 * @param readLimit
107 * @param checkInterval
108 */
109 public ChannelTrafficShapingHandler(
110 ObjectSizeEstimator objectSizeEstimator, Timer timer,
111 long writeLimit, long readLimit, long checkInterval) {
112 super(objectSizeEstimator, timer, writeLimit, readLimit,
113 checkInterval);
114 }
115
116 /**
117 * @param objectSizeEstimator
118 * @param timer
119 * @param writeLimit
120 * @param readLimit
121 */
122 public ChannelTrafficShapingHandler(
123 ObjectSizeEstimator objectSizeEstimator, Timer timer,
124 long writeLimit, long readLimit) {
125 super(objectSizeEstimator, timer, writeLimit, readLimit);
126 }
127
128 /**
129 * @param objectSizeEstimator
130 * @param timer
131 * @param checkInterval
132 */
133 public ChannelTrafficShapingHandler(
134 ObjectSizeEstimator objectSizeEstimator, Timer timer,
135 long checkInterval) {
136 super(objectSizeEstimator, timer, checkInterval);
137 }
138
139 /**
140 * @param objectSizeEstimator
141 * @param timer
142 */
143 public ChannelTrafficShapingHandler(
144 ObjectSizeEstimator objectSizeEstimator, Timer timer) {
145 super(objectSizeEstimator, timer);
146 }
147
148 @Override
149 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
150 throws Exception {
151 if (trafficCounter != null) {
152 trafficCounter.stop();
153 }
154 super.channelClosed(ctx, e);
155 }
156
157 @Override
158 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
159 throws Exception {
160 // readSuspended = true;
161 ctx.setAttachment(Boolean.TRUE);
162 ctx.getChannel().setReadable(false);
163 if (trafficCounter == null) {
164 // create a new counter now
165 if (timer != null) {
166 trafficCounter = new TrafficCounter(this, timer, "ChannelTC" +
167 ctx.getChannel().getId(), checkInterval);
168 }
169 }
170 if (trafficCounter != null) {
171 trafficCounter.start();
172 }
173 super.channelConnected(ctx, e);
174 // readSuspended = false;
175 ctx.setAttachment(null);
176 ctx.getChannel().setReadable(true);
177 }
178
179 }