Changed package from org.dna.mqtt to orga.eclipse.moquette
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.text.ParseException;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.moquette.commons.Constants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Mosquitto configuration parser.
|
||||
*
|
||||
* A line that at the very first has # is a comment
|
||||
* Each line has key value format, where the separator used it the space.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
class ConfigurationParser {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationParser.class);
|
||||
|
||||
private Properties m_properties = new Properties();
|
||||
|
||||
ConfigurationParser() {
|
||||
m_properties.put("port", Integer.toString(Constants.PORT));
|
||||
m_properties.put("host", Constants.HOST);
|
||||
m_properties.put("websocket_port", Integer.toString(Constants.WEBSOCKET_PORT));
|
||||
m_properties.put("password_file", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the configuration from file.
|
||||
*/
|
||||
void parse(File file) throws ParseException {
|
||||
if (file == null) {
|
||||
LOG.warn("parsing NULL file, so fallback on default configuration!");
|
||||
return;
|
||||
}
|
||||
if (!file.exists()) {
|
||||
LOG.warn(String.format("parsing not existing file %s, so fallback on default configuration!", file.getAbsolutePath()));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
FileReader reader = new FileReader(file);
|
||||
parse(reader);
|
||||
} catch (FileNotFoundException fex) {
|
||||
LOG.warn(String.format("parsing not existing file %s, so fallback on default configuration!", file.getAbsolutePath()), fex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the configuration
|
||||
*
|
||||
* @throws ParseException if the format is not compliant.
|
||||
*/
|
||||
void parse(Reader reader) throws ParseException {
|
||||
if (reader == null) {
|
||||
//just log and return default properties
|
||||
LOG.warn("parsing NULL reader, so fallback on default configuration!");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedReader br = new BufferedReader(reader);
|
||||
String line;
|
||||
try {
|
||||
while ((line = br.readLine()) != null) {
|
||||
int commentMarker = line.indexOf('#');
|
||||
if (commentMarker != -1) {
|
||||
if (commentMarker == 0) {
|
||||
//skip its a comment
|
||||
continue;
|
||||
} else {
|
||||
//it's a malformed comment
|
||||
throw new ParseException(line, commentMarker);
|
||||
}
|
||||
} else {
|
||||
if (line.isEmpty() || line.matches("^\\s*$")) {
|
||||
//skip it's a black line
|
||||
continue;
|
||||
}
|
||||
|
||||
//split till the first space
|
||||
int deilimiterIdx = line.indexOf(' ');
|
||||
String key = line.substring(0, deilimiterIdx).trim();
|
||||
String value = line.substring(deilimiterIdx).trim();
|
||||
|
||||
m_properties.put(key, value);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new ParseException("Failed to read", 1);
|
||||
}
|
||||
}
|
||||
|
||||
Properties getProperties() {
|
||||
return m_properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
/**
|
||||
* Maintains the information of single connection, like ClientID, IoSession,
|
||||
* and other connection related flags.
|
||||
*
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ConnectionDescriptor {
|
||||
|
||||
private String m_clientID;
|
||||
private ServerChannel m_session;
|
||||
private boolean m_cleanSession;
|
||||
|
||||
public ConnectionDescriptor(String clientID, ServerChannel session, boolean cleanSession) {
|
||||
this.m_clientID = clientID;
|
||||
this.m_session = session;
|
||||
this.m_cleanSession = cleanSession;
|
||||
}
|
||||
|
||||
public boolean isCleanSession() {
|
||||
return m_cleanSession;
|
||||
}
|
||||
|
||||
public String getClientID() {
|
||||
return m_clientID;
|
||||
}
|
||||
|
||||
public ServerChannel getSession() {
|
||||
return m_session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionDescriptor{" + "m_clientID=" + m_clientID + ", m_cleanSession=" + m_cleanSession + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
/**
|
||||
* Server constants keeper
|
||||
*/
|
||||
public class Constants {
|
||||
public static final String ATTR_CLIENTID = "ClientID";
|
||||
public static final String CLEAN_SESSION = "cleanSession";
|
||||
public static final String KEEP_ALIVE = "keepAlive";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
/**
|
||||
* username and password checker
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public interface IAuthenticator {
|
||||
|
||||
boolean checkValid(String username, String password);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.moquette.spi.impl.SimpleMessaging;
|
||||
import org.eclipse.moquette.server.netty.NettyAcceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
/**
|
||||
* Launch a configured version of the server.
|
||||
* @author andrea
|
||||
*/
|
||||
public class Server {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Server.class);
|
||||
|
||||
public static final String STORAGE_FILE_PATH = System.getProperty("user.home") +
|
||||
File.separator + "moquette_store.mapdb";
|
||||
|
||||
private ServerAcceptor m_acceptor;
|
||||
SimpleMessaging messaging;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
final Server server = new Server();
|
||||
server.startServer();
|
||||
System.out.println("Server started, version 0.7-SNAPSHOT");
|
||||
//Bind a shutdown hook
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
server.stopServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts Moquette bringing the configuration from the file
|
||||
* located at config/moquette.conf
|
||||
*/
|
||||
public void startServer() throws IOException {
|
||||
String configPath = System.getProperty("moquette.path", null);
|
||||
startServer(new File(configPath, "config/moquette.conf"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts Moquette bringing the configuration from the given file
|
||||
*/
|
||||
public void startServer(File configFile) throws IOException {
|
||||
ConfigurationParser confParser = new ConfigurationParser();
|
||||
try {
|
||||
confParser.parse(configFile);
|
||||
} catch (ParseException pex) {
|
||||
LOG.warn("An error occurred in parsing configuration, fallback on default configuration", pex);
|
||||
}
|
||||
Properties configProps = confParser.getProperties();
|
||||
startServer(configProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server with the given properties.
|
||||
*
|
||||
* Its need at least the following properties:
|
||||
* <ul>
|
||||
* <li>port</li>
|
||||
* <li>password_file</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void startServer(Properties configProps) throws IOException {
|
||||
messaging = SimpleMessaging.getInstance();
|
||||
messaging.init(configProps);
|
||||
|
||||
m_acceptor = new NettyAcceptor();
|
||||
m_acceptor.initialize(messaging, configProps);
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
System.out.println("Server stopping...");
|
||||
messaging.stop();
|
||||
m_acceptor.close();
|
||||
System.out.println("Server stopped");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import org.eclipse.moquette.spi.IMessaging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public interface ServerAcceptor {
|
||||
|
||||
void initialize(IMessaging messaging, Properties props) throws IOException;
|
||||
|
||||
void close();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public interface ServerChannel {
|
||||
|
||||
Object getAttribute(Object key);
|
||||
|
||||
void setAttribute(Object key, Object value);
|
||||
|
||||
void setIdleTime(int idleTime);
|
||||
|
||||
void close(boolean immediately);
|
||||
|
||||
void write(Object value);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty;
|
||||
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
|
||||
class MoquetteIdleTimoutHandler extends ChannelDuplexHandler {
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (evt instanceof IdleStateEvent) {
|
||||
IdleState e = ((IdleStateEvent) evt).state();
|
||||
if (e == IdleState.ALL_IDLE) {
|
||||
//fire a channelInactive to trigger publish of Will
|
||||
ctx.fireChannelInactive();
|
||||
ctx.close();
|
||||
} /*else if (e.getState() == IdleState.WRITER_IDLE) {
|
||||
ctx.writeAndFlush(new PingMessage());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import org.eclipse.moquette.commons.Constants;
|
||||
import org.eclipse.moquette.spi.IMessaging;
|
||||
import org.eclipse.moquette.parser.netty.MQTTDecoder;
|
||||
import org.eclipse.moquette.parser.netty.MQTTEncoder;
|
||||
import org.eclipse.moquette.server.ServerAcceptor;
|
||||
import org.eclipse.moquette.server.netty.metrics.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class NettyAcceptor implements ServerAcceptor {
|
||||
|
||||
static class WebSocketFrameToByteBufDecoder extends MessageToMessageDecoder<BinaryWebSocketFrame> {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext chc, BinaryWebSocketFrame frame, List<Object> out) throws Exception {
|
||||
//convert the frame to a ByteBuf
|
||||
ByteBuf bb = frame.content();
|
||||
out.add(bb);
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteBufToWebSocketFrameEncoder extends MessageToMessageEncoder<ByteBuf> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext chc, ByteBuf bb, List<Object> out) throws Exception {
|
||||
//convert the ByteBuf to a WebSocketFrame
|
||||
BinaryWebSocketFrame result = new BinaryWebSocketFrame(bb);
|
||||
out.add(bb);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PipelineInitializer {
|
||||
|
||||
abstract void init(ChannelPipeline pipeline) throws Exception;
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NettyAcceptor.class);
|
||||
|
||||
EventLoopGroup m_bossGroup;
|
||||
EventLoopGroup m_workerGroup;
|
||||
//BytesMetricsCollector m_metricsCollector = new BytesMetricsCollector();
|
||||
MessageMetricsCollector m_metricsCollector = new MessageMetricsCollector();
|
||||
|
||||
@Override
|
||||
public void initialize(IMessaging messaging, Properties props) throws IOException {
|
||||
m_bossGroup = new NioEventLoopGroup();
|
||||
m_workerGroup = new NioEventLoopGroup();
|
||||
|
||||
initializePlainTCPTransport(messaging, props);
|
||||
initializeWebSocketTransport(messaging, props);
|
||||
initializeSSLTCPTransport(messaging, props);
|
||||
}
|
||||
|
||||
private void initFactory(String host, int port, final PipelineInitializer pipeliner) {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(m_bossGroup, m_workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeliner.init(pipeline);
|
||||
}
|
||||
})
|
||||
.option(ChannelOption.SO_BACKLOG, 128)
|
||||
.option(ChannelOption.SO_REUSEADDR, true)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
try {
|
||||
// Bind and start to accept incoming connections.
|
||||
ChannelFuture f = b.bind(host, port);
|
||||
LOG.info("Server binded");
|
||||
f.sync();
|
||||
} catch (InterruptedException ex) {
|
||||
LOG.error(null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializePlainTCPTransport(IMessaging messaging, Properties props) throws IOException {
|
||||
final NettyMQTTHandler handler = new NettyMQTTHandler();
|
||||
handler.setMessaging(messaging);
|
||||
String host = props.getProperty("host");
|
||||
int port = Integer.parseInt(props.getProperty("port"));
|
||||
initFactory(host, port, new PipelineInitializer() {
|
||||
@Override
|
||||
void init(ChannelPipeline pipeline) {
|
||||
pipeline.addFirst("idleStateHandler", new IdleStateHandler(0, 0, Constants.DEFAULT_CONNECT_TIMEOUT));
|
||||
pipeline.addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimoutHandler());
|
||||
//pipeline.addLast("logger", new LoggingHandler("Netty", LogLevel.ERROR));
|
||||
pipeline.addLast("decoder", new MQTTDecoder());
|
||||
pipeline.addLast("encoder", new MQTTEncoder());
|
||||
pipeline.addLast("metrics", new MessageMetricsHandler(m_metricsCollector));
|
||||
pipeline.addLast("handler", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeWebSocketTransport(IMessaging messaging, Properties props) throws IOException {
|
||||
String webSocketPortProp = props.getProperty("websocket_port");
|
||||
if (webSocketPortProp == null) {
|
||||
//Do nothing no WebSocket configured
|
||||
LOG.info("WebSocket is disabled");
|
||||
return;
|
||||
}
|
||||
int port = Integer.parseInt(webSocketPortProp);
|
||||
|
||||
final NettyMQTTHandler handler = new NettyMQTTHandler();
|
||||
handler.setMessaging(messaging);
|
||||
|
||||
String host = props.getProperty("host");
|
||||
initFactory(host, port, new PipelineInitializer() {
|
||||
@Override
|
||||
void init(ChannelPipeline pipeline) {
|
||||
pipeline.addLast("httpEncoder", new HttpResponseEncoder());
|
||||
pipeline.addLast("httpDdecoder", new HttpRequestDecoder());
|
||||
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
|
||||
pipeline.addLast("webSocketHandler", new WebSocketServerProtocolHandler("/mqtt", "mqttv3.1"));
|
||||
pipeline.addLast("bytebuf2wsDecoderr", new ByteBufToWebSocketFrameEncoder());
|
||||
pipeline.addLast("ws2bytebufDecoder", new WebSocketFrameToByteBufDecoder());
|
||||
pipeline.addLast("decoder", new MQTTDecoder());
|
||||
pipeline.addLast("encoder", new MQTTEncoder());
|
||||
pipeline.addLast("metrics", new MessageMetricsHandler(m_metricsCollector));
|
||||
pipeline.addLast("handler", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initializeSSLTCPTransport(IMessaging messaging, Properties props) throws IOException {
|
||||
String sslPortProp = props.getProperty("ssl_port");
|
||||
if (sslPortProp == null) {
|
||||
//Do nothing no SSL configured
|
||||
LOG.info("SSL is disabled");
|
||||
return;
|
||||
}
|
||||
final String jksPath = props.getProperty("jks_path");
|
||||
if (jksPath == null || jksPath.isEmpty()) {
|
||||
//key_store_password or key_manager_password are empty
|
||||
LOG.warn("You have configured the SSL port but not the jks_path, SSL not started");
|
||||
return;
|
||||
}
|
||||
|
||||
//if we have the port also the jks then keyStorePassword and keyManagerPassword
|
||||
//has to be defined
|
||||
final String keyStorePassword = props.getProperty("key_store_password");
|
||||
final String keyManagerPassword = props.getProperty("key_manager_password");
|
||||
if (keyStorePassword == null || keyStorePassword.isEmpty()) {
|
||||
//key_store_password or key_manager_password are empty
|
||||
LOG.warn("You have configured the SSL port but not the key_store_password, SSL not started");
|
||||
return;
|
||||
}
|
||||
if (keyManagerPassword == null || keyManagerPassword.isEmpty()) {
|
||||
//key_manager_password or key_manager_password are empty
|
||||
LOG.warn("You have configured the SSL port but not the key_manager_password, SSL not started");
|
||||
return;
|
||||
}
|
||||
|
||||
int sslPort = Integer.parseInt(sslPortProp);
|
||||
String host = props.getProperty("host");
|
||||
|
||||
final NettyMQTTHandler handler = new NettyMQTTHandler();
|
||||
handler.setMessaging(messaging);
|
||||
initFactory(host, sslPort, new PipelineInitializer() {
|
||||
@Override
|
||||
void init(ChannelPipeline pipeline) throws Exception {
|
||||
InputStream jksInputStream = getClass().getClassLoader().getResourceAsStream(jksPath);
|
||||
SSLContext serverContext = SSLContext.getInstance("TLS");
|
||||
final KeyStore ks = KeyStore.getInstance("JKS");
|
||||
ks.load(jksInputStream, keyStorePassword.toCharArray());
|
||||
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(ks, keyManagerPassword.toCharArray());
|
||||
serverContext.init(kmf.getKeyManagers(), null, null);
|
||||
|
||||
SSLEngine engine = serverContext.createSSLEngine();
|
||||
engine.setUseClientMode(false);
|
||||
final SslHandler sslHandler = new SslHandler(engine);
|
||||
|
||||
pipeline.addLast("ssl", sslHandler);
|
||||
//pipeline.addFirst("metrics", new BytesMetricsHandler(m_metricsCollector));
|
||||
pipeline.addFirst("idleStateHandler", new IdleStateHandler(0, 0, Constants.DEFAULT_CONNECT_TIMEOUT));
|
||||
pipeline.addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimoutHandler());
|
||||
//pipeline.addLast("logger", new LoggingHandler("Netty", LogLevel.ERROR));
|
||||
pipeline.addLast("decoder", new MQTTDecoder());
|
||||
pipeline.addLast("encoder", new MQTTEncoder());
|
||||
pipeline.addLast("metrics", new MessageMetricsHandler(m_metricsCollector));
|
||||
pipeline.addLast("handler", handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (m_workerGroup == null) {
|
||||
throw new IllegalStateException("Invoked close on an Acceptor that wasn't initialized");
|
||||
}
|
||||
if (m_bossGroup == null) {
|
||||
throw new IllegalStateException("Invoked close on an Acceptor that wasn't initialized");
|
||||
}
|
||||
m_workerGroup.shutdownGracefully();
|
||||
m_bossGroup.shutdownGracefully();
|
||||
|
||||
MessageMetrics metrics = m_metricsCollector.computeMetrics();
|
||||
//LOG.info(String.format("Bytes read: %d, bytes wrote: %d", metrics.readBytes(), metrics.wroteBytes()));
|
||||
LOG.info("Msg read: {}, msg wrote: {}", metrics.messagesRead(), metrics.messagesWrote());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.eclipse.moquette.server.Constants;
|
||||
import org.eclipse.moquette.server.ServerChannel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class NettyChannel implements ServerChannel {
|
||||
|
||||
private ChannelHandlerContext m_channel;
|
||||
|
||||
private Map<Object, AttributeKey<Object>> m_attributesKeys = new HashMap<Object, AttributeKey<Object>>();
|
||||
|
||||
private static final AttributeKey<Object> ATTR_KEY_KEEPALIVE = new AttributeKey<Object>(Constants.KEEP_ALIVE);
|
||||
private static final AttributeKey<Object> ATTR_KEY_CLEANSESSION = new AttributeKey<Object>(Constants.CLEAN_SESSION);
|
||||
private static final AttributeKey<Object> ATTR_KEY_CLIENTID = new AttributeKey<Object>(Constants.ATTR_CLIENTID);
|
||||
|
||||
NettyChannel(ChannelHandlerContext ctx) {
|
||||
m_channel = ctx;
|
||||
m_attributesKeys.put(Constants.KEEP_ALIVE, ATTR_KEY_KEEPALIVE);
|
||||
m_attributesKeys.put(Constants.CLEAN_SESSION, ATTR_KEY_CLEANSESSION);
|
||||
m_attributesKeys.put(Constants.ATTR_CLIENTID, ATTR_KEY_CLIENTID);
|
||||
}
|
||||
|
||||
public Object getAttribute(Object key) {
|
||||
Attribute<Object> attr = m_channel.attr(mapKey(key));
|
||||
return attr.get();
|
||||
}
|
||||
|
||||
public void setAttribute(Object key, Object value) {
|
||||
Attribute<Object> attr = m_channel.attr(mapKey(key));
|
||||
attr.set(value);
|
||||
}
|
||||
|
||||
private synchronized AttributeKey<Object> mapKey(Object key) {
|
||||
if (!m_attributesKeys.containsKey(key)) {
|
||||
throw new IllegalArgumentException("mapKey can't find a matching AttributeKey for " + key);
|
||||
}
|
||||
return m_attributesKeys.get(key);
|
||||
}
|
||||
|
||||
public void setIdleTime(int idleTime) {
|
||||
if (m_channel.pipeline().names().contains("idleStateHandler")) {
|
||||
m_channel.pipeline().remove("idleStateHandler");
|
||||
}
|
||||
if (m_channel.pipeline().names().contains("idleEventHandler")) {
|
||||
m_channel.pipeline().remove("idleEventHandler");
|
||||
}
|
||||
m_channel.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, idleTime));
|
||||
m_channel.pipeline().addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimoutHandler());
|
||||
}
|
||||
|
||||
public void close(boolean immediately) {
|
||||
m_channel.close();
|
||||
}
|
||||
|
||||
public void write(Object value) {
|
||||
m_channel.writeAndFlush(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.eclipse.moquette.spi.IMessaging;
|
||||
import org.eclipse.moquette.proto.Utils;
|
||||
import org.eclipse.moquette.proto.messages.AbstractMessage;
|
||||
import static org.eclipse.moquette.proto.messages.AbstractMessage.*;
|
||||
import org.eclipse.moquette.proto.messages.PingRespMessage;
|
||||
import org.eclipse.moquette.server.Constants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
@Sharable
|
||||
public class NettyMQTTHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NettyMQTTHandler.class);
|
||||
private IMessaging m_messaging;
|
||||
private final Map<ChannelHandlerContext, NettyChannel> m_channelMapper = new HashMap<ChannelHandlerContext, NettyChannel>();
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object message) {
|
||||
AbstractMessage msg = (AbstractMessage) message;
|
||||
LOG.info("Received a message of type {}", Utils.msgType2String(msg.getMessageType()));
|
||||
try {
|
||||
switch (msg.getMessageType()) {
|
||||
case CONNECT:
|
||||
case SUBSCRIBE:
|
||||
case UNSUBSCRIBE:
|
||||
case PUBLISH:
|
||||
case PUBREC:
|
||||
case PUBCOMP:
|
||||
case PUBREL:
|
||||
case DISCONNECT:
|
||||
case PUBACK:
|
||||
NettyChannel channel;
|
||||
synchronized(m_channelMapper) {
|
||||
if (!m_channelMapper.containsKey(ctx)) {
|
||||
m_channelMapper.put(ctx, new NettyChannel(ctx));
|
||||
}
|
||||
channel = m_channelMapper.get(ctx);
|
||||
}
|
||||
|
||||
m_messaging.handleProtocolMessage(channel, msg);
|
||||
break;
|
||||
case PINGREQ:
|
||||
PingRespMessage pingResp = new PingRespMessage();
|
||||
ctx.writeAndFlush(pingResp);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Bad error in processing the message", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
NettyChannel channel = m_channelMapper.get(ctx);
|
||||
String clientID = (String) channel.getAttribute(Constants.ATTR_CLIENTID);
|
||||
m_messaging.lostConnection(clientID);
|
||||
ctx.close(/*false*/);
|
||||
synchronized(m_channelMapper) {
|
||||
m_channelMapper.remove(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMessaging(IMessaging messaging) {
|
||||
m_messaging = messaging;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
public class BytesMetrics {
|
||||
private long m_readBytes = 0;
|
||||
private long m_wroteBytes = 0;
|
||||
|
||||
void incrementRead(long numBytes) {
|
||||
m_readBytes += numBytes;
|
||||
}
|
||||
|
||||
void incrementWrote(long numBytes) {
|
||||
m_wroteBytes += numBytes;
|
||||
}
|
||||
|
||||
public long readBytes() {
|
||||
return m_readBytes;
|
||||
}
|
||||
|
||||
public long wroteBytes() {
|
||||
return m_wroteBytes;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* Collects all the metrics from the various pipeline.
|
||||
*/
|
||||
public class BytesMetricsCollector {
|
||||
private Queue<BytesMetrics> m_allMetrics = new ConcurrentLinkedQueue<BytesMetrics>();
|
||||
|
||||
void addMetrics(BytesMetrics metrics) {
|
||||
m_allMetrics.add(metrics);
|
||||
}
|
||||
|
||||
public BytesMetrics computeMetrics() {
|
||||
BytesMetrics allMetrics = new BytesMetrics();
|
||||
for (BytesMetrics m : m_allMetrics) {
|
||||
allMetrics.incrementRead(m.readBytes());
|
||||
allMetrics.incrementWrote(m.wroteBytes());
|
||||
}
|
||||
return allMetrics;
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
public class BytesMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final AttributeKey<BytesMetrics> ATTR_KEY_METRICS = new AttributeKey<BytesMetrics>("BytesMetrics");
|
||||
|
||||
private BytesMetricsCollector m_collector;
|
||||
|
||||
public BytesMetricsHandler(BytesMetricsCollector collector) {
|
||||
m_collector = collector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
Attribute<BytesMetrics> attr = ctx.attr(ATTR_KEY_METRICS);
|
||||
attr.set(new BytesMetrics());
|
||||
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
BytesMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementRead(((ByteBuf)msg).readableBytes());
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
BytesMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementWrote(((ByteBuf)msg).writableBytes());
|
||||
ctx.write(msg, promise);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx,
|
||||
ChannelPromise promise) throws Exception {
|
||||
BytesMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
m_collector.addMetrics(metrics);
|
||||
super.close(ctx, promise);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
public class MessageMetrics {
|
||||
private long m_messagesRead = 0;
|
||||
private long m_messageWrote = 0;
|
||||
|
||||
void incrementRead(long numMessages) {
|
||||
m_messagesRead += numMessages;
|
||||
}
|
||||
|
||||
void incrementWrote(long numMessages) {
|
||||
m_messageWrote += numMessages;
|
||||
}
|
||||
|
||||
public long messagesRead() {
|
||||
return m_messagesRead;
|
||||
}
|
||||
|
||||
public long messagesWrote() {
|
||||
return m_messageWrote;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* Collects all the metrics from the various pipeline.
|
||||
*/
|
||||
public class MessageMetricsCollector {
|
||||
private Queue<MessageMetrics> m_allMetrics = new ConcurrentLinkedQueue<MessageMetrics>();
|
||||
|
||||
void addMetrics(MessageMetrics metrics) {
|
||||
m_allMetrics.add(metrics);
|
||||
}
|
||||
|
||||
public MessageMetrics computeMetrics() {
|
||||
MessageMetrics allMetrics = new MessageMetrics();
|
||||
for (MessageMetrics m : m_allMetrics) {
|
||||
allMetrics.incrementRead(m.messagesRead());
|
||||
allMetrics.incrementWrote(m.messagesWrote());
|
||||
}
|
||||
return allMetrics;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2014 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* The Apache License v2.0 is available at
|
||||
* http://www.opensource.org/licenses/apache2.0.php
|
||||
*
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*/
|
||||
package org.eclipse.moquette.server.netty.metrics;
|
||||
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
public class MessageMetricsHandler extends ChannelDuplexHandler {
|
||||
|
||||
private static final AttributeKey<MessageMetrics> ATTR_KEY_METRICS = new AttributeKey<MessageMetrics>("MessageMetrics");
|
||||
|
||||
private MessageMetricsCollector m_collector;
|
||||
|
||||
public MessageMetricsHandler(MessageMetricsCollector collector) {
|
||||
m_collector = collector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
Attribute<MessageMetrics> attr = ctx.attr(ATTR_KEY_METRICS);
|
||||
attr.set(new MessageMetrics());
|
||||
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
MessageMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementRead(1);
|
||||
ctx.fireChannelRead(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
MessageMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
metrics.incrementWrote(1);
|
||||
ctx.write(msg, promise);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close(ChannelHandlerContext ctx,
|
||||
ChannelPromise promise) throws Exception {
|
||||
MessageMetrics metrics = ctx.attr(ATTR_KEY_METRICS).get();
|
||||
m_collector.addMetrics(metrics);
|
||||
super.close(ctx, promise);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user