From 0705351d417a8a3e920848e2bec7cd7127c5b4e8 Mon Sep 17 00:00:00 2001 From: arisnguyenit97 Date: Sun, 19 May 2024 12:10:54 +0700 Subject: [PATCH] :sparkles: feat: add transform4j, cookie4j unify functions #4 --- plugin/build.gradle | 4 + .../groovy/org/unify4j/common/Cookie4j.java | 216 ++++++++++++++++++ .../main/groovy/org/unify4j/common/Os4j.java | 137 +++++++++++ .../org/unify4j/common/Transform4j.java | 15 +- .../unify4j/model/builder/CookieBuilder.java | 43 ++++ .../unify4j/model/request/CookieRequest.java | 56 +++++ 6 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 plugin/src/main/groovy/org/unify4j/common/Cookie4j.java create mode 100644 plugin/src/main/groovy/org/unify4j/common/Os4j.java create mode 100644 plugin/src/main/groovy/org/unify4j/model/builder/CookieBuilder.java create mode 100644 plugin/src/main/groovy/org/unify4j/model/request/CookieRequest.java diff --git a/plugin/build.gradle b/plugin/build.gradle index 9ade07c..e6111a2 100755 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -85,4 +85,8 @@ dependencies { implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.9.0' // The "validation-api" library, version 2.0.1.Final, provides tools for validating Java objects according to defined constraints. implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' + // The Servlet API is used for creating web applications in Java. + // Including it as compileOnly means that it's necessary for compiling your code (as it might include annotations or classes used during compilation), + // but it shouldn't be packaged into the final artifact (JAR, WAR, etc.) because servlet containers, like Tomcat or Jetty, usually provide this API at runtime. + compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' } diff --git a/plugin/src/main/groovy/org/unify4j/common/Cookie4j.java b/plugin/src/main/groovy/org/unify4j/common/Cookie4j.java new file mode 100644 index 0000000..16612ad --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/common/Cookie4j.java @@ -0,0 +1,216 @@ +package org.unify4j.common; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Cookie4j { + protected static final Logger logger = LoggerFactory.getLogger(Cookie4j.class); + + /** + * Retrieves cookies from the provided HttpServletRequest and returns them as a map of cookie names to values. + * If the request is null or contains no cookies, returns an empty map. + * + * @param request The HttpServletRequest from which to retrieve cookies. + * @return A map of cookie names to values extracted from the request. + */ + public static Map getCookies(HttpServletRequest request) { + if (request == null || Object4j.isEmpty(request.getCookies())) { + return Collections.emptyMap(); + } + return Arrays.stream(request.getCookies()).collect(Collectors.toMap(Cookie::getName, // Use cookie's name as the map key + Cookie::getValue, // Use cookie's value as the map value + (cookie1, cookie2) -> { // Merge function for handling duplicate keys + logger.info("cookie duplicated key found by cookie-1: {} and cookie-2: {}", cookie1, cookie2); + return cookie1; // Keep the value of the first cookie in case of a duplicate key + })); + } + + /** + * Retrieves cookies from the provided ServletRequest and returns them as a map of cookie names to values. + * If the request is null or not of type HttpServletRequest, returns an empty map. + * + * @param request The ServletRequest from which to retrieve cookies. + * @return A map of cookie names to values extracted from the request, or an empty map if the request is null or not an HttpServletRequest. + */ + public static Map getCookies(ServletRequest request) { + if (!(request instanceof HttpServletRequest)) { + return Collections.emptyMap(); + } + return getCookies((HttpServletRequest) request); + } + + /** + * Constructs a string representation of cookies present in the provided HttpServletRequest. + * The string format is "name1=value1,name2=value2,..." for all cookies. + * If the request is null or contains no cookies, returns an empty string. + * + * @param request The HttpServletRequest from which to retrieve cookies. + * @return A string representation of cookies in the format "name1=value1,name2=value2,...", or an empty string if the request is null or contains no cookies. + */ + public static String cookieString(HttpServletRequest request) { + if (request == null || Object4j.isEmpty(request.getCookies())) { + return ""; + } + return Arrays.stream(request.getCookies()).map(cookie -> cookie.getName().concat("=").concat(cookie.getValue())) // Map each cookie to "name=value" format + .collect(Collectors.joining(",")); // Join all cookie strings with "," + } + + /** + * Constructs a string representation of cookies present in the provided ServletRequest. + * The string format is "name1=value1,name2=value2,..." for all cookies. + * If the request is not an instance of HttpServletRequest, returns an empty string. + * + * @param request The ServletRequest from which to retrieve cookies. + * @return A string representation of cookies in the format "name1=value1,name2=value2,...", or an empty string if the request is not an instance of HttpServletRequest. + */ + public static String cookieString(ServletRequest request) { + if (!(request instanceof HttpServletRequest)) { + return ""; + } + return cookieString((HttpServletRequest) request); + } + + /** + * Retrieves cookies from the provided HttpServletRequest and returns them as a List of Cookie objects. + * If the request is null or does not contain any cookies, returns an empty list. + * + * @param request The HttpServletRequest from which to retrieve cookies. + * @return A List of Cookie objects extracted from the request, or an empty list if the request is null or contains no cookies. + */ + public static List getCollections(HttpServletRequest request) { + if (request == null) { + return Collections.emptyList(); + } + return Arrays.stream(request.getCookies()).collect(Collectors.toList()); + } + + /** + * Checks if the provided HttpServletRequest contains all the specified cookies. + * + * @param request The HttpServletRequest object containing cookies to be checked. + * @param cookies A List of cookie names to be checked for existence. + * @return true if all specified cookies are present in the request, false otherwise. + */ + public static boolean hasCookies(HttpServletRequest request, List cookies) { + if (request == null || Collection4j.isEmpty(cookies) || Object4j.isEmpty(request.getCookies())) { + return false; + } + List list = Arrays.stream(request.getCookies()).map(Cookie::getName).collect(Collectors.toList()); + return list.stream().flatMap(x -> cookies.stream().filter(x::equalsIgnoreCase).limit(1)).findFirst().isPresent(); + } + + /** + * Checks if the provided ServletRequest contains all the specified cookies. + * + * @param request The ServletRequest object containing cookies to be checked. + * @param cookies A List of cookie names to be checked for existence. + * @return true if all specified cookies are present in the request, false otherwise. + */ + public static boolean hasCookies(ServletRequest request, List cookies) { + return hasCookies((HttpServletRequest) request, cookies); + } + + /** + * Checks if the provided HttpServletRequest contains the specified cookie. + * + * @param request The HttpServletRequest object containing cookies to be checked. + * @param cookie The name of the cookie to be checked for existence. + * @return true if the specified cookie is present in the request, false otherwise. + */ + public static boolean hasCookie(HttpServletRequest request, String cookie) { + return hasCookies(request, Collections.singletonList(cookie)); + } + + /** + * Checks if the provided ServletRequest contains the specified cookie. + * + * @param request The ServletRequest object containing cookies to be checked. + * @param cookie The name of the cookie to be checked for existence. + * @return true if the specified cookie is present in the request, false otherwise. + */ + public static boolean hasCookie(ServletRequest request, String cookie) { + return hasCookies(request, Collections.singletonList(cookie)); + } + + /** + * Checks if the provided HttpServletRequest contains all the specified cookies. + * + * @param request The HttpServletRequest object containing cookies to be checked. + * @param cookies A variable number of cookie names to be checked for existence. + * @return true if all specified cookies are present in the request, false otherwise. + */ + public static boolean hasCookies(HttpServletRequest request, String... cookies) { + return hasCookies(request, Transform4j.fromArray2Coll(cookies)); + } + + /** + * Checks if the provided ServletRequest contains all the specified cookies. + * + * @param request The ServletRequest object containing cookies to be checked. + * @param cookies A variable number of cookie names to be checked for existence. + * @return true if all specified cookies are present in the request, false otherwise. + */ + public static boolean hasCookies(ServletRequest request, String... cookies) { + if (!(request instanceof HttpServletRequest)) { + return false; + } + return hasCookies((HttpServletRequest) request, cookies); + } + + /** + * Checks if the provided HttpServletRequest contains the specified cookie. + * + * @param request The HttpServletRequest object containing cookies to be checked. + * @param cookie The Cookie object to be checked for existence. + * @return true if the specified cookie is present in the request, false otherwise. + */ + public static boolean hasCookie(HttpServletRequest request, Cookie cookie) { + return hasCookies(request, Collections.singletonList(cookie.getName())); + } + + /** + * Checks if the provided ServletRequest contains the specified cookie. + * + * @param request The ServletRequest object containing cookies to be checked. + * @param cookie The Cookie object to be checked for existence. + * @return true if the specified cookie is present in the request, false otherwise. + */ + public static boolean hasCookie(ServletRequest request, Cookie cookie) { + if (!(request instanceof HttpServletRequest)) { + return false; + } + return hasCookie((HttpServletRequest) request, cookie); + } + + /** + * Checks if the provided HttpServletRequest has any cookies. + * + * @param request The HttpServletRequest object to check for available cookies. + * @return true if the request contains cookies, false otherwise. + */ + public static boolean isAvailableCookie(HttpServletRequest request) { + return Collection4j.isNotEmptyMap(getCookies(request)); + } + + /** + * Checks if the provided ServletRequest has any cookies. + * + * @param request The ServletRequest object to check for available cookies. + * @return true if the request contains cookies, false otherwise. + */ + public static boolean isAvailableCookie(ServletRequest request) { + if (!(request instanceof HttpServletRequest)) { + return false; + } + return isAvailableCookie((HttpServletRequest) request); + } +} diff --git a/plugin/src/main/groovy/org/unify4j/common/Os4j.java b/plugin/src/main/groovy/org/unify4j/common/Os4j.java new file mode 100644 index 0000000..8133eac --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/common/Os4j.java @@ -0,0 +1,137 @@ +package org.unify4j.common; + +public class Os4j { + protected final static char SLASH_CHAR = '/'; + protected final static char BACK_SLASH_CHAR = '\\'; + + /** + * Normalizes the given path by replacing all backslashes with forward slashes. + * + * @param path The path to be normalized. + * @return The normalized path with all backslashes replaced by forward slashes. + */ + public static String normalised(String path) { + return normalised(path, BACK_SLASH_CHAR, SLASH_CHAR); + } + + /** + * Normalizes the given path by replacing all occurrences of the specified separator with the new separator. + * + * @param path The path to be normalized. + * @param separator The character to be replaced. + * @return The normalized path with the specified separator replaced. + */ + public static String normalised(String path, char separator) { + return normalised(path, separator, separator); + } + + /** + * Normalizes the given path by replacing all occurrences of the specified separator with the new separator + * and collapsing any consecutive separators into a single separator. + * + * @param path The path to be normalized. + * @param separator The character to be replaced. + * @param newSeparator The character to replace with. + * @return The normalized path with specified changes. + */ + public static String normalised(String path, char separator, char newSeparator) { + if (String4j.isEmpty(path)) { + return path; + } + String filename = path.trim(); + if (separator != newSeparator) { + filename = filename.replace(separator, newSeparator); + } + return filename.replace(String.format("\\%s{2,}", newSeparator), "\\" + newSeparator); + } + + /** + * Normalizes the given path by collapsing any unnecessary segments (such as "." and "..") and + * removing redundant slashes. + * + * @param path The path to be normalized. + * @return The normalized path. + */ + public static String withNormalised(String path) { + if (String4j.isEmpty(path)) { + return path; + } + if (path.indexOf('.') == -1 && path.indexOf('/') == -1) { + return path; + } + boolean isNormalized = true; + int noSegments = 0; + int lastChar = path.length() - 1; + for (int src = lastChar; src >= 0; ) { + int slash = path.lastIndexOf('/', src); + if (slash != -1) { + if (slash == src) { + if (src != lastChar) { + isNormalized = false; + } + } else { + noSegments++; + } + } else { + noSegments++; + } + src = slash - 1; + } + int[] segments = new int[noSegments]; + char[] chars = new char[path.length()]; + path.getChars(0, chars.length, chars, 0); + noSegments = 0; + for (int src = 0; src < chars.length; ) { + while (src < chars.length && chars[src] == '/') { + src++; + } + if (src < chars.length) { + segments[noSegments++] = src; + while (src < chars.length && chars[src] != '/') { + src++; + } + } + } + final int DELETED = -1; + for (int segment = 0; segment < noSegments; segment++) { + int src = segments[segment]; + if (chars[src++] == '.') { + if (src == chars.length || chars[src] == '/') { + segments[segment] = DELETED; + isNormalized = false; + } else { + if (chars[src++] == '.' && (src == chars.length || chars[src] == '/')) { + for (int toDelete = segment - 1; toDelete >= 0; toDelete--) { + if (segments[toDelete] != DELETED) { + if (chars[segments[toDelete]] != '.') { + segments[toDelete] = DELETED; + segments[segment] = DELETED; + isNormalized = false; + } + break; + } + } + } + } + } + } + if (isNormalized) { + return path; + } else { + int dst = (chars[0] == '/') ? 1 : 0; + for (int segment = 0; segment < noSegments; segment++) { + int segmentStart = segments[segment]; + if (segmentStart != DELETED) { + for (int src = segmentStart; src < chars.length; src++) { + char ch = chars[src]; + chars[dst++] = ch; + if (ch == '/') { + break; + } + } + } + } + return new String(chars, 0, dst); + } + } +} diff --git a/plugin/src/main/groovy/org/unify4j/common/Transform4j.java b/plugin/src/main/groovy/org/unify4j/common/Transform4j.java index b423bf1..01d9873 100644 --- a/plugin/src/main/groovy/org/unify4j/common/Transform4j.java +++ b/plugin/src/main/groovy/org/unify4j/common/Transform4j.java @@ -3,7 +3,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.List; public class Transform4j { protected static final Logger logger = LoggerFactory.getLogger(Transform4j.class); @@ -41,10 +44,20 @@ public static char[] fromArray2Chars(String[] arrays) { * If the collection is not empty, it converts the collection to an array of strings using the toArray method. * The returned array contains the string representations of the elements in the collection. */ - public static String[] fromColl2StringArray(Collection collection) { + public static String[] fromColl2Array(Collection collection) { if (!Collection4j.isEmpty(collection)) { return collection.stream().map(Object::toString).toArray(String[]::new); } return null; } + + /** + * Converts an array of strings into a List of strings. + * + * @param strings The array of strings to convert. + * @return A List containing the strings from the input array. + */ + public static List fromArray2Coll(String[] strings) { + return new ArrayList<>(Arrays.asList(strings)); + } } diff --git a/plugin/src/main/groovy/org/unify4j/model/builder/CookieBuilder.java b/plugin/src/main/groovy/org/unify4j/model/builder/CookieBuilder.java new file mode 100644 index 0000000..186e8ad --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/model/builder/CookieBuilder.java @@ -0,0 +1,43 @@ +package org.unify4j.model.builder; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.unify4j.common.Json4j; +import org.unify4j.model.request.CookieRequest; + +import java.io.Serializable; +import java.time.Duration; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CookieBuilder implements Serializable { + public CookieBuilder() { + super(); + } + + private String name; + private String value; + private Duration expiredAt; + + public CookieBuilder withName(String name) { + this.name = name; + return this; + } + + public CookieBuilder withValue(String value) { + this.value = value; + return this; + } + + public CookieBuilder withValue(Object value) { + this.value = Json4j.toJson(value); + return this; + } + + public CookieBuilder withExpiredAt(Duration expiredAt) { + this.expiredAt = expiredAt; + return this; + } + + public CookieRequest build() { + return new CookieRequest(name, value, expiredAt); + } +} \ No newline at end of file diff --git a/plugin/src/main/groovy/org/unify4j/model/request/CookieRequest.java b/plugin/src/main/groovy/org/unify4j/model/request/CookieRequest.java new file mode 100644 index 0000000..3a6af09 --- /dev/null +++ b/plugin/src/main/groovy/org/unify4j/model/request/CookieRequest.java @@ -0,0 +1,56 @@ +package org.unify4j.model.request; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.io.Serializable; +import java.time.Duration; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CookieRequest implements Serializable { + public CookieRequest() { + super(); + } + + public CookieRequest(String name, String value, Duration expiredAt) { + this.name = name; + this.value = value; + this.expiredAt = expiredAt; + } + + private String name; + private String value; + @JsonProperty("expired_at") + @JsonAlias({"expired_at", "expiredAt"}) + private Duration expiredAt; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Duration getExpiredAt() { + return expiredAt; + } + + public void setExpiredAt(Duration expiredAt) { + this.expiredAt = expiredAt; + } + + @Override + public String toString() { + return String.format("Cookie { name: '%s', value: '%s', expired_at: %s }", name, value, expiredAt); + } +}