TraceUtil.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashSet;
import java.util.Set;
final class TraceUtil {
public static void traceSend(
OutputStream str,
Instance instance,
ConnectionI connection,
Logger logger,
TraceLevels tl) {
if (tl.protocol >= 1) {
int p = str.pos();
var is = new InputStream(instance, str.getEncoding(), str.getBuffer(), false);
is.pos(0);
StringWriter s = new StringWriter();
byte type = printMessage(s, is, connection);
logger.trace(
tl.protocolCat, "sending " + getMessageTypeAsString(type) + " " + s.toString());
str.pos(p);
}
}
public static void traceRecv(
InputStream str, ConnectionI connection, Logger logger, TraceLevels tl) {
if (tl.protocol >= 1) {
int p = str.pos();
str.pos(0);
StringWriter s = new StringWriter();
byte type = printMessage(s, str, connection);
logger.trace(
tl.protocolCat,
"received " + getMessageTypeAsString(type) + " " + s.toString());
str.pos(p);
}
}
public static void trace(
String heading,
InputStream str,
ConnectionI connection,
Logger logger,
TraceLevels tl) {
if (tl.protocol >= 1) {
int p = str.pos();
str.pos(0);
StringWriter s = new StringWriter();
s.write(heading);
printMessage(s, str, connection);
logger.trace(tl.protocolCat, s.toString());
str.pos(p);
}
}
private static final Set<String> slicingIds = new HashSet<>();
public static synchronized void traceSlicing(
String kind, String typeId, String slicingCat, Logger logger) {
if (slicingIds.add(typeId)) {
StringWriter s = new StringWriter();
s.write("unknown " + kind + " type `" + typeId + "'");
logger.trace(slicingCat, s.toString());
}
}
private static void printIdentityFacetOperation(Writer out, InputStream stream) {
try {
ToStringMode toStringMode = stream.instance().toStringMode();
Identity identity = Identity.ice_read(stream);
out.write("\nidentity = " + Util.identityToString(identity, toStringMode));
String[] facet = stream.readStringSeq();
out.write("\nfacet = ");
if (facet.length > 0) {
out.write(StringUtil.escapeString(facet[0], "", toStringMode));
}
String operation = stream.readString();
out.write("\noperation = " + operation);
} catch (IOException ex) {
assert false;
}
}
private static void printRequest(StringWriter s, InputStream str) {
int requestId = str.readInt();
s.write("\nrequest id = " + requestId);
if (requestId == 0) {
s.write(" (oneway)");
}
printRequestHeader(s, str);
}
private static void printBatchRequest(StringWriter s, InputStream str) {
int batchRequestNum = str.readInt();
s.write("\nnumber of requests = " + batchRequestNum);
for (int i = 0; i < batchRequestNum; i++) {
s.write("\nrequest #" + i + ':');
printRequestHeader(s, str);
}
}
private static void printReply(StringWriter s, InputStream str) {
int requestId = str.readInt();
s.write("\nrequest id = " + requestId);
s.write("\nreply status = ");
// convert the signed byte into a positive int
int replyStatusInt = str.readByte() & 0xFF;
var replyStatus = ReplyStatus.valueOf(replyStatusInt);
if (replyStatus != null) {
s.write(replyStatus.toString());
switch (replyStatus) {
case Ok:
case UserException:
EncodingVersion v = str.skipEncapsulation();
if (!v.equals(Util.Encoding_1_0)) {
s.write("\nencoding = ");
s.write(Util.encodingVersionToString(v));
}
break;
case ObjectNotExist:
case FacetNotExist:
case OperationNotExist:
printIdentityFacetOperation(s, str);
break;
default:
s.write("\nmessage = " + str.readString());
break;
}
} else {
s.write(Integer.toString(replyStatusInt));
// Same as default case above:
s.write("\nmessage = " + str.readString());
}
}
private static void printRequestHeader(Writer out, InputStream stream) {
printIdentityFacetOperation(out, stream);
try {
byte mode = stream.readByte();
out.write("\nmode = " + (int) mode + ' ');
switch (OperationMode.values()[mode]) {
case Normal -> out.write("(normal)");
case Nonmutating -> out.write("(nonmutating)");
case Idempotent -> out.write("(idempotent)");
default -> out.write("(unknown)");
}
int sz = stream.readSize();
out.write("\ncontext = ");
while (sz-- > 0) {
String key = stream.readString();
String value = stream.readString();
out.write(key + '/' + value);
if (sz > 0) {
out.write(", ");
}
}
EncodingVersion v = stream.skipEncapsulation();
if (!v.equals(Util.Encoding_1_0)) {
out.write("\nencoding = ");
out.write(Util.encodingVersionToString(v));
}
} catch (IOException ex) {
assert false;
}
}
private static byte printHeader(Writer out, InputStream stream) {
stream.readByte(); // Don't bother printing the magic number
stream.readByte();
stream.readByte();
stream.readByte();
// byte pMajor = stream.readByte();
// byte pMinor = stream.readByte();
// out.write("\nprotocol version = " + (int)pMajor + "." + (int)pMinor);
stream.readByte(); // major
stream.readByte(); // minor
// byte eMajor = stream.readByte();
// byte eMinor = stream.readByte();
// out.write("\nencoding version = " + (int)eMajor + "." + (int)eMinor);
stream.readByte(); // major
stream.readByte(); // minor
byte type = stream.readByte();
try {
out.write("\nmessage type = " + (int) type + " (" + getMessageTypeAsString(type) + ')');
byte compress = stream.readByte();
out.write("\ncompression status = " + (int) compress + ' ');
switch (compress) {
case (byte) 0 -> out.write("(not compressed; do not compress response, if any)");
case (byte) 1 -> out.write("(not compressed; compress response, if any)");
case (byte) 2 -> out.write("(compressed; compress response, if any)");
default -> out.write("(unknown)");
}
int size = stream.readInt();
out.write("\nmessage size = " + size);
return type;
} catch (IOException ex) {
assert false;
return 0;
}
}
private static byte printMessage(StringWriter s, InputStream str, ConnectionI connection) {
byte type = printHeader(s, str);
switch (type) {
case Protocol.closeConnectionMsg, Protocol.validateConnectionMsg -> { /* we're done */ }
case Protocol.requestMsg -> printRequest(s, str);
case Protocol.requestBatchMsg -> printBatchRequest(s, str);
case Protocol.replyMsg -> printReply(s, str);
default -> {}
}
if (connection != null) {
s.write("\ntransport = " + connection.type() + "\n");
String connectionId = connection.endpoint().connectionId();
if (!connectionId.isEmpty()) {
s.write("connection ID = " + connectionId + "\n");
}
s.write(connection.toString());
} else {
s.write("\ncollocated = true");
}
return type;
}
private static String getMessageTypeAsString(byte type) {
return switch (type) {
case Protocol.requestMsg -> "request";
case Protocol.requestBatchMsg -> "batch request";
case Protocol.replyMsg -> "reply";
case Protocol.closeConnectionMsg -> "close connection";
case Protocol.validateConnectionMsg -> "validate connection";
default -> "unknown";
};
}
private TraceUtil() {}
}