From 514dd71be7045159e0471c2e887a2e2f2b466fc0 Mon Sep 17 00:00:00 2001 From: emeroad Date: Thu, 24 Feb 2022 17:11:18 +0900 Subject: [PATCH] [#8780] Add ContentLength Util --- .../pinpoint/common/util/ContentLength.java | 149 ++++++++++++++++++ .../common/util/ContentLengthTest.java | 94 +++++++++++ 2 files changed, 243 insertions(+) create mode 100644 commons/src/main/java/com/navercorp/pinpoint/common/util/ContentLength.java create mode 100644 commons/src/test/java/com/navercorp/pinpoint/common/util/ContentLengthTest.java diff --git a/commons/src/main/java/com/navercorp/pinpoint/common/util/ContentLength.java b/commons/src/main/java/com/navercorp/pinpoint/common/util/ContentLength.java new file mode 100644 index 000000000000..cfdb8e59dce5 --- /dev/null +++ b/commons/src/main/java/com/navercorp/pinpoint/common/util/ContentLength.java @@ -0,0 +1,149 @@ +package com.navercorp.pinpoint.common.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ContentLength { + + public static final int SKIP = Integer.MIN_VALUE; + public static final int NOT_EXIST = -1; + + private final LengthFunction[] functions; + + public ContentLength(LengthFunction[] functions) { + this.functions = Objects.requireNonNull(functions, "functions"); + } + + public int getLength(Object content) { + long length = getLongLength(content); + return toInt(length); + } + + private int toInt(long value) { + if (value > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) value; + } + + public long getLongLength(Object content) { + if (content == null) { + return NOT_EXIST; + } + for (LengthFunction function : functions) { + long length = function.getLength(content); + if (length == SKIP) { + continue; + } + return length; + } + return NOT_EXIST; + } + + + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private static final Map, LengthFunction> MAPPING = getMapping(); + + private static Map, LengthFunction> getMapping() { + Map, LengthFunction> map = new LinkedHashMap<>(); + map.put(String.class, new StringLength()); + map.put(byte[].class, new PrimitiveByteArrayLength()); + map.put(char[].class, new PrimitiveCharArrayLength()); + map.put(File.class, new FileLength()); + map.put(InputStream.class, new InputStreamAvailableLength()); + return map; + } + + private Builder() { + } + + private final List list = new ArrayList<>(); + + public void addContentType(Class content) { + Objects.requireNonNull(content, "content"); + LengthFunction lengthFunction = MAPPING.get(content); + if (lengthFunction == null) { + throw new IllegalArgumentException("unsupported content :" + content); + } + list.add(lengthFunction); + } + + public void addFunction(LengthFunction function) { + Objects.requireNonNull(function, "function"); + list.add(function); + } + + public ContentLength build() { + LengthFunction[] functions = list.toArray(new LengthFunction[0]); + return new ContentLength(functions); + } + } + + public interface LengthFunction { + long getLength(Object context); + } + + public static class PrimitiveByteArrayLength implements LengthFunction { + public long getLength(Object context) { + if (context instanceof byte[]) { + return ((byte[]) context).length; + } + return SKIP; + } + + + } + + public static class PrimitiveCharArrayLength implements LengthFunction { + public long getLength(Object context) { + if (context instanceof char[]) { + return ((char[]) context).length; + } + return SKIP; + } + + } + + public static class StringLength implements LengthFunction { + public long getLength(Object context) { + if (context instanceof String) { + return ((String) context).length(); + } + return SKIP; + } + + } + + public static class FileLength implements LengthFunction { + public long getLength(Object context) { + if (context instanceof File) { + return ((File) context).length(); + } + return SKIP; + } + } + + public static class InputStreamAvailableLength implements LengthFunction { + public long getLength(Object context) { + if (context instanceof InputStream) { + try { + return ((InputStream) context).available(); + } catch (IOException ignore) { + // io error + return NOT_EXIST; + } + } + return SKIP; + } + } +} diff --git a/commons/src/test/java/com/navercorp/pinpoint/common/util/ContentLengthTest.java b/commons/src/test/java/com/navercorp/pinpoint/common/util/ContentLengthTest.java new file mode 100644 index 000000000000..a579d4f30188 --- /dev/null +++ b/commons/src/test/java/com/navercorp/pinpoint/common/util/ContentLengthTest.java @@ -0,0 +1,94 @@ +package com.navercorp.pinpoint.common.util; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.when; + +public class ContentLengthTest { + + @Test + public void length() throws IOException { + ContentLength.Builder builder = ContentLength.newBuilder(); + builder.addContentType(String.class); + builder.addContentType(byte[].class); + builder.addContentType(char[].class); + builder.addContentType(InputStream.class); + builder.addContentType(File.class); + ContentLength contentLength = builder.build(); + + String strContent = "abc"; + int strLength = contentLength.getLength(strContent); + org.junit.Assert.assertEquals(strContent.length(), strLength); + + byte[] byteArray = new byte[1]; + int bytesLength = contentLength.getLength(byteArray); + org.junit.Assert.assertEquals(byteArray.length, bytesLength); + + char[] charArray = new char[5]; + int charsLength = contentLength.getLength(charArray); + org.junit.Assert.assertEquals(charArray.length, charsLength); + + InputStream inputStream = mock(InputStream.class); + when(inputStream.available()).thenReturn(20); + int streamLength = contentLength.getLength(inputStream); + org.junit.Assert.assertEquals(inputStream.available(), streamLength); + + File file = mock(File.class); + when(file.length()).thenReturn(30L); + int fileLength = contentLength.getLength(file); + org.junit.Assert.assertEquals(file.length(), fileLength); + } + + @Test + public void length_function() { + ContentLength.Builder builder = ContentLength.newBuilder(); + builder.addFunction(new ContentLength.LengthFunction() { + @Override + public long getLength(Object context) { + if (context instanceof long[]) { + return ((long[]) context).length; + } + return ContentLength.SKIP; + } + }); + + ContentLength contentLength = builder.build(); + + int length = contentLength.getLength(new long[10]); + org.junit.Assert.assertEquals(10, length); + } + + @Test + public void length_unknownType() { + ContentLength.Builder builder = ContentLength.newBuilder(); + ContentLength contentLength = builder.build(); + + int length = contentLength.getLength("abc"); + org.junit.Assert.assertEquals(ContentLength.NOT_EXIST, length); + + int nullLength = contentLength.getLength(null); + org.junit.Assert.assertEquals(ContentLength.NOT_EXIST, nullLength); + } + + + @Test + public void overflow_file() { + ContentLength.Builder builder = ContentLength.newBuilder(); + builder.addContentType(File.class); + ContentLength content = builder.build(); + + File file = mock(File.class); + when(file.length()).thenReturn(Long.MAX_VALUE); + + int intLength = content.getLength(file); + org.junit.Assert.assertEquals(Integer.MAX_VALUE, intLength); + + long longLength = content.getLongLength(file); + org.junit.Assert.assertEquals(Long.MAX_VALUE, longLength); + } +} \ No newline at end of file