attribute = channel.attr(ATTR_KEY_METRICS);
50 | BytesMetrics metrics = attribute.get();
51 | if (metrics == null) {
52 | metrics = new BytesMetrics();
53 | attribute.set(metrics);
54 | }
55 | return metrics;
56 | }
57 |
58 | @Override
59 | public void onMessageReceived(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
60 | BytesMetrics metrics = getOrSetMetrics(ctx.channel());
61 | metrics.incrementRead(msg.readableBytes());
62 | ctx.fireChannelRead(msg);
63 | }
64 |
65 | @Override
66 | protected void onMessageWriter(ChannelHandlerContext ctx, ByteBuf msg, ChannelPromise promise) throws Exception {
67 | BytesMetrics metrics = getOrSetMetrics(ctx.channel());
68 | metrics.incrementWrote(msg.writableBytes());
69 | if (promise.isVoid()) {
70 | ctx.write(msg, promise);
71 | } else {
72 | ctx.write(msg, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
73 | }
74 | }
75 |
76 | @Override
77 | public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
78 | BytesMetrics metrics = getOrSetMetrics(ctx.channel());
79 | readBytes.getAndAdd(metrics.bytesRead());
80 | writeBytes.getAndAdd(metrics.bytesWrote());
81 | ctx.close(promise);
82 | }
83 |
84 | public static class BytesMetrics {
85 |
86 | private long m_bytesRead;
87 | private long m_bytesWrote;
88 |
89 | void incrementRead(long numBytes) {
90 | m_bytesRead += numBytes;
91 | }
92 |
93 | void incrementWrote(long numBytes) {
94 | m_bytesWrote += numBytes;
95 | }
96 |
97 | public long bytesRead() {
98 | return m_bytesRead;
99 | }
100 |
101 | public long bytesWrote() {
102 | return m_bytesWrote;
103 | }
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/CaseInsensitiveKeyMap.java:
--------------------------------------------------------------------------------
1 | package com.github.netty.core.util;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * 不敏感大小写的map
7 | *
8 | * A Map implementation that uses case-insensitive (using {@link
9 | * Locale#ENGLISH}) strings as keys.
10 | *
11 | * Keys must be instances of {@link String}. Note that this means that
12 | * null
keys are not permitted.
13 | *
14 | * This implementation is not thread-safe.
15 | *
16 | * @param Type of values placed in this Map.
17 | */
18 | public class CaseInsensitiveKeyMap extends AbstractMap {
19 | private final Map map;
20 |
21 | public CaseInsensitiveKeyMap() {
22 | this.map = new LinkedHashMap<>();
23 | }
24 |
25 | public CaseInsensitiveKeyMap(int initialCapacity) {
26 | map = new LinkedHashMap<>(initialCapacity);
27 | }
28 |
29 | @Override
30 | public V get(Object key) {
31 | return map.get(Key.getInstance(key));
32 | }
33 |
34 | @Override
35 | public V put(String key, V value) {
36 | Key caseInsensitiveKey = Key.getInstance(key);
37 | if (caseInsensitiveKey == null) {
38 | throw new NullPointerException();
39 | }
40 | return map.put(caseInsensitiveKey, value);
41 | }
42 |
43 |
44 | /**
45 | * {@inheritDoc}
46 | *
47 | * Use this method with caution. If the input Map contains duplicate
48 | * keys when the keys are compared in a case insensitive manner then some
49 | * values will be lost when inserting via this method.
50 | */
51 | @Override
52 | public void putAll(Map extends String, ? extends V> m) {
53 | super.putAll(m);
54 | }
55 |
56 |
57 | @Override
58 | public boolean containsKey(Object key) {
59 | return map.containsKey(Key.getInstance(key));
60 | }
61 |
62 |
63 | @Override
64 | public V remove(Object key) {
65 | return map.remove(Key.getInstance(key));
66 | }
67 |
68 |
69 | @Override
70 | public Set> entrySet() {
71 | return new EntrySet<>(map.entrySet());
72 | }
73 |
74 |
75 | private static class EntrySet extends AbstractSet> {
76 |
77 | private final Set> entrySet;
78 |
79 | public EntrySet(Set> entrySet) {
80 | this.entrySet = entrySet;
81 | }
82 |
83 | @Override
84 | public Iterator> iterator() {
85 | return new EntryIterator<>(entrySet.iterator());
86 | }
87 |
88 | @Override
89 | public int size() {
90 | return entrySet.size();
91 | }
92 | }
93 |
94 |
95 | private static class EntryIterator implements Iterator> {
96 |
97 | private final Iterator> iterator;
98 |
99 | public EntryIterator(Iterator> iterator) {
100 | this.iterator = iterator;
101 | }
102 |
103 | @Override
104 | public boolean hasNext() {
105 | return iterator.hasNext();
106 | }
107 |
108 | @Override
109 | public Entry next() {
110 | Entry entry = iterator.next();
111 | return new EntryImpl<>(entry.getKey().getKey(), entry.getValue());
112 | }
113 |
114 | @Override
115 | public void remove() {
116 | iterator.remove();
117 | }
118 | }
119 |
120 |
121 | private static class EntryImpl implements Entry {
122 |
123 | private final String key;
124 | private final V value;
125 |
126 | public EntryImpl(String key, V value) {
127 | this.key = key;
128 | this.value = value;
129 | }
130 |
131 | @Override
132 | public String getKey() {
133 | return key;
134 | }
135 |
136 | @Override
137 | public V getValue() {
138 | return value;
139 | }
140 |
141 | @Override
142 | public V setValue(V value) {
143 | throw new UnsupportedOperationException();
144 | }
145 | }
146 |
147 | private static class Key {
148 |
149 | private final String key;
150 | private final String lcKey;
151 |
152 | private Key(String key) {
153 | this.key = key;
154 | this.lcKey = key.toLowerCase(Locale.ENGLISH);
155 | }
156 |
157 | public static Key getInstance(Object o) {
158 | if (o instanceof String) {
159 | return new Key((String) o);
160 | }
161 | return null;
162 | }
163 |
164 | public String getKey() {
165 | return key;
166 | }
167 |
168 | @Override
169 | public int hashCode() {
170 | return lcKey.hashCode();
171 | }
172 |
173 | @Override
174 | public boolean equals(Object obj) {
175 | if (this == obj) {
176 | return true;
177 | }
178 | if (obj == null) {
179 | return false;
180 | }
181 | if (getClass() != obj.getClass()) {
182 | return false;
183 | }
184 | Key other = (Key) obj;
185 | return lcKey.equals(other.lcKey);
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/JVMUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.netty.core.util;
2 |
3 | import java.io.OutputStream;
4 | import java.lang.management.*;
5 |
6 | public class JVMUtil {
7 |
8 | public static void jstack(OutputStream stream) throws Exception {
9 | ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
10 | for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, true)) {
11 | stream.write(getThreadDumpString(threadInfo).getBytes());
12 | }
13 | }
14 |
15 | private static String getThreadDumpString(ThreadInfo threadInfo) {
16 | StringBuilder sb = new StringBuilder("\"" + threadInfo.getThreadName() + "\"" +
17 | " Id=" + threadInfo.getThreadId() + " " +
18 | threadInfo.getThreadState());
19 | if (threadInfo.getLockName() != null) {
20 | sb.append(" on ").append(threadInfo.getLockName());
21 | }
22 | if (threadInfo.getLockOwnerName() != null) {
23 | sb.append(" owned by \"").append(threadInfo.getLockOwnerName()).append("\" Id=").append(threadInfo.getLockOwnerId());
24 | }
25 | if (threadInfo.isSuspended()) {
26 | sb.append(" (suspended)");
27 | }
28 | if (threadInfo.isInNative()) {
29 | sb.append(" (in native)");
30 | }
31 | sb.append('\n');
32 | int i = 0;
33 |
34 | StackTraceElement[] stackTrace = threadInfo.getStackTrace();
35 | MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors();
36 | for (; i < stackTrace.length && i < 32; i++) {
37 | StackTraceElement ste = stackTrace[i];
38 | sb.append("\tat ").append(ste.toString());
39 | sb.append('\n');
40 | if (i == 0 && threadInfo.getLockInfo() != null) {
41 | Thread.State ts = threadInfo.getThreadState();
42 | switch (ts) {
43 | case BLOCKED:
44 | sb.append("\t- blocked on ").append(threadInfo.getLockInfo());
45 | sb.append('\n');
46 | break;
47 | case WAITING:
48 | sb.append("\t- waiting on ").append(threadInfo.getLockInfo());
49 | sb.append('\n');
50 | break;
51 | case TIMED_WAITING:
52 | sb.append("\t- timed waiting on ").append(threadInfo.getLockInfo());
53 | sb.append('\n');
54 | break;
55 | default:
56 | }
57 | }
58 |
59 | for (MonitorInfo mi : lockedMonitors) {
60 | if (mi.getLockedStackDepth() == i) {
61 | sb.append("\t- locked ").append(mi);
62 | sb.append('\n');
63 | }
64 | }
65 | }
66 | if (i < stackTrace.length) {
67 | sb.append("\t...");
68 | sb.append('\n');
69 | }
70 |
71 | LockInfo[] locks = threadInfo.getLockedSynchronizers();
72 | if (locks.length > 0) {
73 | sb.append("\n\tNumber of locked synchronizers = ").append(locks.length);
74 | sb.append('\n');
75 | for (LockInfo li : locks) {
76 | sb.append("\t- ").append(li);
77 | sb.append('\n');
78 | }
79 | }
80 | sb.append('\n');
81 | return sb.toString();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/LinkedMultiValueMap.java:
--------------------------------------------------------------------------------
1 | package com.github.netty.core.util;
2 |
3 | import java.io.Serializable;
4 | import java.util.*;
5 |
6 | /**
7 | * This Map implementation is generally not thread-safe. It is primarily designed
8 | * for data structures exposed from request objects, for use in a single thread only.
9 | *
10 | * @param the key type
11 | * @param the value element type
12 | * @author Arjen Poutsma
13 | * @author Juergen Hoeller
14 | * @since 3.0
15 | */
16 | public class LinkedMultiValueMap implements Map>, Serializable, Cloneable {
17 |
18 | private static final long serialVersionUID = 3801124242820219131L;
19 |
20 | private final Map> targetMap;
21 |
22 |
23 | /**
24 | * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap}.
25 | */
26 | public LinkedMultiValueMap() {
27 | this.targetMap = new LinkedHashMap<>();
28 | }
29 |
30 | /**
31 | * Create a new LinkedMultiValueMap that wraps a {@link LinkedHashMap}
32 | * with the given initial capacity.
33 | *
34 | * @param initialCapacity the initial capacity
35 | */
36 | public LinkedMultiValueMap(int initialCapacity) {
37 | this.targetMap = new LinkedHashMap<>(initialCapacity);
38 | }
39 |
40 |
41 | public LinkedMultiValueMap(Map> targetMap) {
42 | this.targetMap = Objects.requireNonNull(targetMap);
43 | }
44 |
45 |
46 | public V getFirst(K key) {
47 | List values = this.targetMap.get(key);
48 | return (values != null ? values.get(0) : null);
49 | }
50 |
51 |
52 | public void add(K key, V value) {
53 | List values = this.targetMap.computeIfAbsent(key, k -> new ArrayList<>(2));
54 | values.add(value);
55 | }
56 |
57 |
58 | public void addAll(K key, List extends V> values) {
59 | List currentValues = this.targetMap.computeIfAbsent(key, k -> new ArrayList<>(values.size()));
60 | currentValues.addAll(values);
61 | }
62 |
63 | public void set(K key, V value) {
64 | List values = new ArrayList<>(1);
65 | values.add(value);
66 | this.targetMap.put(key, values);
67 | }
68 |
69 |
70 | public void setAll(Map values) {
71 | values.forEach(this::set);
72 | }
73 |
74 |
75 | public Map toSingleValueMap() {
76 | LinkedHashMap singleValueMap = new LinkedHashMap<>(this.targetMap.size());
77 | this.targetMap.forEach((key, value) -> singleValueMap.put(key, value.get(0)));
78 | return singleValueMap;
79 | }
80 |
81 |
82 | // Map implementation
83 |
84 | @Override
85 | public int size() {
86 | return this.targetMap.size();
87 | }
88 |
89 | @Override
90 | public boolean isEmpty() {
91 | return this.targetMap.isEmpty();
92 | }
93 |
94 | @Override
95 | public boolean containsKey(Object key) {
96 | return this.targetMap.containsKey(key);
97 | }
98 |
99 | @Override
100 | public boolean containsValue(Object value) {
101 | return this.targetMap.containsValue(value);
102 | }
103 |
104 | @Override
105 | public List get(Object key) {
106 | return this.targetMap.get(key);
107 | }
108 |
109 | @Override
110 | public List put(K key, List value) {
111 | return this.targetMap.put(key, value);
112 | }
113 |
114 | @Override
115 | public List remove(Object key) {
116 | return this.targetMap.remove(key);
117 | }
118 |
119 | @Override
120 | public void putAll(Map extends K, ? extends List> map) {
121 | this.targetMap.putAll(map);
122 | }
123 |
124 | @Override
125 | public void clear() {
126 | this.targetMap.clear();
127 | }
128 |
129 | @Override
130 | public Set keySet() {
131 | return this.targetMap.keySet();
132 | }
133 |
134 | @Override
135 | public Collection> values() {
136 | return this.targetMap.values();
137 | }
138 |
139 | @Override
140 | public Set>> entrySet() {
141 | return this.targetMap.entrySet();
142 | }
143 |
144 | @Override
145 | public boolean equals(Object obj) {
146 | return this.targetMap.equals(obj);
147 | }
148 |
149 |
150 | @Override
151 | public int hashCode() {
152 | return this.targetMap.hashCode();
153 | }
154 |
155 | @Override
156 | public String toString() {
157 | return this.targetMap.toString();
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/LoggerFactoryX.java:
--------------------------------------------------------------------------------
1 | package com.github.netty.core.util;
2 |
3 | /**
4 | * @author wangzihao
5 | * 2018/8/25/025
6 | */
7 | public class LoggerFactoryX {
8 |
9 | public static LoggerX getLogger(Class clazz) {
10 | return new LoggerX(clazz);
11 | }
12 |
13 | public static LoggerX getLogger(String clazz) {
14 | return new LoggerX(clazz);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/LoggerX.java:
--------------------------------------------------------------------------------
1 | package com.github.netty.core.util;
2 |
3 | import io.netty.util.internal.logging.InternalLogger;
4 | import io.netty.util.internal.logging.InternalLoggerFactory;
5 |
6 | /**
7 | * JDK logging level [SEVERE WARNING INFO CONFIG FINE FINER FINEST]
8 | *
9 | * @author wangzihao
10 | * 2018/8/25/025
11 | */
12 | public class LoggerX {
13 |
14 | private static final long serialVersionUID = 1L;
15 | private transient InternalLogger logger;
16 |
17 | LoggerX() {
18 | this.logger = InternalLoggerFactory.getInstance(LoggerX.class);
19 | }
20 |
21 | LoggerX(Class clazz) {
22 | this.logger = InternalLoggerFactory.getInstance(clazz);
23 | }
24 |
25 | LoggerX(String name) {
26 | this.logger = InternalLoggerFactory.getInstance(name);
27 | }
28 |
29 | public boolean isTraceEnabled() {
30 | return logger.isTraceEnabled();
31 | }
32 |
33 | public void trace(String msg) {
34 | logger.trace(msg);
35 | }
36 |
37 | public void trace(String format, Object arg) {
38 | logger.trace(format, arg);
39 | }
40 |
41 | public void trace(String format, Object argA, Object argB) {
42 | logger.trace(format, argA, argB);
43 | }
44 |
45 | public void trace(String format, Object... arguments) {
46 | logger.trace(format, arguments);
47 | }
48 |
49 |
50 | public void trace(String msg, Throwable t) {
51 | logger.trace(msg, t);
52 | }
53 |
54 |
55 | public boolean isDebugEnabled() {
56 | return logger.isDebugEnabled();
57 | }
58 |
59 |
60 | public void debug(String msg) {
61 | logger.debug(msg);
62 | }
63 |
64 |
65 | public void debug(String format, Object arg) {
66 | logger.debug(format, arg);
67 | }
68 |
69 |
70 | public void debug(String format, Object argA, Object argB) {
71 | logger.debug(format, argA, argB);
72 | }
73 |
74 |
75 | public void debug(String format, Object... arguments) {
76 | logger.debug(format, arguments);
77 | }
78 |
79 |
80 | public void debug(String msg, Throwable t) {
81 | logger.debug(msg, t);
82 | }
83 |
84 |
85 | public boolean isInfoEnabled() {
86 | return logger.isInfoEnabled();
87 | }
88 |
89 |
90 | public void info(String msg) {
91 | logger.info(msg);
92 | }
93 |
94 |
95 | public void info(String format, Object arg) {
96 | logger.info(format, arg);
97 | }
98 |
99 |
100 | public void info(String format, Object argA, Object argB) {
101 | logger.info(format, argA, argB);
102 | }
103 |
104 |
105 | public void info(String format, Object... arguments) {
106 | logger.info(format, arguments);
107 | }
108 |
109 |
110 | public void info(String msg, Throwable t) {
111 | logger.info(msg, t);
112 | }
113 |
114 |
115 | public boolean isWarnEnabled() {
116 | return logger.isWarnEnabled();
117 | }
118 |
119 |
120 | public void warn(String msg) {
121 | logger.warn(msg);
122 | }
123 |
124 |
125 | public void warn(String format, Object arg) {
126 | logger.warn(format, arg);
127 | }
128 |
129 |
130 | public void warn(String format, Object argA, Object argB) {
131 | logger.warn(format, argA, argB);
132 | }
133 |
134 |
135 | public void warn(String format, Object... arguments) {
136 | logger.warn(format, arguments);
137 | }
138 |
139 |
140 | public void warn(String msg, Throwable t) {
141 | logger.warn(msg, t);
142 | }
143 |
144 |
145 | public boolean isErrorEnabled() {
146 | return logger.isErrorEnabled();
147 | }
148 |
149 |
150 | public void error(String msg) {
151 | logger.error(msg);
152 | }
153 |
154 |
155 | public void error(String format, Object arg) {
156 | logger.error(format, arg);
157 | }
158 |
159 |
160 | public void error(String format, Object argA, Object argB) {
161 | logger.error(format, argA, argB);
162 | }
163 |
164 |
165 | public void error(String format, Object... arguments) {
166 | logger.error(format, arguments);
167 | }
168 |
169 |
170 | public void error(String msg, Throwable t) {
171 | logger.error(msg, t);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/com/github/netty/core/util/MessageMetricsChannelHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2018 The original author or authors
3 | * ------------------------------------------------------
4 | * All rights reserved. This program and the accompanying materials
5 | * are made available under the terms of the Eclipse Public License v1.0
6 | * and Apache License v2.0 which accompanies this distribution.
7 | *
8 | * The Eclipse Public License is available at
9 | * http://www.eclipse.org/legal/epl-v10.html
10 | *
11 | * The Apache License v2.0 is available at
12 | * http://www.opensource.org/licenses/apache2.0.php
13 | *
14 | * You may elect to redistribute this code under either of these licenses.
15 | */
16 |
17 | package com.github.netty.core.util;
18 |
19 | import com.github.netty.core.AbstractChannelHandler;
20 | import io.netty.channel.*;
21 | import io.netty.util.Attribute;
22 | import io.netty.util.AttributeKey;
23 |
24 | import java.util.concurrent.atomic.AtomicLong;
25 |
26 | /**
27 | * Communication monitoring (read write/time)
28 | *
29 | * @author wangzihao
30 | */
31 | @ChannelHandler.Sharable
32 | public class MessageMetricsChannelHandler extends AbstractChannelHandler