RntbdContextRequest.java
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.cosmos.implementation.directconnectivity.rntbd;
import com.azure.cosmos.implementation.UserAgentContainer;
import com.azure.cosmos.implementation.guava27.Strings;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectWriter;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.CorruptedFrameException;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import static com.azure.cosmos.implementation.HttpConstants.Versions;
import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdConstants.CURRENT_PROTOCOL_VERSION;
import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdConstants.RntbdContextRequestHeader;
import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdConstants.RntbdOperationType;
import static com.azure.cosmos.implementation.directconnectivity.rntbd.RntbdConstants.RntbdResourceType;
public final class RntbdContextRequest {
@JsonProperty
private final UUID activityId;
@JsonProperty
private final Headers headers;
RntbdContextRequest(final UUID activityId, final UserAgentContainer userAgent) {
this(activityId, new Headers(userAgent));
}
private RntbdContextRequest(final UUID activityId, final Headers headers) {
this.activityId = activityId;
this.headers = headers;
}
public UUID getActivityId() {
return this.activityId;
}
public String getClientVersion() {
return this.headers.clientVersion.getValue(String.class);
}
public static RntbdContextRequest decode(final ByteBuf in) {
final int resourceOperationTypeCode = in.getInt(in.readerIndex() + Integer.BYTES);
if (resourceOperationTypeCode != 0) {
final String reason = String.format("resourceOperationCode=0x%08X", resourceOperationTypeCode);
throw new IllegalStateException(reason);
}
final int start = in.readerIndex();
final int expectedLength = in.readIntLE();
final RntbdRequestFrame header = RntbdRequestFrame.decode(in);
final Headers headers = Headers.decode(in.readSlice(expectedLength - (in.readerIndex() - start)));
final int observedLength = in.readerIndex() - start;
if (observedLength != expectedLength) {
final String reason = Strings.lenientFormat("expectedLength=%s, observedLength=%s", expectedLength, observedLength);
throw new IllegalStateException(reason);
}
in.discardReadBytes();
return new RntbdContextRequest(header.getActivityId(), headers);
}
public void encode(final ByteBuf out) {
final int expectedLength = RntbdRequestFrame.LENGTH + this.headers.computeLength();
final int start = out.writerIndex();
out.writeIntLE(expectedLength);
final RntbdRequestFrame header = new RntbdRequestFrame(this.getActivityId(), RntbdOperationType.Connection, RntbdResourceType.Connection);
header.encode(out);
this.headers.encode(out);
final int observedLength = out.writerIndex() - start;
if (observedLength != expectedLength) {
final String reason = Strings.lenientFormat("expectedLength=%s, observedLength=%s", expectedLength, observedLength);
throw new IllegalStateException(reason);
}
}
@Override
public String toString() {
final ObjectWriter writer = RntbdObjectMapper.writer();
try {
return writer.writeValueAsString(this);
} catch (final JsonProcessingException error) {
throw new CorruptedFrameException(error);
}
}
private static final class Headers extends RntbdTokenStream<RntbdContextRequestHeader> {
private static final byte[] ClientVersion = Versions.CURRENT_VERSION.getBytes(StandardCharsets.UTF_8);
@JsonProperty
RntbdToken clientVersion;
@JsonProperty
RntbdToken protocolVersion;
@JsonProperty
RntbdToken userAgent;
Headers(final UserAgentContainer container) {
this(Unpooled.EMPTY_BUFFER);
this.clientVersion.setValue(ClientVersion);
this.userAgent.setValue(container.getUserAgent());
this.protocolVersion.setValue(CURRENT_PROTOCOL_VERSION);
}
private Headers(ByteBuf in) {
super(RntbdContextRequestHeader.set, RntbdContextRequestHeader.map, in);
this.clientVersion = this.get(RntbdContextRequestHeader.ClientVersion);
this.protocolVersion = this.get(RntbdContextRequestHeader.ProtocolVersion);
this.userAgent = this.get(RntbdContextRequestHeader.UserAgent);
}
static Headers decode(final ByteBuf in) {
return Headers.decode(new Headers(in));
}
}
}