|
16 | 16 | */
|
17 | 17 | package org.apache.kafka.tools.consumer.group.share;
|
18 | 18 |
|
19 |
| -import org.apache.kafka.clients.consumer.ConsumerRecord; |
20 |
| -import org.apache.kafka.common.MessageFormatter; |
21 |
| -import org.apache.kafka.common.errors.UnsupportedVersionException; |
22 | 19 | import org.apache.kafka.common.protocol.ApiMessage;
|
23 |
| -import org.apache.kafka.common.protocol.ByteBufferAccessor; |
24 |
| -import org.apache.kafka.coordinator.share.generated.CoordinatorRecordType; |
25 |
| -import org.apache.kafka.coordinator.share.generated.ShareSnapshotKey; |
26 |
| -import org.apache.kafka.coordinator.share.generated.ShareSnapshotKeyJsonConverter; |
27 |
| -import org.apache.kafka.coordinator.share.generated.ShareSnapshotValue; |
28 |
| -import org.apache.kafka.coordinator.share.generated.ShareSnapshotValueJsonConverter; |
29 |
| -import org.apache.kafka.coordinator.share.generated.ShareUpdateKey; |
30 |
| -import org.apache.kafka.coordinator.share.generated.ShareUpdateKeyJsonConverter; |
31 |
| -import org.apache.kafka.coordinator.share.generated.ShareUpdateValue; |
32 |
| -import org.apache.kafka.coordinator.share.generated.ShareUpdateValueJsonConverter; |
| 20 | +import org.apache.kafka.coordinator.share.ShareCoordinatorRecordSerde; |
| 21 | +import org.apache.kafka.coordinator.share.generated.CoordinatorRecordJsonConverters; |
33 | 22 | import org.apache.kafka.tools.consumer.CoordinatorRecordMessageFormatter;
|
34 | 23 |
|
35 | 24 | import com.fasterxml.jackson.databind.JsonNode;
|
36 |
| -import com.fasterxml.jackson.databind.node.JsonNodeFactory; |
37 |
| -import com.fasterxml.jackson.databind.node.NullNode; |
38 |
| -import com.fasterxml.jackson.databind.node.ObjectNode; |
39 |
| -import com.fasterxml.jackson.databind.node.TextNode; |
40 |
| - |
41 |
| -import java.io.IOException; |
42 |
| -import java.io.PrintStream; |
43 |
| -import java.nio.ByteBuffer; |
44 |
| -import java.util.Objects; |
45 |
| -import java.util.Optional; |
46 |
| - |
47 |
| -import static java.nio.charset.StandardCharsets.UTF_8; |
48 | 25 |
|
49 | 26 | /**
|
50 | 27 | * Formatter for records of in __share_group_state topic.
|
51 | 28 | */
|
52 |
| -public class ShareGroupStateMessageFormatter implements MessageFormatter { |
53 |
| - |
54 |
| - private static final String VERSION = "version"; |
55 |
| - private static final String DATA = "data"; |
56 |
| - private static final String KEY = "key"; |
57 |
| - private static final String VALUE = "value"; |
58 |
| - private static final String UNKNOWN = "unknown"; |
59 |
| - |
60 |
| - @Override |
61 |
| - public void writeTo(ConsumerRecord<byte[], byte[]> consumerRecord, PrintStream output) { |
62 |
| - ObjectNode json = new ObjectNode(JsonNodeFactory.instance); |
63 |
| - |
64 |
| - byte[] key = consumerRecord.key(); |
65 |
| - short keyVersion = -1; |
66 |
| - if (Objects.nonNull(key)) { |
67 |
| - keyVersion = ByteBuffer.wrap(key).getShort(); |
68 |
| - JsonNode dataNode = readToKeyJson(ByteBuffer.wrap(key), keyVersion); |
69 |
| - |
70 |
| - if (dataNode instanceof NullNode) { |
71 |
| - return; |
72 |
| - } |
73 |
| - json.putObject(KEY) |
74 |
| - .put(VERSION, keyVersion) |
75 |
| - .set(DATA, dataNode); |
76 |
| - } else { |
77 |
| - json.set(KEY, NullNode.getInstance()); |
78 |
| - } |
79 |
| - |
80 |
| - byte[] value = consumerRecord.value(); |
81 |
| - if (Objects.nonNull(value)) { |
82 |
| - short valueVersion = ByteBuffer.wrap(value).getShort(); |
83 |
| - JsonNode dataNode = readToValueJson(ByteBuffer.wrap(value), keyVersion, valueVersion); |
84 |
| - |
85 |
| - json.putObject(VALUE) |
86 |
| - .put(VERSION, valueVersion) |
87 |
| - .set(DATA, dataNode); |
88 |
| - } else { |
89 |
| - json.set(VALUE, NullNode.getInstance()); |
90 |
| - } |
| 29 | +public class ShareGroupStateMessageFormatter extends CoordinatorRecordMessageFormatter { |
91 | 30 |
|
92 |
| - try { |
93 |
| - output.write(json.toString().getBytes(UTF_8)); |
94 |
| - } catch (IOException e) { |
95 |
| - throw new RuntimeException(e); |
96 |
| - } |
| 31 | + public ShareGroupStateMessageFormatter() { |
| 32 | + super(new ShareCoordinatorRecordSerde()); |
97 | 33 | }
|
98 | 34 |
|
99 |
| - private JsonNode readToKeyJson(ByteBuffer byteBuffer, short version) { |
100 |
| - return readToSnapshotMessageKey(byteBuffer) |
101 |
| - .map(logKey -> transferKeyMessageToJsonNode(logKey, version)) |
102 |
| - .orElseGet(() -> new TextNode(UNKNOWN)); |
103 |
| - } |
104 |
| - |
105 |
| - private Optional<ApiMessage> readToSnapshotMessageKey(ByteBuffer byteBuffer) { |
106 |
| - short version = byteBuffer.getShort(); |
107 |
| - try { |
108 |
| - switch (CoordinatorRecordType.fromId(version)) { |
109 |
| - case SHARE_SNAPSHOT: |
110 |
| - return Optional.of(new ShareSnapshotKey(new ByteBufferAccessor(byteBuffer), version)); |
111 |
| - case SHARE_UPDATE: |
112 |
| - return Optional.of(new ShareUpdateKey(new ByteBufferAccessor(byteBuffer), version)); |
113 |
| - default: |
114 |
| - return Optional.empty(); |
115 |
| - } |
116 |
| - } catch (UnsupportedVersionException ex) { |
117 |
| - return Optional.empty(); |
118 |
| - } |
119 |
| - } |
120 |
| - |
121 |
| - private JsonNode transferKeyMessageToJsonNode(ApiMessage logKey, short keyVersion) { |
122 |
| - if (logKey instanceof ShareSnapshotKey) { |
123 |
| - return ShareSnapshotKeyJsonConverter.write((ShareSnapshotKey) logKey, keyVersion); |
124 |
| - } else if (logKey instanceof ShareUpdateKey) { |
125 |
| - return ShareUpdateKeyJsonConverter.write((ShareUpdateKey) logKey, keyVersion); |
126 |
| - } |
127 |
| - return new TextNode(UNKNOWN); |
128 |
| - } |
129 |
| - |
130 |
| - /** |
131 |
| - * Here the valueVersion is not enough to identity the deserializer for the ByteBuffer. |
132 |
| - * This is because both {@link ShareSnapshotValue} and {@link ShareUpdateValue} have version 0 |
133 |
| - * as per RPC spec. |
134 |
| - * To differentiate, we need to use the corresponding key versions. This is acceptable as |
135 |
| - * the records will always appear in pairs (key, value). However, this means that we cannot |
136 |
| - * extend {@link CoordinatorRecordMessageFormatter} as it requires overriding |
137 |
| - * readToValueJson whose signature does not allow for passing keyversion. |
138 |
| - * |
139 |
| - * @param byteBuffer - Represents the raw data read from the topic |
140 |
| - * @param keyVersion - Version of the actual key component of the data read from topic |
141 |
| - * @param valueVersion - Version of the actual value component of the data read from topic |
142 |
| - * @return JsonNode corresponding to the raw data value component |
143 |
| - */ |
144 |
| - protected JsonNode readToValueJson(ByteBuffer byteBuffer, short keyVersion, short valueVersion) { |
145 |
| - return readToSnapshotMessageValue(byteBuffer, keyVersion) |
146 |
| - .map(logValue -> transferValueMessageToJsonNode(logValue, valueVersion)) |
147 |
| - .orElseGet(() -> new TextNode(UNKNOWN)); |
| 35 | + @Override |
| 36 | + protected boolean isRecordTypeAllowed(short recordType) { |
| 37 | + return true; |
148 | 38 | }
|
149 | 39 |
|
150 |
| - private JsonNode transferValueMessageToJsonNode(ApiMessage logValue, short version) { |
151 |
| - if (logValue instanceof ShareSnapshotValue) { |
152 |
| - return ShareSnapshotValueJsonConverter.write((ShareSnapshotValue) logValue, version); |
153 |
| - } else if (logValue instanceof ShareUpdateValue) { |
154 |
| - return ShareUpdateValueJsonConverter.write((ShareUpdateValue) logValue, version); |
155 |
| - } |
156 |
| - return new TextNode(UNKNOWN); |
| 40 | + @Override |
| 41 | + protected JsonNode keyAsJson(ApiMessage message) { |
| 42 | + return CoordinatorRecordJsonConverters.writeRecordKeyAsJson(message); |
157 | 43 | }
|
158 | 44 |
|
159 |
| - private Optional<ApiMessage> readToSnapshotMessageValue(ByteBuffer byteBuffer, short keyVersion) { |
160 |
| - short version = byteBuffer.getShort(); |
161 |
| - // Check the key version here as that will determine which type |
162 |
| - // of value record to fetch. Both share update and share snapshot |
163 |
| - // value records can have the same version. |
164 |
| - try { |
165 |
| - switch (CoordinatorRecordType.fromId(keyVersion)) { |
166 |
| - case SHARE_SNAPSHOT: |
167 |
| - return Optional.of(new ShareSnapshotValue(new ByteBufferAccessor(byteBuffer), version)); |
168 |
| - case SHARE_UPDATE: |
169 |
| - return Optional.of(new ShareUpdateValue(new ByteBufferAccessor(byteBuffer), version)); |
170 |
| - default: |
171 |
| - return Optional.empty(); |
172 |
| - } |
173 |
| - } catch (UnsupportedVersionException ex) { |
174 |
| - return Optional.empty(); |
175 |
| - } |
| 45 | + @Override |
| 46 | + protected JsonNode valueAsJson(ApiMessage message, short version) { |
| 47 | + return CoordinatorRecordJsonConverters.writeRecordValueAsJson(message, version); |
176 | 48 | }
|
177 | 49 | }
|
0 commit comments