Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #96 #97

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ Please visit this web site for more information of this project:
The Apache Software License, Version 2.0.
================================================================

This software includes code from Spring boot:
This software includes code from Spring projects:

Please visit this web site for more information of this project:
* https://github.com/spring-projects/spring-boot
* https://github.com/spring-projects/spring-framework
================================================================

This software includes code from AhoCorasickDoubleArrayTrie:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package com.jd.live.agent.core.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
Expand All @@ -25,6 +27,11 @@
*/
public class CollectionUtils {

/**
* Default load factor for {@link HashMap}/{@link LinkedHashMap} variants.
*/
public static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
* Filters the provided list of objects based on the given predicate.
*
Expand Down Expand Up @@ -74,4 +81,35 @@ public static <S, T> List<T> convert(List<S> sources, Function<S, T> converter)
}
return result;
}

/**
* Instantiate a new {@link LinkedHashMap} with an initial capacity
* that can accommodate the specified number of elements without
* any immediate resize/rehash operations to be expected.
*/
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int expectedSize) {
return new LinkedHashMap<>(computeMapInitialCapacity(expectedSize), DEFAULT_LOAD_FACTOR);
}

/**
* Instantiate a new {@link HashMap} with an initial capacity
* that can accommodate the specified number of elements without
* any immediate resize/rehash operations to be expected.
* <p>This differs from the regular {@link HashMap} constructor
* which takes an initial capacity relative to a load factor
* but is effectively aligned with the JDK's
* {@link java.util.concurrent.ConcurrentHashMap#ConcurrentHashMap(int)}.
*
* @param expectedSize the expected number of elements (with a corresponding
* capacity to be derived so that no resize/rehash operations are needed)
* @see #newLinkedHashMap(int)
* @since 5.3
*/
public static <K, V> HashMap<K, V> newHashMap(int expectedSize) {
return new HashMap<>(computeMapInitialCapacity(expectedSize), DEFAULT_LOAD_FACTOR);
}

