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

[#11021] Apply JsonFields #11027

Merged
merged 2 commits into from
May 17, 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
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,67 @@
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.collect.Iterators;

import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.RandomAccess;
import java.util.function.Function;
import java.util.stream.Stream;

@JsonSerialize(using = JsonFields.Serializer.class)
public class JsonFields<K, V> implements Iterable<JsonField<String, V>>{
public class JsonFields<K, V> implements Iterable<JsonField<K, V>>, RandomAccess {

private final Map<K, V> node;
private final JsonField<K, V>[] fields;
private final Function<K, String> nameMapper;

JsonFields(Map<K, V> node, Function<K, String> nameMapper) {
this.node = Objects.requireNonNull(node, "node");
JsonFields(JsonField<K, V>[] fields, Function<K, String> nameMapper) {
this.fields = Objects.requireNonNull(fields, "node");
this.nameMapper = Objects.requireNonNull(nameMapper, "nameMapper");
}

@Override
public String toString() {
return node.toString();
public int size() {
return fields.length;
}

public JsonField<K, V> get(int index) {
Objects.checkIndex(index, fields.length);
return fields[index];
}

public boolean isEmpty() {
return fields.length == 0;
}

@Override
public Iterator<JsonField<String, V>> iterator() {
return Iterators.transform(node.entrySet().iterator(), this::toJsonField);
public Iterator<JsonField<K, V>> iterator() {
return stream().iterator();
}

private JsonField<String, V> toJsonField(Map.Entry<K, V> entry) {
K key = entry.getKey();
String name = this.nameMapper.apply(key);
return new JsonStringField<>(name, entry.getValue());
public Stream<JsonField<K, V>> stream() {
return Arrays.stream(fields);
}

public Stream<JsonField<String, V>> nameStream() {
return stream()
.map(f -> JsonField.of(nameMapper.apply(f.name()), f.value()));
}


public static class Serializer<K, V> extends JsonSerializer<JsonFields<K, V>> {
@Override
public void serialize(JsonFields<K, V> fields, JsonGenerator gen, SerializerProvider serializers) throws IOException {
final Function<K, String> nameMapper = fields.nameMapper;

gen.writeStartObject();
for (Map.Entry<K, V> entry : fields.node.entrySet()) {
String name = nameMapper.apply(entry.getKey());
for (JsonField<K, V> entry : fields.fields) {
String name = nameMapper.apply(entry.name());
gen.writeFieldName(name);
gen.writeObject(entry.getValue());
gen.writeObject(entry.value());
}
gen.writeEndObject();
}
Expand All @@ -59,13 +74,24 @@ public static <K, V> Builder<K, V> newBuilder() {
return new Builder<>(Object::toString);
}

public static <K, V> Builder<K, V> newBuilder(Function<K, String> keyMapper) {
return new Builder<>(keyMapper);
/**
* @param nameMapper nameMapper does not guarantee uniqueness.
*/
public static <K, V> Builder<K, V> newBuilder(Function<K, String> nameMapper) {
return new Builder<>(nameMapper);
}

@Override
public String toString() {
return Arrays.toString(fields);
}

public static class Builder<K, V> {
private final Map<K, V> node;
private final Function<K, String> nameMapper;
// optional
private boolean throwIfDuplicateKeys = false;
private Comparator<JsonField<K, V>> comparator;

Builder(Function<K, String> nameMapper) {
this.node = new LinkedHashMap<>();
Expand All @@ -74,18 +100,43 @@ public static class Builder<K, V> {

public Builder<K, V> addField(K name, V value) {
Objects.requireNonNull(name, "name");
node.put(name, value);
final V duplicateKey = node.put(name, value);
if (throwIfDuplicateKeys) {
if (duplicateKey != null) {
throw new IllegalArgumentException("Duplicate key: " + name);
}
}
return this;
}

public Builder<K, V> addField(JsonField<K, V> field) {
Objects.requireNonNull(field, "field");
node.put(field.name(), field.value());

this.addField(field.name(), field.value());
return this;
}

public Builder<K, V> throwIfDuplicateKeys(boolean enable) {
this.throwIfDuplicateKeys = enable;
return this;
}

public Builder<K, V> comparator(Comparator<JsonField<K, V>> comparator) {
this.comparator = Objects.requireNonNull(comparator, "comparator");
return this;
}

public JsonFields<K, V> build() {
return new JsonFields<>(node, nameMapper);
@SuppressWarnings("unchecked")
JsonField<K, V>[] fields = new JsonField[node.size()];
int index = 0;
for (Map.Entry<K, V> entry : node.entrySet()) {
fields[index++] = JsonField.of(entry.getKey(), entry.getValue());
}
if (comparator != null) {
Arrays.sort(fields, comparator);
}
return new JsonFields<>(fields, nameMapper);
}
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.Map;

Expand Down Expand Up @@ -41,7 +42,7 @@ public String name() {
}

@Test
void testStringKey() throws Exception {
void stringKey() throws Exception {

Map<String, String> map = new LinkedHashMap<>();
map.put("key1", "value1");
Expand Down Expand Up @@ -87,7 +88,35 @@ void testIterator() {
}

@Test
public void jsonNodeFactory_sample() throws Exception {
void testSort() {
JsonFields.Builder<Integer, Integer> builder = JsonFields.newBuilder();
builder.comparator(Comparator.comparing(JsonField::name));

JsonFields<Integer, Integer> fields = builder
.addField(3, 3)
.addField(2, 2)
.addField(1, 1)
.addField(0, 0)
.build();

for (int i = 0; i < fields.size(); i++) {
JsonField<Integer, Integer> field = fields.get(i);
Assertions.assertEquals(i, field.name());
}
}

@Test
void throwIfDuplicateKeys() {
JsonFields.Builder<String, String> builder = JsonFields.newBuilder();
builder.throwIfDuplicateKeys(true);

builder.addField("a", "1");

Assertions.assertThrows(IllegalArgumentException.class, () -> builder.addField("a", "2"));
}

@Test
void jsonNodeFactory_sample() throws Exception {
JsonNodeFactory factory = JsonNodeFactory.instance;
ObjectNode jsonNodes = factory.objectNode();
jsonNodes.set("string", factory.pojoNode("value"));
Expand All @@ -96,4 +125,6 @@ public void jsonNodeFactory_sample() throws Exception {
String json = mapper.writeValueAsString(jsonNodes);
logger.debug("json {}", json);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
package com.navercorp.pinpoint.web.applicationmap.histogram;

import com.google.common.collect.Ordering;
import com.navercorp.pinpoint.common.server.util.json.JsonField;
import com.navercorp.pinpoint.common.server.util.json.JsonFields;
import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindow;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.web.applicationmap.rawdata.AgentHistogram;
import com.navercorp.pinpoint.web.applicationmap.rawdata.AgentHistogramList;
import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModel;
import com.navercorp.pinpoint.web.view.TimeViewModel;
import com.navercorp.pinpoint.web.view.id.AgentNameView;
import com.navercorp.pinpoint.web.vo.Application;
import com.navercorp.pinpoint.web.vo.stat.SampledApdexScore;
import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint;
Expand All @@ -48,8 +50,8 @@ public class AgentTimeHistogram {
private static final Double DEFAULT_MAX_APDEX_SCORE = -2D;
private static final String DEFAULT_AGENT_ID = "defaultAgentId";

private static final Comparator<AgentResponseTimeViewModel> AGENT_NAME_COMPARATOR
= Comparator.comparing(AgentResponseTimeViewModel::getAgentName);
private static final Comparator<JsonField<AgentNameView, List<TimeViewModel>>> AGENT_NAME_COMPARATOR
= Comparator.comparing((jsonField) -> jsonField.name().agentName());

private static final Ordering<TimeHistogram> histogramOrdering = Ordering.from(TimeHistogram.TIME_STAMP_ASC_COMPARATOR);

Expand All @@ -66,17 +68,17 @@ public AgentTimeHistogram(Application application, AgentHistogramList agentHisto
this.agentHistogramList = Objects.requireNonNull(agentHistogramList, "agentHistogramList");
}

public JsonFields<AgentNameView, List<TimeViewModel>> createViewModel(TimeHistogramFormat timeHistogramFormat) {

public List<AgentResponseTimeViewModel> createViewModel(TimeHistogramFormat timeHistogramFormat) {
final List<AgentResponseTimeViewModel> result = new ArrayList<>();
JsonFields.Builder<AgentNameView, List<TimeViewModel>> builder = JsonFields.newBuilder();
builder.comparator(AGENT_NAME_COMPARATOR);
for (AgentHistogram agentHistogram : agentHistogramList.getAgentHistogramList()) {
Application agentId = agentHistogram.getAgentId();
List<TimeHistogram> timeList = histogramOrdering.sortedCopy(agentHistogram.getTimeHistogram());
AgentResponseTimeViewModel model = createAgentResponseTimeViewModel(agentId, timeList, timeHistogramFormat);
result.add(model);
JsonField<AgentNameView, List<TimeViewModel>> model = createAgentResponseTimeViewModel(agentId, timeList, timeHistogramFormat);
builder.addField(model);
}
result.sort(AGENT_NAME_COMPARATOR);
return result;
return builder.build();
}

public Map<String, List<TimeHistogram>> getTimeHistogramMap() {
Expand All @@ -89,9 +91,9 @@ public Map<String, List<TimeHistogram>> getTimeHistogramMap() {
}


private AgentResponseTimeViewModel createAgentResponseTimeViewModel(Application agentName, List<TimeHistogram> timeHistogramList, TimeHistogramFormat timeHistogramFormat) {
private JsonField<AgentNameView, List<TimeViewModel>> createAgentResponseTimeViewModel(Application agentName, List<TimeHistogram> timeHistogramList, TimeHistogramFormat timeHistogramFormat) {
List<TimeViewModel> responseTimeViewModel = createResponseTimeViewModel(timeHistogramList, timeHistogramFormat);
return new AgentResponseTimeViewModel(agentName, responseTimeViewModel);
return JsonField.of(AgentNameView.of(agentName), responseTimeViewModel);
}

private List<TimeViewModel> createResponseTimeViewModel(List<TimeHistogram> timeHistogramList, TimeHistogramFormat timeHistogramFormat) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package com.navercorp.pinpoint.web.applicationmap.histogram;

import com.navercorp.pinpoint.common.server.util.time.Range;
import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModelList;
import com.navercorp.pinpoint.web.view.TimeViewModel;
import com.navercorp.pinpoint.web.view.histogram.HistogramView;
import com.navercorp.pinpoint.web.vo.Application;
import com.navercorp.pinpoint.web.vo.ResponseTime;
Expand Down Expand Up @@ -118,12 +116,9 @@ public Map<String, ResponseTimeStatics> getAgentResponseStatisticsMap() {
return map;
}

public List<TimeViewModel> getApplicationTimeHistogram(TimeHistogramFormat timeHistogramFormat) {
return applicationTimeHistogram.createViewModel(timeHistogramFormat);
}

public AgentResponseTimeViewModelList getAgentTimeHistogram(TimeHistogramFormat timeHistogramFormat) {
return new AgentResponseTimeViewModelList(agentTimeHistogram.createViewModel(timeHistogramFormat));
public AgentTimeHistogram getAgentTimeHistogram() {
return agentTimeHistogram;
}

public List<HistogramView> createAgentHistogramViewList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.navercorp.pinpoint.common.server.util.json.JsonFields;
import com.navercorp.pinpoint.common.server.util.time.Range;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.web.applicationmap.histogram.AgentTimeHistogram;
Expand All @@ -30,9 +31,9 @@
import com.navercorp.pinpoint.web.applicationmap.rawdata.AgentHistogramList;
import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkCallData;
import com.navercorp.pinpoint.web.applicationmap.rawdata.LinkCallDataMap;
import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModelList;
import com.navercorp.pinpoint.web.view.LinkSerializer;
import com.navercorp.pinpoint.web.view.TimeViewModel;
import com.navercorp.pinpoint.web.view.id.AgentNameView;
import com.navercorp.pinpoint.web.vo.Application;

import java.util.Collection;
Expand Down Expand Up @@ -213,11 +214,12 @@ public void addOutLink(LinkCallDataMap outLinkCallDataMap) {
this.outLink.addLinkDataMap(outLinkCallDataMap);
}

public AgentResponseTimeViewModelList getSourceAgentTimeSeriesHistogram() {
public JsonFields<AgentNameView, List<TimeViewModel>> getSourceAgentTimeSeriesHistogram() {
// we need Target (to)'s time since time in link is RPC-based
AgentTimeHistogramBuilder builder = new AgentTimeHistogramBuilder(toNode.getApplication(), range);
AgentTimeHistogram applicationTimeSeriesHistogram = builder.buildSource(inLink);
return new AgentResponseTimeViewModelList(applicationTimeSeriesHistogram.createViewModel(timeHistogramFormat));

return applicationTimeSeriesHistogram.createViewModel(timeHistogramFormat);
}

public AgentTimeHistogram getTargetAgentTimeHistogram() {
Expand Down
Loading
Loading