Last but not least coding conventions
This commit is contained in:
parent
8db746d3fd
commit
eb4e6bd556
File diff suppressed because it is too large
Load Diff
@ -1,486 +1,485 @@
|
||||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2009, 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.handler.trafficshaping;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.jboss.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (tlee@redhat.com)
|
||||
* @author Frederic Bregier (fredbregier@free.fr)
|
||||
* @version $Rev$, $Date$
|
||||
*
|
||||
* The {@link PerformanceCounterFactory} is a Factory for
|
||||
* {@link PerformanceCounter}. It stores the necessary information to enable
|
||||
* dynamic creation of {@link PerformanceCounter} inside the
|
||||
* {@link TrafficShapingHandler}.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class PerformanceCounterFactory {
|
||||
/**
|
||||
* No limit
|
||||
*/
|
||||
public static long NO_LIMIT = -1;
|
||||
|
||||
/**
|
||||
* No statistics (if channel or global PerformanceCounter is a very long
|
||||
* time living, it can produce a excess of capacity, i.e. 2^64 bytes so 17
|
||||
* billions of billions of bytes).
|
||||
*/
|
||||
public static long NO_STAT = -1;
|
||||
|
||||
/**
|
||||
* Default delay between two checks: 1s
|
||||
*/
|
||||
public static long DEFAULT_DELAY = 1000;
|
||||
|
||||
/**
|
||||
* ExecutorService to associated to any PerformanceCounter
|
||||
*/
|
||||
private ExecutorService executorService = null;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to write for all channel PerformanceCounter
|
||||
*/
|
||||
private long channelLimitWrite = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to read for all channel PerformanceCounter
|
||||
*/
|
||||
private long channelLimitRead = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Delay between two performance snapshots for channel
|
||||
*/
|
||||
private long channelDelay = DEFAULT_DELAY; // default 1 s
|
||||
|
||||
/**
|
||||
* Will the PerformanceCounter for Channel be active
|
||||
*/
|
||||
private boolean channelActive = true;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to write for the global PerformanceCounter
|
||||
*/
|
||||
private long globalLimitWrite = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to read for the global PerformanceCounter
|
||||
*/
|
||||
private long globalLimitRead = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Delay between two performance snapshots for global
|
||||
*/
|
||||
private long globalDelay = DEFAULT_DELAY; // default 1 s
|
||||
|
||||
/**
|
||||
* Will the PerformanceCounter for Global be active
|
||||
*/
|
||||
private boolean globalActive = true;
|
||||
|
||||
/**
|
||||
* Global Monitor
|
||||
*/
|
||||
private PerformanceCounter globalPerformanceMonitor = null;
|
||||
|
||||
/**
|
||||
* Called each time the accounting is computed for the PerformanceCounters.
|
||||
* This method could be used for instance to implement real time accounting.
|
||||
*
|
||||
* @param counter
|
||||
* the PerformanceCounter that computes its performance
|
||||
*/
|
||||
protected abstract void accounting(PerformanceCounter counter);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param newexecutorService
|
||||
* @param newChannelActive
|
||||
* @param newChannelLimitWrite
|
||||
* @param newChannelLimitRead
|
||||
* @param newChannelDelay
|
||||
* @param newGlobalActive
|
||||
* @param newGlobalLimitWrite
|
||||
* @param newGlobalLimitRead
|
||||
* @param newGlobalDelay
|
||||
*/
|
||||
private void init(ExecutorService newexecutorService,
|
||||
boolean newChannelActive, long newChannelLimitWrite,
|
||||
long newChannelLimitRead, long newChannelDelay,
|
||||
boolean newGlobalActive, long newGlobalLimitWrite,
|
||||
long newGlobalLimitRead, long newGlobalDelay) {
|
||||
this.executorService = newexecutorService;
|
||||
this.channelActive = newChannelActive;
|
||||
this.channelLimitWrite = newChannelLimitWrite;
|
||||
this.channelLimitRead = newChannelLimitRead;
|
||||
this.channelDelay = newChannelDelay;
|
||||
this.globalActive = newGlobalActive;
|
||||
this.globalLimitWrite = newGlobalLimitWrite;
|
||||
this.globalLimitRead = newGlobalLimitRead;
|
||||
this.globalDelay = newGlobalDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param channelLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelDelay
|
||||
* The delay between two computations of performances for
|
||||
* channels or NO_STAT if no stats are to be computed
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalDelay
|
||||
* The delay between two computations of performances for global
|
||||
* context or NO_STAT if no stats are to be computed
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, long channelLimitWrite,
|
||||
long channelLimitRead, long channelDelay, boolean globalActive,
|
||||
long globalLimitWrite, long globalLimitRead, long globalDelay) {
|
||||
init(executorService, channelActive, channelLimitWrite,
|
||||
channelLimitRead, channelDelay, globalActive, globalLimitWrite,
|
||||
globalLimitRead, globalDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using default Delay
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param channelLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, long channelLimitWrite,
|
||||
long channelLimitRead, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead) {
|
||||
init(executorService, channelActive, channelLimitWrite,
|
||||
channelLimitRead, DEFAULT_DELAY, globalActive,
|
||||
globalLimitWrite, globalLimitRead, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT and default delay for channels
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalDelay
|
||||
* The delay between two computations of performances for global
|
||||
* context or NO_STAT if no stats are to be computed
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead, long globalDelay) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, globalLimitWrite, globalLimitRead,
|
||||
globalDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT for channels and default delay for all
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, globalLimitWrite, globalLimitRead,
|
||||
DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT and default delay for all
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, NO_LIMIT, NO_LIMIT, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to change the active status of PerformanceCounter on Channels (for
|
||||
* new one only)
|
||||
*
|
||||
* @param active
|
||||
*/
|
||||
public void setChannelActive(boolean active) {
|
||||
this.channelActive = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to change the active status of PerformanceCounter on Global (stop
|
||||
* or start if necessary)
|
||||
*
|
||||
* @param active
|
||||
*/
|
||||
public void setGlobalActive(boolean active) {
|
||||
if (this.globalActive) {
|
||||
if (!active) {
|
||||
stopGlobalPerformanceCounter();
|
||||
}
|
||||
}
|
||||
this.globalActive = active;
|
||||
getGlobalPerformanceCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the underlying limitations. Only Global PerformanceCounter (if
|
||||
* any) is dynamically changed, but Channels PerformanceCounters are not
|
||||
* changed, only new created ones.
|
||||
*
|
||||
* @param newchannelLimitWrite
|
||||
* @param newchannelLimitRead
|
||||
* @param newchanneldelay
|
||||
* @param newglobalLimitWrite
|
||||
* @param newglobalLimitRead
|
||||
* @param newglobaldelay
|
||||
*/
|
||||
public void changeConfiguration(long newchannelLimitWrite,
|
||||
long newchannelLimitRead, long newchanneldelay,
|
||||
long newglobalLimitWrite, long newglobalLimitRead,
|
||||
long newglobaldelay) {
|
||||
this.channelLimitWrite = newchannelLimitWrite;
|
||||
this.channelLimitRead = newchannelLimitRead;
|
||||
this.channelDelay = newchanneldelay;
|
||||
this.globalLimitWrite = newglobalLimitWrite;
|
||||
this.globalLimitRead = newglobalLimitRead;
|
||||
this.globalDelay = newglobaldelay;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
newglobalLimitWrite, newglobalLimitRead, newglobaldelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Global PerformanceCounter or null if this support is disabled
|
||||
*/
|
||||
public PerformanceCounter getGlobalPerformanceCounter() {
|
||||
if (this.globalActive) {
|
||||
if (this.globalPerformanceMonitor == null) {
|
||||
this.globalPerformanceMonitor = new PerformanceCounter(this,
|
||||
this.executorService, null, "GlobalPC",
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
this.globalPerformanceMonitor.startMonitoring();
|
||||
}
|
||||
}
|
||||
return this.globalPerformanceMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel
|
||||
* @return the channel PerformanceCounter or null if this support is
|
||||
* disabled
|
||||
*/
|
||||
public PerformanceCounter createChannelPerformanceCounter(Channel channel) {
|
||||
if (this.channelActive && ((this.channelLimitRead > NO_LIMIT) || (this.channelLimitWrite > NO_LIMIT)
|
||||
|| (this.channelDelay > NO_STAT))) {
|
||||
return new PerformanceCounter(this, this.executorService, channel,
|
||||
"ChannelPC" + channel.getId(), this.channelLimitWrite,
|
||||
this.channelLimitRead, this.channelDelay);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the global performance counter if any (Even it is stopped, the
|
||||
* factory can however be reused)
|
||||
*
|
||||
*/
|
||||
public void stopGlobalPerformanceCounter() {
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.stopMonitoring();
|
||||
this.globalPerformanceMonitor = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelDelay
|
||||
*/
|
||||
public long getChannelDelay() {
|
||||
return this.channelDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelDelay
|
||||
* the channelDelay to set
|
||||
*/
|
||||
public void setChannelDelay(long channelDelay) {
|
||||
this.channelDelay = channelDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelLimitRead
|
||||
*/
|
||||
public long getChannelLimitRead() {
|
||||
return this.channelLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelLimitRead
|
||||
* the channelLimitRead to set
|
||||
*/
|
||||
public void setChannelLimitRead(long channelLimitRead) {
|
||||
this.channelLimitRead = channelLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelLimitWrite
|
||||
*/
|
||||
public long getChannelLimitWrite() {
|
||||
return this.channelLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelLimitWrite
|
||||
* the channelLimitWrite to set
|
||||
*/
|
||||
public void setChannelLimitWrite(long channelLimitWrite) {
|
||||
this.channelLimitWrite = channelLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalDelay
|
||||
*/
|
||||
public long getGlobalDelay() {
|
||||
return this.globalDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalDelay
|
||||
* the globalDelay to set
|
||||
*/
|
||||
public void setGlobalDelay(long globalDelay) {
|
||||
this.globalDelay = globalDelay;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalLimitRead
|
||||
*/
|
||||
public long getGlobalLimitRead() {
|
||||
return this.globalLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalLimitRead
|
||||
* the globalLimitRead to set
|
||||
*/
|
||||
public void setGlobalLimitRead(long globalLimitRead) {
|
||||
this.globalLimitRead = globalLimitRead;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalLimitWrite
|
||||
*/
|
||||
public long getGlobalLimitWrite() {
|
||||
return this.globalLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalLimitWrite
|
||||
* the globalLimitWrite to set
|
||||
*/
|
||||
public void setGlobalLimitWrite(long globalLimitWrite) {
|
||||
this.globalLimitWrite = globalLimitWrite;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelActive
|
||||
*/
|
||||
public boolean isChannelActive() {
|
||||
return this.channelActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalActive
|
||||
*/
|
||||
public boolean isGlobalActive() {
|
||||
return this.globalActive;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2009, 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.handler.trafficshaping;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.jboss.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Frederic Bregier (fredbregier@free.fr)
|
||||
* @version $Rev$, $Date$
|
||||
*
|
||||
* The {@link PerformanceCounterFactory} is a Factory for
|
||||
* {@link PerformanceCounter}. It stores the necessary information to enable
|
||||
* dynamic creation of {@link PerformanceCounter} inside the
|
||||
* {@link TrafficShapingHandler}.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public abstract class PerformanceCounterFactory {
|
||||
/**
|
||||
* No limit
|
||||
*/
|
||||
public static long NO_LIMIT = -1;
|
||||
|
||||
/**
|
||||
* No statistics (if channel or global PerformanceCounter is a very long
|
||||
* time living, it can produce a excess of capacity, i.e. 2^64 bytes so 17
|
||||
* billions of billions of bytes).
|
||||
*/
|
||||
public static long NO_STAT = -1;
|
||||
|
||||
/**
|
||||
* Default delay between two checks: 1s
|
||||
*/
|
||||
public static long DEFAULT_DELAY = 1000;
|
||||
|
||||
/**
|
||||
* ExecutorService to associated to any PerformanceCounter
|
||||
*/
|
||||
private ExecutorService executorService = null;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to write for all channel PerformanceCounter
|
||||
*/
|
||||
private long channelLimitWrite = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to read for all channel PerformanceCounter
|
||||
*/
|
||||
private long channelLimitRead = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Delay between two performance snapshots for channel
|
||||
*/
|
||||
private long channelDelay = DEFAULT_DELAY; // default 1 s
|
||||
|
||||
/**
|
||||
* Will the PerformanceCounter for Channel be active
|
||||
*/
|
||||
private boolean channelActive = true;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to write for the global PerformanceCounter
|
||||
*/
|
||||
private long globalLimitWrite = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Limit in B/s to apply to read for the global PerformanceCounter
|
||||
*/
|
||||
private long globalLimitRead = NO_LIMIT;
|
||||
|
||||
/**
|
||||
* Delay between two performance snapshots for global
|
||||
*/
|
||||
private long globalDelay = DEFAULT_DELAY; // default 1 s
|
||||
|
||||
/**
|
||||
* Will the PerformanceCounter for Global be active
|
||||
*/
|
||||
private boolean globalActive = true;
|
||||
|
||||
/**
|
||||
* Global Monitor
|
||||
*/
|
||||
private PerformanceCounter globalPerformanceMonitor = null;
|
||||
|
||||
/**
|
||||
* Called each time the accounting is computed for the PerformanceCounters.
|
||||
* This method could be used for instance to implement real time accounting.
|
||||
*
|
||||
* @param counter
|
||||
* the PerformanceCounter that computes its performance
|
||||
*/
|
||||
protected abstract void accounting(PerformanceCounter counter);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param newexecutorService
|
||||
* @param newChannelActive
|
||||
* @param newChannelLimitWrite
|
||||
* @param newChannelLimitRead
|
||||
* @param newChannelDelay
|
||||
* @param newGlobalActive
|
||||
* @param newGlobalLimitWrite
|
||||
* @param newGlobalLimitRead
|
||||
* @param newGlobalDelay
|
||||
*/
|
||||
private void init(ExecutorService newexecutorService,
|
||||
boolean newChannelActive, long newChannelLimitWrite,
|
||||
long newChannelLimitRead, long newChannelDelay,
|
||||
boolean newGlobalActive, long newGlobalLimitWrite,
|
||||
long newGlobalLimitRead, long newGlobalDelay) {
|
||||
this.executorService = newexecutorService;
|
||||
this.channelActive = newChannelActive;
|
||||
this.channelLimitWrite = newChannelLimitWrite;
|
||||
this.channelLimitRead = newChannelLimitRead;
|
||||
this.channelDelay = newChannelDelay;
|
||||
this.globalActive = newGlobalActive;
|
||||
this.globalLimitWrite = newGlobalLimitWrite;
|
||||
this.globalLimitRead = newGlobalLimitRead;
|
||||
this.globalDelay = newGlobalDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full constructor
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param channelLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelDelay
|
||||
* The delay between two computations of performances for
|
||||
* channels or NO_STAT if no stats are to be computed
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalDelay
|
||||
* The delay between two computations of performances for global
|
||||
* context or NO_STAT if no stats are to be computed
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, long channelLimitWrite,
|
||||
long channelLimitRead, long channelDelay, boolean globalActive,
|
||||
long globalLimitWrite, long globalLimitRead, long globalDelay) {
|
||||
init(executorService, channelActive, channelLimitWrite,
|
||||
channelLimitRead, channelDelay, globalActive, globalLimitWrite,
|
||||
globalLimitRead, globalDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using default Delay
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param channelLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param channelLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, long channelLimitWrite,
|
||||
long channelLimitRead, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead) {
|
||||
init(executorService, channelActive, channelLimitWrite,
|
||||
channelLimitRead, DEFAULT_DELAY, globalActive,
|
||||
globalLimitWrite, globalLimitRead, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT and default delay for channels
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalDelay
|
||||
* The delay between two computations of performances for global
|
||||
* context or NO_STAT if no stats are to be computed
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead, long globalDelay) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, globalLimitWrite, globalLimitRead,
|
||||
globalDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT for channels and default delay for all
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
* @param globalLimitWrite
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
* @param globalLimitRead
|
||||
* NO_LIMIT or a limit in bytes/s
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive, long globalLimitWrite,
|
||||
long globalLimitRead) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, globalLimitWrite, globalLimitRead,
|
||||
DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor using NO_LIMIT and default delay for all
|
||||
*
|
||||
* @param executorService
|
||||
* created for instance like Executors.newCachedThreadPool
|
||||
* @param channelActive
|
||||
* True if each channel will have a PerformanceCounter
|
||||
* @param globalActive
|
||||
* True if global context will have one unique PerformanceCounter
|
||||
*/
|
||||
public PerformanceCounterFactory(ExecutorService executorService,
|
||||
boolean channelActive, boolean globalActive) {
|
||||
init(executorService, channelActive, NO_LIMIT, NO_LIMIT,
|
||||
DEFAULT_DELAY, globalActive, NO_LIMIT, NO_LIMIT, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to change the active status of PerformanceCounter on Channels (for
|
||||
* new one only)
|
||||
*
|
||||
* @param active
|
||||
*/
|
||||
public void setChannelActive(boolean active) {
|
||||
this.channelActive = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to change the active status of PerformanceCounter on Global (stop
|
||||
* or start if necessary)
|
||||
*
|
||||
* @param active
|
||||
*/
|
||||
public void setGlobalActive(boolean active) {
|
||||
if (this.globalActive) {
|
||||
if (!active) {
|
||||
stopGlobalPerformanceCounter();
|
||||
}
|
||||
}
|
||||
this.globalActive = active;
|
||||
getGlobalPerformanceCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the underlying limitations. Only Global PerformanceCounter (if
|
||||
* any) is dynamically changed, but Channels PerformanceCounters are not
|
||||
* changed, only new created ones.
|
||||
*
|
||||
* @param newchannelLimitWrite
|
||||
* @param newchannelLimitRead
|
||||
* @param newchanneldelay
|
||||
* @param newglobalLimitWrite
|
||||
* @param newglobalLimitRead
|
||||
* @param newglobaldelay
|
||||
*/
|
||||
public void changeConfiguration(long newchannelLimitWrite,
|
||||
long newchannelLimitRead, long newchanneldelay,
|
||||
long newglobalLimitWrite, long newglobalLimitRead,
|
||||
long newglobaldelay) {
|
||||
this.channelLimitWrite = newchannelLimitWrite;
|
||||
this.channelLimitRead = newchannelLimitRead;
|
||||
this.channelDelay = newchanneldelay;
|
||||
this.globalLimitWrite = newglobalLimitWrite;
|
||||
this.globalLimitRead = newglobalLimitRead;
|
||||
this.globalDelay = newglobaldelay;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
newglobalLimitWrite, newglobalLimitRead, newglobaldelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Global PerformanceCounter or null if this support is disabled
|
||||
*/
|
||||
public PerformanceCounter getGlobalPerformanceCounter() {
|
||||
if (this.globalActive) {
|
||||
if (this.globalPerformanceMonitor == null) {
|
||||
this.globalPerformanceMonitor = new PerformanceCounter(this,
|
||||
this.executorService, null, "GlobalPC",
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
this.globalPerformanceMonitor.startMonitoring();
|
||||
}
|
||||
}
|
||||
return this.globalPerformanceMonitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel
|
||||
* @return the channel PerformanceCounter or null if this support is
|
||||
* disabled
|
||||
*/
|
||||
public PerformanceCounter createChannelPerformanceCounter(Channel channel) {
|
||||
if (this.channelActive && ((this.channelLimitRead > NO_LIMIT) || (this.channelLimitWrite > NO_LIMIT)
|
||||
|| (this.channelDelay > NO_STAT))) {
|
||||
return new PerformanceCounter(this, this.executorService, channel,
|
||||
"ChannelPC" + channel.getId(), this.channelLimitWrite,
|
||||
this.channelLimitRead, this.channelDelay);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the global performance counter if any (Even it is stopped, the
|
||||
* factory can however be reused)
|
||||
*
|
||||
*/
|
||||
public void stopGlobalPerformanceCounter() {
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.stopMonitoring();
|
||||
this.globalPerformanceMonitor = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelDelay
|
||||
*/
|
||||
public long getChannelDelay() {
|
||||
return this.channelDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelDelay
|
||||
* the channelDelay to set
|
||||
*/
|
||||
public void setChannelDelay(long channelDelay) {
|
||||
this.channelDelay = channelDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelLimitRead
|
||||
*/
|
||||
public long getChannelLimitRead() {
|
||||
return this.channelLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelLimitRead
|
||||
* the channelLimitRead to set
|
||||
*/
|
||||
public void setChannelLimitRead(long channelLimitRead) {
|
||||
this.channelLimitRead = channelLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelLimitWrite
|
||||
*/
|
||||
public long getChannelLimitWrite() {
|
||||
return this.channelLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channelLimitWrite
|
||||
* the channelLimitWrite to set
|
||||
*/
|
||||
public void setChannelLimitWrite(long channelLimitWrite) {
|
||||
this.channelLimitWrite = channelLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalDelay
|
||||
*/
|
||||
public long getGlobalDelay() {
|
||||
return this.globalDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalDelay
|
||||
* the globalDelay to set
|
||||
*/
|
||||
public void setGlobalDelay(long globalDelay) {
|
||||
this.globalDelay = globalDelay;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalLimitRead
|
||||
*/
|
||||
public long getGlobalLimitRead() {
|
||||
return this.globalLimitRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalLimitRead
|
||||
* the globalLimitRead to set
|
||||
*/
|
||||
public void setGlobalLimitRead(long globalLimitRead) {
|
||||
this.globalLimitRead = globalLimitRead;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalLimitWrite
|
||||
*/
|
||||
public long getGlobalLimitWrite() {
|
||||
return this.globalLimitWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param globalLimitWrite
|
||||
* the globalLimitWrite to set
|
||||
*/
|
||||
public void setGlobalLimitWrite(long globalLimitWrite) {
|
||||
this.globalLimitWrite = globalLimitWrite;
|
||||
if (this.globalPerformanceMonitor != null) {
|
||||
this.globalPerformanceMonitor.changeConfiguration(null,
|
||||
this.globalLimitWrite, this.globalLimitRead,
|
||||
this.globalDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the channelActive
|
||||
*/
|
||||
public boolean isChannelActive() {
|
||||
return this.channelActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the globalActive
|
||||
*/
|
||||
public boolean isGlobalActive() {
|
||||
return this.globalActive;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,250 +1,249 @@
|
||||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2009, 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.handler.trafficshaping;
|
||||
|
||||
import java.io.InvalidClassException;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelEvent;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipelineCoverage;
|
||||
import org.jboss.netty.channel.ChannelState;
|
||||
import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
|
||||
/**
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Trustin Lee (tlee@redhat.com)
|
||||
* @author Frederic Bregier (fredbregier@free.fr)
|
||||
* @version $Rev$, $Date$
|
||||
*
|
||||
* TrafficShapingHandler allows to limit the global bandwidth or per session
|
||||
* bandwidth, as traffic shaping.<br>
|
||||
* <br>
|
||||
*
|
||||
* The method getMessageSize(MessageEvent) has to be implemented to specify what
|
||||
* is the size of the object to be read or write accordingly to the type of
|
||||
* object. In simple case, it can be as simple as a call to
|
||||
* getChannelBufferMessageSize(MessageEvent).<br>
|
||||
* <br>
|
||||
*
|
||||
* TrafficShapingHandler depends on {@link PerformanceCounterFactory} to create
|
||||
* or use the necessary {@link PerformanceCounter} with the necessary options.
|
||||
* However, you can change the behavior of both global and channel
|
||||
* PerformanceCounter if you like by getting them from this handler and changing
|
||||
* their status.
|
||||
*
|
||||
*/
|
||||
@ChannelPipelineCoverage("one")
|
||||
public abstract class TrafficShapingHandler extends SimpleChannelHandler {
|
||||
/**
|
||||
* Channel Monitor
|
||||
*/
|
||||
private PerformanceCounter channelPerformanceCounter = null;
|
||||
|
||||
/**
|
||||
* Global Monitor
|
||||
*/
|
||||
private PerformanceCounter globalPerformanceCounter = null;
|
||||
|
||||
/**
|
||||
* Factory if used
|
||||
*/
|
||||
private PerformanceCounterFactory factory = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param factory
|
||||
* the PerformanceCounterFactory from which all Monitors will be
|
||||
* created
|
||||
*/
|
||||
public TrafficShapingHandler(PerformanceCounterFactory factory) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
this.globalPerformanceCounter = this.factory
|
||||
.getGlobalPerformanceCounter();
|
||||
this.channelPerformanceCounter = null;
|
||||
// will be set when connected is called
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has to be implemented. It returns the size in bytes of the
|
||||
* message to be read or written.
|
||||
*
|
||||
* @param arg1
|
||||
* the MessageEvent to be read or written
|
||||
* @return the size in bytes of the given MessageEvent
|
||||
* @exception Exception
|
||||
* An exception can be thrown if the object is not of the
|
||||
* expected type
|
||||
*/
|
||||
protected abstract long getMessageSize(MessageEvent arg1) throws Exception;
|
||||
|
||||
/**
|
||||
* Example of function (which can be used) for the ChannelBuffer
|
||||
*
|
||||
* @param arg1
|
||||
* @return the size in bytes of the given MessageEvent
|
||||
* @throws Exception
|
||||
*/
|
||||
protected long getChannelBufferMessageSize(MessageEvent arg1)
|
||||
throws Exception {
|
||||
Object o = arg1.getMessage();
|
||||
if (!(o instanceof ChannelBuffer)) {
|
||||
// Type unimplemented
|
||||
throw new InvalidClassException("Wrong object received in " +
|
||||
this.getClass().getName() + " codec " +
|
||||
o.getClass().getName());
|
||||
}
|
||||
ChannelBuffer dataBlock = (ChannelBuffer) o;
|
||||
return dataBlock.readableBytes();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.MessageEvent)
|
||||
*/
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext arg0, MessageEvent arg1)
|
||||
throws Exception {
|
||||
long size = getMessageSize(arg1);
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.setReceivedBytes(arg0, size);
|
||||
}
|
||||
if (this.globalPerformanceCounter != null) {
|
||||
this.globalPerformanceCounter.setReceivedBytes(arg0, size);
|
||||
}
|
||||
// The message is then just passed to the next Codec
|
||||
super.messageReceived(arg0, arg1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#writeRequested(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.MessageEvent)
|
||||
*/
|
||||
@Override
|
||||
public void writeRequested(ChannelHandlerContext arg0, MessageEvent arg1)
|
||||
throws Exception {
|
||||
long size = getMessageSize(arg1);
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.setToWriteBytes(size);
|
||||
}
|
||||
if (this.globalPerformanceCounter != null) {
|
||||
this.globalPerformanceCounter.setToWriteBytes(size);
|
||||
}
|
||||
// The message is then just passed to the next Codec
|
||||
super.writeRequested(arg0, arg1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#channelClosed(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.ChannelStateEvent)
|
||||
*/
|
||||
@Override
|
||||
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
|
||||
throws Exception {
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.stopMonitoring();
|
||||
this.channelPerformanceCounter = null;
|
||||
}
|
||||
super.channelClosed(ctx, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.ChannelStateEvent)
|
||||
*/
|
||||
@Override
|
||||
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
|
||||
throws Exception {
|
||||
// readSuspended = true;
|
||||
ctx.setAttachment(Boolean.TRUE);
|
||||
ctx.getChannel().setReadable(false);
|
||||
if ((this.channelPerformanceCounter == null) && (this.factory != null)) {
|
||||
// A factory was used
|
||||
this.channelPerformanceCounter = this.factory
|
||||
.createChannelPerformanceCounter(ctx.getChannel());
|
||||
}
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter
|
||||
.setMonitoredChannel(ctx.getChannel());
|
||||
this.channelPerformanceCounter.startMonitoring();
|
||||
}
|
||||
super.channelConnected(ctx, e);
|
||||
// readSuspended = false;
|
||||
ctx.setAttachment(null);
|
||||
ctx.getChannel().setReadable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
|
||||
throws Exception {
|
||||
if (e instanceof ChannelStateEvent) {
|
||||
ChannelStateEvent cse = (ChannelStateEvent) e;
|
||||
if (cse.getState() == ChannelState.INTEREST_OPS &&
|
||||
(((Integer) cse.getValue()).intValue() & Channel.OP_READ) != 0) {
|
||||
|
||||
// setReadable(true) requested
|
||||
boolean readSuspended = ctx.getAttachment() != null;
|
||||
if (readSuspended) {
|
||||
// Drop the request silently if PerformanceCounter has
|
||||
// set the flag.
|
||||
e.getFuture().setSuccess();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.handleDownstream(ctx, e);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the current ChannelPerformanceCounter set from the factory (if
|
||||
* channel is still connected) or null if this function was disabled
|
||||
* in the Factory
|
||||
*/
|
||||
public PerformanceCounter getChannelPerformanceCounter() {
|
||||
return this.channelPerformanceCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the GlobalPerformanceCounter from the factory or null if this
|
||||
* function was disabled in the Factory
|
||||
*/
|
||||
public PerformanceCounter getGlobalPerformanceCounter() {
|
||||
return this.globalPerformanceCounter;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2009, 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.handler.trafficshaping;
|
||||
|
||||
import java.io.InvalidClassException;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.channel.Channel;
|
||||
import org.jboss.netty.channel.ChannelEvent;
|
||||
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||
import org.jboss.netty.channel.ChannelPipelineCoverage;
|
||||
import org.jboss.netty.channel.ChannelState;
|
||||
import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
|
||||
/**
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
* @author Frederic Bregier (fredbregier@free.fr)
|
||||
* @version $Rev$, $Date$
|
||||
*
|
||||
* TrafficShapingHandler allows to limit the global bandwidth or per session
|
||||
* bandwidth, as traffic shaping.<br>
|
||||
* <br>
|
||||
*
|
||||
* The method getMessageSize(MessageEvent) has to be implemented to specify what
|
||||
* is the size of the object to be read or write accordingly to the type of
|
||||
* object. In simple case, it can be as simple as a call to
|
||||
* getChannelBufferMessageSize(MessageEvent).<br>
|
||||
* <br>
|
||||
*
|
||||
* TrafficShapingHandler depends on {@link PerformanceCounterFactory} to create
|
||||
* or use the necessary {@link PerformanceCounter} with the necessary options.
|
||||
* However, you can change the behavior of both global and channel
|
||||
* PerformanceCounter if you like by getting them from this handler and changing
|
||||
* their status.
|
||||
*
|
||||
*/
|
||||
@ChannelPipelineCoverage("one")
|
||||
public abstract class TrafficShapingHandler extends SimpleChannelHandler {
|
||||
/**
|
||||
* Channel Monitor
|
||||
*/
|
||||
private PerformanceCounter channelPerformanceCounter = null;
|
||||
|
||||
/**
|
||||
* Global Monitor
|
||||
*/
|
||||
private PerformanceCounter globalPerformanceCounter = null;
|
||||
|
||||
/**
|
||||
* Factory if used
|
||||
*/
|
||||
private PerformanceCounterFactory factory = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param factory
|
||||
* the PerformanceCounterFactory from which all Monitors will be
|
||||
* created
|
||||
*/
|
||||
public TrafficShapingHandler(PerformanceCounterFactory factory) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
this.globalPerformanceCounter = this.factory
|
||||
.getGlobalPerformanceCounter();
|
||||
this.channelPerformanceCounter = null;
|
||||
// will be set when connected is called
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has to be implemented. It returns the size in bytes of the
|
||||
* message to be read or written.
|
||||
*
|
||||
* @param arg1
|
||||
* the MessageEvent to be read or written
|
||||
* @return the size in bytes of the given MessageEvent
|
||||
* @exception Exception
|
||||
* An exception can be thrown if the object is not of the
|
||||
* expected type
|
||||
*/
|
||||
protected abstract long getMessageSize(MessageEvent arg1) throws Exception;
|
||||
|
||||
/**
|
||||
* Example of function (which can be used) for the ChannelBuffer
|
||||
*
|
||||
* @param arg1
|
||||
* @return the size in bytes of the given MessageEvent
|
||||
* @throws Exception
|
||||
*/
|
||||
protected long getChannelBufferMessageSize(MessageEvent arg1)
|
||||
throws Exception {
|
||||
Object o = arg1.getMessage();
|
||||
if (!(o instanceof ChannelBuffer)) {
|
||||
// Type unimplemented
|
||||
throw new InvalidClassException("Wrong object received in " +
|
||||
this.getClass().getName() + " codec " +
|
||||
o.getClass().getName());
|
||||
}
|
||||
ChannelBuffer dataBlock = (ChannelBuffer) o;
|
||||
return dataBlock.readableBytes();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.MessageEvent)
|
||||
*/
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext arg0, MessageEvent arg1)
|
||||
throws Exception {
|
||||
long size = getMessageSize(arg1);
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.setReceivedBytes(arg0, size);
|
||||
}
|
||||
if (this.globalPerformanceCounter != null) {
|
||||
this.globalPerformanceCounter.setReceivedBytes(arg0, size);
|
||||
}
|
||||
// The message is then just passed to the next Codec
|
||||
super.messageReceived(arg0, arg1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#writeRequested(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.MessageEvent)
|
||||
*/
|
||||
@Override
|
||||
public void writeRequested(ChannelHandlerContext arg0, MessageEvent arg1)
|
||||
throws Exception {
|
||||
long size = getMessageSize(arg1);
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.setToWriteBytes(size);
|
||||
}
|
||||
if (this.globalPerformanceCounter != null) {
|
||||
this.globalPerformanceCounter.setToWriteBytes(size);
|
||||
}
|
||||
// The message is then just passed to the next Codec
|
||||
super.writeRequested(arg0, arg1);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#channelClosed(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.ChannelStateEvent)
|
||||
*/
|
||||
@Override
|
||||
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
|
||||
throws Exception {
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter.stopMonitoring();
|
||||
this.channelPerformanceCounter = null;
|
||||
}
|
||||
super.channelClosed(ctx, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.jboss.netty.channel.SimpleChannelHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext,
|
||||
* org.jboss.netty.channel.ChannelStateEvent)
|
||||
*/
|
||||
@Override
|
||||
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
|
||||
throws Exception {
|
||||
// readSuspended = true;
|
||||
ctx.setAttachment(Boolean.TRUE);
|
||||
ctx.getChannel().setReadable(false);
|
||||
if ((this.channelPerformanceCounter == null) && (this.factory != null)) {
|
||||
// A factory was used
|
||||
this.channelPerformanceCounter = this.factory
|
||||
.createChannelPerformanceCounter(ctx.getChannel());
|
||||
}
|
||||
if (this.channelPerformanceCounter != null) {
|
||||
this.channelPerformanceCounter
|
||||
.setMonitoredChannel(ctx.getChannel());
|
||||
this.channelPerformanceCounter.startMonitoring();
|
||||
}
|
||||
super.channelConnected(ctx, e);
|
||||
// readSuspended = false;
|
||||
ctx.setAttachment(null);
|
||||
ctx.getChannel().setReadable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
|
||||
throws Exception {
|
||||
if (e instanceof ChannelStateEvent) {
|
||||
ChannelStateEvent cse = (ChannelStateEvent) e;
|
||||
if (cse.getState() == ChannelState.INTEREST_OPS &&
|
||||
(((Integer) cse.getValue()).intValue() & Channel.OP_READ) != 0) {
|
||||
|
||||
// setReadable(true) requested
|
||||
boolean readSuspended = ctx.getAttachment() != null;
|
||||
if (readSuspended) {
|
||||
// Drop the request silently if PerformanceCounter has
|
||||
// set the flag.
|
||||
e.getFuture().setSuccess();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.handleDownstream(ctx, e);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the current ChannelPerformanceCounter set from the factory (if
|
||||
* channel is still connected) or null if this function was disabled
|
||||
* in the Factory
|
||||
*/
|
||||
public PerformanceCounter getChannelPerformanceCounter() {
|
||||
return this.channelPerformanceCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the GlobalPerformanceCounter from the factory or null if this
|
||||
* function was disabled in the Factory
|
||||
*/
|
||||
public PerformanceCounter getGlobalPerformanceCounter() {
|
||||
return this.globalPerformanceCounter;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,95 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of a Traffic Shaping Handler and Dynamic Statistics.<br>
|
||||
* <br><br>
|
||||
*
|
||||
*
|
||||
* <P>The main goal of this package is to allow to shape the traffic (bandwidth limitation),
|
||||
* but also to get statistics on how many bytes are read or written. Both functions can
|
||||
* be active or inactive (traffic or statistics).</P><br><br><br>
|
||||
*
|
||||
* <P>Three classes implement this behavior:<br><br>
|
||||
* <ul>
|
||||
* <li>) <tt>PerformanceCounter</tt>: this class is the kernel of the package. It can be accessed to get some extra information
|
||||
* like the read or write bytes since last check, the read and write bandwidth from last check...</li><br><br>
|
||||
*
|
||||
* <li>) <tt>PerformanceCounterFactory</tt>: this class has to be implemented in your code in order to implement (eventually empty)
|
||||
* the accounting method. This class is a Factory for PerformanceCounter which is used in the third class to create the
|
||||
* necessary PerformanceCounter according to your specifications.</li><br><br>
|
||||
*
|
||||
* <li>) <tt>TrafficShapingHandler</tt>: this class is the handler to be inserted in your pipeline. The insertion can be wherever
|
||||
* you want, but <b>it must be placed before any <tt>MemoryAwareThreadPoolExecutor</tt></b> in your pipeline.</li><br><br>
|
||||
* <b><i>It is really recommended
|
||||
* to have such a <tt>emoryAwareThreadPoolExecutor</tt> (either non ordered or <tt>OrderedMemoryAwareThreadPoolExecutor</tt>) in your pipeline</i></b>
|
||||
* when you want to use this feature with some real traffic shaping, since it will allow to relax the constraint on
|
||||
* NioWorker to do other jobs if necessary.<br>
|
||||
* Instead, if you don't, you can have the following situation: if there are more clients
|
||||
* connected and doing data transfer (either in read or write) than NioWorker, your global performance can be under your specifications or even
|
||||
* sometimes it will block for a while which can turn to "timeout" operations.
|
||||
* For instance, let says that you've got 2 NioWorkers, and 10 clients wants to send data to your server. If you set a bandwidth limitation
|
||||
* of 100KB/s for each channel (client), you could have a final limitation of about 60KB/s for each channel since NioWorkers are
|
||||
* stopping by this handler.<br><br>
|
||||
* The method <tt>getMessageSize(MessageEvent)</tt> has to be implemented to specify what is the size of the object to be read or write
|
||||
* accordingly to the type of object. In simple case, it can be as simple as a call to <tt>getChannelBufferMessageSize(MessageEvent)</tt>.<br>
|
||||
* </ul></P><br><br>
|
||||
*
|
||||
* <P>Standard use could be as follow:</P><br><br>
|
||||
*
|
||||
* <P>To activate or deactivate the traffic shaping, change the value corresponding to your desire as
|
||||
* [Global or per Channel] [Write or Read] Limitation in byte/s.</P><br>
|
||||
* <P><tt>PerformanceCounterFactory.NO_LIMIT</tt> (-1)
|
||||
* stands for no limitation, so the traffic shaping is deactivate (on what you specified).</P><br>
|
||||
* <P>You can either change those values with the method <tt>changeConfiguration</tt> in PerformanceCounterFactory or
|
||||
* directly from the PerformanceCounter method <tt>changeConfiguration</tt>.</P><br>
|
||||
* <br><br>
|
||||
*
|
||||
* <P>To activate or deactivate the statistics, you can adjust the delay to a low (not less than 200ms
|
||||
* for efficiency reasons) or a high value (let say 24H in ms is huge enough to not get the problem)
|
||||
* or even using <tt>PerformanceCounterFactory.NO_STAT</tt> (-1).</P><br>
|
||||
* <P>And if you don't want to do anything with this statistics, just implement an empty method for
|
||||
* <tt>PerformanceCounterFactory.accounting(PerformanceCounter)</tt>.</P><br>
|
||||
* <P>Again this can be changed either from PerformanceCounterFactory or directly in PerformanceCounter.</P><br><br><br>
|
||||
*
|
||||
* <P>You can also completely deactivate channel or global PerformanceCounter by setting the boolean to false
|
||||
* accordingly to your needs in the PerformanceCounterFactory. It will deactivate the global Monitor. For channels monitor,
|
||||
* it will prevent new monitors to be created (or reversely they will be created for newly connected channels).</P><br><br><br>
|
||||
*
|
||||
* <P>So in your application you will create your own PerformanceCounterFactory and setting the values to fit your needs.</P><br><br>
|
||||
* <tt>MyPerformanceCounterFactory myFactory = new MyPerformanceCounter(...);</tt><br><br><br>
|
||||
* <P>Then you can create your pipeline (using a PipelineFactory since each TrafficShapingHandler must be unique by channel) and adding this handler before
|
||||
* your MemoryAwareThreadPoolExecutor:</P><br><br>
|
||||
* <tt>pipeline.addLast("MyTrafficShaping",new MyTrafficShapingHandler(myFactory));</tt><br>
|
||||
* <tt>...</tt><br>
|
||||
* <tt>pipeline.addLast("MemoryExecutor",new ExecutionHandler(memoryAwareThreadPoolExecutor));</tt><br><br><br>
|
||||
*
|
||||
* <P>TrafficShapingHandler must be unique by channel but however it is still global due to
|
||||
* the PerformanceCounterFactcory that is shared between all handlers across the channels.</P><br><br>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @apiviz.exclude ^java\.lang\.
|
||||
*/
|
||||
package org.jboss.netty.handler.trafficshaping;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of a Traffic Shaping Handler and Dynamic Statistics.<br>
|
||||
* <br><br>
|
||||
*
|
||||
*
|
||||
* <P>The main goal of this package is to allow to shape the traffic (bandwidth limitation),
|
||||
* but also to get statistics on how many bytes are read or written. Both functions can
|
||||
* be active or inactive (traffic or statistics).</P><br><br><br>
|
||||
*
|
||||
* <P>Three classes implement this behavior:<br><br>
|
||||
* <ul>
|
||||
* <li>) <tt>PerformanceCounter</tt>: this class is the kernel of the package. It can be accessed to get some extra information
|
||||
* like the read or write bytes since last check, the read and write bandwidth from last check...</li><br><br>
|
||||
*
|
||||
* <li>) <tt>PerformanceCounterFactory</tt>: this class has to be implemented in your code in order to implement (eventually empty)
|
||||
* the accounting method. This class is a Factory for PerformanceCounter which is used in the third class to create the
|
||||
* necessary PerformanceCounter according to your specifications.</li><br><br>
|
||||
*
|
||||
* <li>) <tt>TrafficShapingHandler</tt>: this class is the handler to be inserted in your pipeline. The insertion can be wherever
|
||||
* you want, but <b>it must be placed before any <tt>MemoryAwareThreadPoolExecutor</tt></b> in your pipeline.</li><br><br>
|
||||
* <b><i>It is really recommended
|
||||
* to have such a <tt>emoryAwareThreadPoolExecutor</tt> (either non ordered or <tt>OrderedMemoryAwareThreadPoolExecutor</tt>) in your pipeline</i></b>
|
||||
* when you want to use this feature with some real traffic shaping, since it will allow to relax the constraint on
|
||||
* NioWorker to do other jobs if necessary.<br>
|
||||
* Instead, if you don't, you can have the following situation: if there are more clients
|
||||
* connected and doing data transfer (either in read or write) than NioWorker, your global performance can be under your specifications or even
|
||||
* sometimes it will block for a while which can turn to "timeout" operations.
|
||||
* For instance, let says that you've got 2 NioWorkers, and 10 clients wants to send data to your server. If you set a bandwidth limitation
|
||||
* of 100KB/s for each channel (client), you could have a final limitation of about 60KB/s for each channel since NioWorkers are
|
||||
* stopping by this handler.<br><br>
|
||||
* The method <tt>getMessageSize(MessageEvent)</tt> has to be implemented to specify what is the size of the object to be read or write
|
||||
* accordingly to the type of object. In simple case, it can be as simple as a call to <tt>getChannelBufferMessageSize(MessageEvent)</tt>.<br>
|
||||
* </ul></P><br><br>
|
||||
*
|
||||
* <P>Standard use could be as follow:</P><br><br>
|
||||
*
|
||||
* <P>To activate or deactivate the traffic shaping, change the value corresponding to your desire as
|
||||
* [Global or per Channel] [Write or Read] Limitation in byte/s.</P><br>
|
||||
* <P><tt>PerformanceCounterFactory.NO_LIMIT</tt> (-1)
|
||||
* stands for no limitation, so the traffic shaping is deactivate (on what you specified).</P><br>
|
||||
* <P>You can either change those values with the method <tt>changeConfiguration</tt> in PerformanceCounterFactory or
|
||||
* directly from the PerformanceCounter method <tt>changeConfiguration</tt>.</P><br>
|
||||
* <br><br>
|
||||
*
|
||||
* <P>To activate or deactivate the statistics, you can adjust the delay to a low (not less than 200ms
|
||||
* for efficiency reasons) or a high value (let say 24H in ms is huge enough to not get the problem)
|
||||
* or even using <tt>PerformanceCounterFactory.NO_STAT</tt> (-1).</P><br>
|
||||
* <P>And if you don't want to do anything with this statistics, just implement an empty method for
|
||||
* <tt>PerformanceCounterFactory.accounting(PerformanceCounter)</tt>.</P><br>
|
||||
* <P>Again this can be changed either from PerformanceCounterFactory or directly in PerformanceCounter.</P><br><br><br>
|
||||
*
|
||||
* <P>You can also completely deactivate channel or global PerformanceCounter by setting the boolean to false
|
||||
* accordingly to your needs in the PerformanceCounterFactory. It will deactivate the global Monitor. For channels monitor,
|
||||
* it will prevent new monitors to be created (or reversely they will be created for newly connected channels).</P><br><br><br>
|
||||
*
|
||||
* <P>So in your application you will create your own PerformanceCounterFactory and setting the values to fit your needs.</P><br><br>
|
||||
* <tt>MyPerformanceCounterFactory myFactory = new MyPerformanceCounter(...);</tt><br><br><br>
|
||||
* <P>Then you can create your pipeline (using a PipelineFactory since each TrafficShapingHandler must be unique by channel) and adding this handler before
|
||||
* your MemoryAwareThreadPoolExecutor:</P><br><br>
|
||||
* <tt>pipeline.addLast("MyTrafficShaping",new MyTrafficShapingHandler(myFactory));</tt><br>
|
||||
* <tt>...</tt><br>
|
||||
* <tt>pipeline.addLast("MemoryExecutor",new ExecutionHandler(memoryAwareThreadPoolExecutor));</tt><br><br><br>
|
||||
*
|
||||
* <P>TrafficShapingHandler must be unique by channel but however it is still global due to
|
||||
* the PerformanceCounterFactcory that is shared between all handlers across the channels.</P><br><br>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @apiviz.exclude ^java\.lang\.
|
||||
*/
|
||||
package org.jboss.netty.handler.trafficshaping;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user