private static int computeMapInitialCapacity(int expectedSize) {
return (int) Math.ceil(expectedSize / (double) DEFAULT_LOAD_FACTOR);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package com.jd.live.agent.core.util.http;

import com.jd.live.agent.core.parser.ObjectReader;
import com.jd.live.agent.core.util.map.CaseInsensitiveLinkedMap;
import com.jd.live.agent.core.util.map.MultiLinkedMap;
import com.jd.live.agent.core.util.map.MultiMap;

import java.io.*;
import java.net.HttpURLConnection;
Expand Down Expand Up @@ -203,9 +206,9 @@ public static void parseQuery(String query, boolean decode, BiConsumer<String, S
* @param query the query string to parse
* @return a map where each key is associated with a list of values
*/
public static Map<String, List<String>> parseQuery(String query) {
Map<String, List<String>> result = new HashMap<>();
parseQuery(query, true, (key, value) -> result.computeIfAbsent(key, k -> new ArrayList<>(1)).add(value == null ? "" : value));
public static MultiMap<String, String> parseQuery(String query) {
MultiMap<String, String> result = new MultiLinkedMap<>();
parseQuery(query, true, (key, value) -> result.add(key, value == null ? "" : value));
return result;
}

Expand All @@ -216,9 +219,9 @@ public static Map<String, List<String>> parseQuery(String query) {
* @param decode whether the query string is URL decoded
* @return a map where each key is associated with a list of values
*/
public static Map<String, List<String>> parseQuery(String query, boolean decode) {
Map<String, List<String>> result = new HashMap<>();
parseQuery(query, decode, (key, value) -> result.computeIfAbsent(key, k -> new ArrayList<>(1)).add(value == null ? "" : value));
public static MultiMap<String, String> parseQuery(String query, boolean decode) {
MultiMap<String, String> result = new MultiLinkedMap<>();
parseQuery(query, decode, (key, value) -> result.add(key, value == null ? "" : value));
return result;
}

Expand All @@ -228,11 +231,11 @@ public static Map<String, List<String>> parseQuery(String query, boolean decode)
* @param headers the collection of "Cookie" headers
* @return a map of cookie names to lists of cookie values
*/
public static Map<String, List<String>> parseCookie(Collection<String> headers) {
Map<String, List<String>> result = new HashMap<>();
public static MultiMap<String, String> parseCookie(Collection<String> headers) {
MultiMap<String, String> result = new MultiLinkedMap<>(CaseInsensitiveLinkedMap::new);
if (headers != null && !headers.isEmpty()) {
for (String header : headers) {
parseCookie(header, (key, value) -> result.computeIfAbsent(key, k -> new ArrayList<>(1)).add(header));
parseCookie(header, (key, value) -> result.add(key, value == null ? "" : value));
}
}
return result;
Expand All @@ -244,9 +247,9 @@ public static Map<String, List<String>> parseCookie(Collection<String> headers)
* @param header cooke header string
* @return a map of cookie names to lists of cookie values
*/
public static Map<String, List<String>> parseCookie(String header) {
Map<String, List<String>> result = new HashMap<>();
parseCookie(header, (key, value) -> result.computeIfAbsent(key, k -> new ArrayList<>(1)).add(header));
public static MultiMap<String, String> parseCookie(String header) {
MultiMap<String, String> result = new MultiLinkedMap<>(CaseInsensitiveLinkedMap::new);
parseCookie(header, (key, value) -> result.add(key, value == null ? "" : value));
return result;
}

Expand All @@ -260,7 +263,6 @@ public static void parseCookie(String value, BiConsumer<String, String> consumer
Cookies.parse(value, consumer);
}


/**
* Converts a map of cookies with generic type values to a map of cookies with string values.
*
Expand All @@ -269,17 +271,17 @@ public static void parseCookie(String value, BiConsumer<String, String> consumer
* @param valueFunc a function that converts a value of type T to a string
* @return a map where the key is the cookie name and the value is a list of cookie values as strings
*/
public static <T> Map<String, List<String>> parseCookie(Map<String, List<T>> cookies, Function<T, String> valueFunc) {
Map<String, List<String>> result = new HashMap<>();
public static <T> MultiMap<String, String> parseCookie(Map<String, List<T>> cookies, Function<T, String> valueFunc) {
MultiMap<String, String> result = new MultiLinkedMap<>(CaseInsensitiveLinkedMap::new);
if (cookies != null && !cookies.isEmpty()) {
cookies.forEach((name, cooke) -> {
if (!cooke.isEmpty()) {
if (cooke.size() == 1) {
result.put(name, Collections.singletonList(valueFunc.apply(cooke.get(0))));
result.set(name, valueFunc.apply(cooke.get(0)));
} else {
List<String> values = new ArrayList<>(cooke.size());
cooke.forEach(value -> values.add(valueFunc.apply(value)));
result.put(name, values);
result.setAll(name, values);
}
}
});
Expand All @@ -294,19 +296,17 @@ public static <T> Map<String, List<String>> parseCookie(Map<String, List<T>> coo
* @param headerFunc a function that takes a header name and returns an enumeration of its values
* @return a map where each key is a header name and the value is a list of header values
*/
public static Map<String, List<String>> parseHeader(Enumeration<String> names,
Function<String, Enumeration<String>> headerFunc) {
Map<String, List<String>> result = new HashMap<>();
public static MultiMap<String, String> parseHeader(Enumeration<String> names,
Function<String, Enumeration<String>> headerFunc) {
MultiMap<String, String> result = new MultiLinkedMap<>(CaseInsensitiveLinkedMap::new);
String name;
List<String> values;
Enumeration<String> valueEnumeration;
while (names.hasMoreElements()) {
name = names.nextElement();
values = result.computeIfAbsent(name, k -> new ArrayList<>());
valueEnumeration = headerFunc.apply(name);
if (valueEnumeration != null) {
while (valueEnumeration.hasMoreElements()) {
values.add(valueEnumeration.nextElement());
result.add(name, valueEnumeration.nextElement());
}
}
}
Expand Down
Loading
Loading