Skip to content

Commit 7cfb618

Browse files
committed
[#noissue] Refactor parsing logic to use KeyValueTokenizer.
1 parent 247b991 commit 7cfb618

File tree

10 files changed

+167
-39
lines changed

10 files changed

+167
-39
lines changed

agent-module/plugins/dameng-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/dameng/DamengJdbcUrlParser.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.navercorp.pinpoint.bootstrap.plugin.jdbc.StringMaker;
2525
import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo;
2626
import com.navercorp.pinpoint.common.trace.ServiceType;
27+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
2728
import com.navercorp.pinpoint.common.util.StringUtils;
2829

2930
import java.util.Arrays;
@@ -73,10 +74,10 @@ private DatabaseInfo parseURL(String url) {
7374
String host = DEFAULT_HOST;
7475
String port = DEFAULT_PORT;
7576
if (StringUtils.hasText(hostPort)) {
76-
String[] hostPortInfo = hostPort.split(":", 2);
77-
host = hostPortInfo[0];
78-
if (hostPortInfo.length > 1) {
79-
port = hostPortInfo[1];
77+
KeyValueTokenizer.KeyValue hostPortInfo = KeyValueTokenizer.tokenize(hostPort, ":");
78+
host = hostPortInfo.getKey();
79+
if (!hostPortInfo.getValue().isEmpty()) {
80+
port = hostPortInfo.getValue();
8081
}
8182
}
8283

@@ -122,11 +123,11 @@ private Map<String, String> parseQuery(String propString) {
122123
if (!StringUtils.hasText(v)) {
123124
continue;
124125
}
125-
String[] kv = v.split("=", 2);
126-
if (kv.length > 1) {
127-
map.put(kv[0], kv[1]);
126+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize(v, "=");
127+
if (keyValue != null) {
128+
map.put(keyValue.getKey(), keyValue.getValue());
128129
} else {
129-
map.put(kv[0], StringUtils.EMPTY_STRING);
130+
logger.info("Parse failed " + v) ;
130131
}
131132
}
132133
return map;

collector/src/main/java/com/navercorp/pinpoint/collector/grpc/channelz/service/ChannelzSocketLookup.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.navercorp.pinpoint.collector.grpc.channelz.service;
1818

19+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
20+
1921
import javax.annotation.Nullable;
2022
import java.util.Collection;
2123

@@ -48,16 +50,16 @@ private SocketEntry(String remoteAddr, Integer localPort, long socketId) {
4850
* @return entry of socket index
4951
*/
5052
public static SocketEntry compose(Object remote, Object local, long socketId) {
51-
String remoteAddr = split(remote)[0];
52-
String localPort = split(local)[1];
53+
String remoteAddr = split(remote).getKey();
54+
String localPort = split(local).getValue();
5355
return new SocketEntry(remoteAddr.substring(1), parse(localPort), socketId);
5456
}
5557

56-
private static String[] split(Object obj) {
58+
private static KeyValueTokenizer.KeyValue split(Object obj) {
5759
if (obj == null) {
5860
return null;
5961
}
60-
return obj.toString().split(":", 2);
62+
return KeyValueTokenizer.tokenize(obj.toString(), ":");
6163
}
6264

6365
private static Integer parse(String str) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.navercorp.pinpoint.common.util;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
8+
class KeyValueTokenizerTest {
9+
10+
@Test
11+
void tokenize() {
12+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize("key=value", "=");
13+
assertEquals("key", keyValue.getKey());
14+
assertEquals("value", keyValue.getValue());
15+
}
16+
17+
@Test
18+
void tokenize2() {
19+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize("key==value", "==");
20+
assertEquals("key", keyValue.getKey());
21+
assertEquals("value", keyValue.getValue());
22+
}
23+
24+
@Test
25+
void tokenize_emptyValue() {
26+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize("key=", "=");
27+
assertEquals("key", keyValue.getKey());
28+
assertEquals("", keyValue.getValue());
29+
}
30+
31+
@Test
32+
void tokenize_emptyKeyValue() {
33+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize("=", "=");
34+
assertEquals("", keyValue.getKey());
35+
assertEquals("", keyValue.getValue());
36+
}
37+
38+
@Test
39+
void tokenize_empty() {
40+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize("", "=");
41+
Assertions.assertNull(keyValue);
42+
}
43+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.navercorp.pinpoint.common.util;
2+
import java.util.Objects;
3+
4+
public class KeyValueTokenizer {
5+
6+
public static final TokenFactory<KeyValue> KEY_VALUE_FACTORY = new TokenFactory<KeyValue>() {
7+
public KeyValue accept(String key, String value) {
8+
return new KeyValue(key, value);
9+
}
10+
};
11+
12+
public static final TokenFactory<KeyValue> KEY_VALUE_TRIM_FACTORY = new TokenFactory<KeyValue>() {
13+
public KeyValue accept(String key, String value) {
14+
return new KeyValue(key.trim(), value.trim());
15+
}
16+
};
17+
18+
public static KeyValue tokenize(String text, String delimiter) {
19+
return tokenize(text, delimiter, KEY_VALUE_FACTORY);
20+
}
21+
22+
/**
23+
* Tokenizes the given text into a key and value using the specified delimiter and token factory.
24+
*
25+
* @param text the text to tokenize
26+
* @param delimiter the delimiter separating key and value
27+
* @param factory the factory used to create the token
28+
* @param <T> the type of token to return
29+
* @return the parsed token, or {@code null} if the delimiter is not found in the text
30+
*/
31+
public static <T> T tokenize(String text, String delimiter, TokenFactory<T> factory) {
32+
Objects.requireNonNull(text, "text");
33+
34+
final int delimiterIndex = text.indexOf(delimiter);
35+
if (delimiterIndex == -1) {
36+
return null;
37+
}
38+
39+
final String key = text.substring(0, delimiterIndex);
40+
41+
final int delimiterLength = delimiter.length();
42+
if (delimiterIndex == text.length() - delimiterLength) {
43+
return factory.accept(key, "");
44+
}
45+
String value = text.substring(delimiterIndex + delimiterLength);
46+
return factory.accept(key, value);
47+
}
48+
49+
50+
public interface TokenFactory<V> {
51+
V accept(String key, String value);
52+
}
53+
54+
public static class KeyValue {
55+
private final String key;
56+
private final String value;
57+
58+
public KeyValue(String key, String value) {
59+
this.key = Objects.requireNonNull(key, "key");
60+
this.value = Objects.requireNonNull(value, "value");
61+
}
62+
63+
public String getKey() {
64+
return key;
65+
}
66+
67+
public String getValue() {
68+
return value;
69+
}
70+
}
71+
}

exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ExceptionTraceQueryParameter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.common.primitives.Ints;
2020
import com.navercorp.pinpoint.common.server.util.StringPrecondition;
2121
import com.navercorp.pinpoint.common.timeseries.window.TimePrecision;
22+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
2223
import com.navercorp.pinpoint.common.util.StringUtils;
2324
import com.navercorp.pinpoint.metric.web.util.QueryParameter;
2425

@@ -197,8 +198,8 @@ public Builder addAllFilters(Collection<String> strings) {
197198
return self();
198199
}
199200
for (String string : strings) {
200-
String[] tag = string.split(":", 2);
201-
filterByAttributes.put(tag[0], tag[1]);
201+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize(string, ":");
202+
filterByAttributes.put(keyValue.getKey(), keyValue.getValue());
202203
}
203204
return self();
204205
}

metric-module/metric-commons/src/main/java/com/navercorp/pinpoint/metric/common/util/TagUtils.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919

2020
import com.navercorp.pinpoint.common.util.CollectionUtils;
21+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
2122
import com.navercorp.pinpoint.metric.common.model.Tag;
2223
import org.apache.commons.lang3.StringUtils;
2324

@@ -33,7 +34,14 @@
3334
public class TagUtils {
3435

3536
private static final Pattern MULTI_VALUE_FIELD_PATTERN = Pattern.compile("[\\[\\]\"]");
36-
private static final Pattern JSON_TAG_STRING_PATTERN = Pattern.compile("[{}\"]");
37+
private static final String JSON_TAG_STRING = "{}\"";
38+
39+
public static final KeyValueTokenizer.TokenFactory<Tag> TAG_FACTORY = new KeyValueTokenizer.TokenFactory<>() {
40+
@Override
41+
public Tag accept(String key, String value) {
42+
return new Tag(key, value);
43+
}
44+
};
3745

3846
private TagUtils() {
3947
}
@@ -69,16 +77,7 @@ public static List<Tag> parseTags(String tagStrings) {
6977

7078
public static Tag parseTag(String tagString) {
7179
Objects.requireNonNull(tagString, "tagString");
72-
73-
String[] tag = StringUtils.split(tagString, ":", 2);
74-
75-
if (tag.length == 1) {
76-
return new Tag(tag[0], "");
77-
} else if (tag.length == 2) {
78-
return new Tag(tag[0], tag[1]);
79-
} else {
80-
throw new IllegalArgumentException("tagString:" + tagString);
81-
}
80+
return KeyValueTokenizer.tokenize(tagString, ":", TAG_FACTORY);
8281
}
8382

8483
private static String[] parseMultiValueFieldList(String string) {
@@ -87,10 +86,11 @@ private static String[] parseMultiValueFieldList(String string) {
8786
}
8887

8988
public static String toTagString(String jsonTagString) {
90-
if (jsonTagString.equals("{}")) {
89+
if ("{}".equals(jsonTagString)) {
9190
return "";
9291
}
93-
return JSON_TAG_STRING_PATTERN.matcher(jsonTagString).replaceAll("");
92+
93+
return org.springframework.util.StringUtils.deleteAny(jsonTagString, JSON_TAG_STRING);
9494
}
9595

9696
public static String toTagString(List<Tag> tagList) {

metric-module/metric-commons/src/test/java/com/navercorp/pinpoint/metric/common/util/TagUtilsTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public void parseTagTest() {
4141
Assertions.assertEquals(tagList, result);
4242
}
4343

44+
@Test
45+
public void parseTagTest_emptyValue() {
46+
Tag tag = TagUtils.parseTag("A:");
47+
48+
Assertions.assertEquals("A", tag.getName());
49+
Assertions.assertEquals("", tag.getValue());
50+
}
51+
4452
@Test
4553
public void parseTagsListTest() {
4654
List<Tag> tagList = List.of(

redis/src/main/java/com/navercorp/pinpoint/channel/redis/kv/RedisKVPubChannelProvider.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.navercorp.pinpoint.channel.PubChannel;
1919
import com.navercorp.pinpoint.channel.PubChannelProvider;
20+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
2021
import org.springframework.data.redis.core.RedisTemplate;
2122

2223
import java.time.Duration;
@@ -35,12 +36,12 @@ class RedisKVPubChannelProvider implements PubChannelProvider {
3536

3637
@Override
3738
public PubChannel getPubChannel(String key) {
38-
String[] words = key.split(":", 2);
39-
if (words.length != 2) {
40-
throw new IllegalArgumentException("the key must contain expire duration");
39+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize(key, ":");
40+
if (keyValue == null) {
41+
throw new IllegalArgumentException("the key must contain ':' key:" + key);
4142
}
42-
Duration expire = Duration.parse(words[0]);
43-
return new RedisKVPubChannel(this.template, expire.toMillis(), words[1]);
43+
Duration expire = Duration.parse(keyValue.getKey());
44+
return new RedisKVPubChannel(this.template, expire.toMillis(), keyValue.getValue());
4445
}
4546

4647
}

redis/src/main/java/com/navercorp/pinpoint/channel/redis/kv/RedisKVSubChannelProvider.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.navercorp.pinpoint.channel.SubChannel;
1919
import com.navercorp.pinpoint.channel.SubChannelProvider;
20+
import com.navercorp.pinpoint.common.util.KeyValueTokenizer;
2021
import org.springframework.data.redis.core.RedisTemplate;
2122
import reactor.core.scheduler.Scheduler;
2223

@@ -38,12 +39,12 @@ class RedisKVSubChannelProvider implements SubChannelProvider {
3839

3940
@Override
4041
public SubChannel getSubChannel(String key) {
41-
String[] words = key.split(":", 2);
42-
if (words.length != 2) {
43-
throw new IllegalArgumentException("the key must contain period");
42+
KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize(key, ":");
43+
if (keyValue == null) {
44+
throw new IllegalArgumentException("the key must contain ':' key:" + key);
4445
}
45-
Duration period = Duration.parse(words[0]);
46-
return new RedisKVSubChannel(this.template, this.scheduler, period, words[1]);
46+
Duration period = Duration.parse(keyValue.getKey());
47+
return new RedisKVSubChannel(this.template, this.scheduler, period, keyValue.getValue());
4748
}
4849

4950
}

web/src/main/java/com/navercorp/pinpoint/web/applicationmap/controller/ServerMapHistogramController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ private Application newApplication(String nodeKey) {
256256
if (!NODE_KEY_VALIDATION_PATTERN.matcher(nodeKey).matches()) {
257257
throw new IllegalArgumentException("Invalid node key format: " + nodeKey);
258258
}
259-
String[] parts = NODE_DELIMITER_PATTERN.split(nodeKey);
259+
String[] parts = NODE_DELIMITER_PATTERN.split(nodeKey, 2);
260260
String applicationName = parts[0];
261261
String serviceTypeName = parts[1];
262262

@@ -345,7 +345,7 @@ public LinkHistogramSummaryView getLinkTimeHistogramData(
345345
if (!LINK_KEY_VALIDATION_PATTERN.matcher(linkKey).matches()) {
346346
throw new IllegalArgumentException("Invalid linkKey format: expected 'fromApp~toApp' but got: " + linkKey);
347347
}
348-
String[] parts = LINK_DELIMITER_PATTERN.split(linkKey);
348+
String[] parts = LINK_DELIMITER_PATTERN.split(linkKey, 2);
349349
if (parts.length != 2) {
350350
throw new IllegalArgumentException("Invalid linkKey format: expected 'fromApp~toApp' but got: " + linkKey);
351351
}

0 commit comments

Comments
 (0)