/* * Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.ipc.invalidation.common; import com.google.common.base.Receiver; import com.google.ipc.invalidation.util.Bytes; import com.google.ipc.invalidation.util.LazyString; import com.google.ipc.invalidation.util.TextBuilder; import com.google.protobuf.ByteString; import com.google.protos.ipc.invalidation.ClientProtocol.ApplicationClientIdP; import com.google.protos.ipc.invalidation.ClientProtocol.ClientHeader; import com.google.protos.ipc.invalidation.ClientProtocol.ClientToServerMessage; import com.google.protos.ipc.invalidation.ClientProtocol.ConfigChangeMessage; import com.google.protos.ipc.invalidation.ClientProtocol.ErrorMessage; import com.google.protos.ipc.invalidation.ClientProtocol.InfoMessage; import com.google.protos.ipc.invalidation.ClientProtocol.InfoRequestMessage; import com.google.protos.ipc.invalidation.ClientProtocol.InitializeMessage; import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationMessage; import com.google.protos.ipc.invalidation.ClientProtocol.InvalidationP; import com.google.protos.ipc.invalidation.ClientProtocol.ObjectIdP; import com.google.protos.ipc.invalidation.ClientProtocol.PropertyRecord; import com.google.protos.ipc.invalidation.ClientProtocol.ProtocolVersion; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationMessage; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationP; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatus; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationStatusMessage; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSubtree; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSummary; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncMessage; import com.google.protos.ipc.invalidation.ClientProtocol.RegistrationSyncRequestMessage; import com.google.protos.ipc.invalidation.ClientProtocol.ServerHeader; import com.google.protos.ipc.invalidation.ClientProtocol.ServerToClientMessage; import com.google.protos.ipc.invalidation.ClientProtocol.StatusP; import com.google.protos.ipc.invalidation.ClientProtocol.TokenControlMessage; import java.util.Collection; /** * Utilities to make it easier/cleaner/shorter for printing and converting protobufs to strings in * . This class exposes methods to return objects such that their toString method returns a * compact representation of the proto. These methods can be used in the Ticl * */ public class CommonProtoStrings2 { // // Implementation notes: The following methods return the object as mentioned above for different // protos. Each method (except for a couple of them) essentially calls a private static method // that uses a TextBuilder to construct the final string. Each method has the following spec: // Returns a compact string representation for {@code <parameter-name>} for logging // /** See spec in implementation notes. */ public static Object toLazyCompactString(final ByteString byteString) { if (byteString == null) { return null; } return new Object() { @Override public String toString() { return Bytes.toString(byteString.toByteArray()); } }; } /** See spec in implementation notes. */ public static Object toLazyCompactString(final byte[] bytes) { if (bytes == null) { return null; } return new Object() { @Override public String toString() { return Bytes.toString(bytes); } }; } /** See spec in implementation notes. */ public static Object toLazyCompactString(final ObjectIdP objectId) { return LazyString.toLazyCompactString(objectId, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, objectId); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final InvalidationP invalidation) { return LazyString.toLazyCompactString(invalidation, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, invalidation); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final RegistrationP registration) { return LazyString.toLazyCompactString(registration, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, registration); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final ApplicationClientIdP applicationId) { return LazyString.toLazyCompactString(applicationId, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, applicationId); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final RegistrationSummary regSummary) { return LazyString.toLazyCompactString(regSummary, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, regSummary); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final InfoMessage infoMessage) { return LazyString.toLazyCompactString(infoMessage, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, infoMessage); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactString(final RegistrationSyncMessage syncMessage) { return LazyString.toLazyCompactString(syncMessage, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, syncMessage); } }); } /** See spec in implementation notes and toCompactString for ClientToServerMessage. */ public static Object toLazyCompactString(final ClientToServerMessage message, final boolean printHighFrequencyMessages) { return LazyString.toLazyCompactString(message, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, message, printHighFrequencyMessages); } }); } /** See spec in implementation notes and toCompactString for ServerToClientMessage. */ public static Object toLazyCompactString(final ServerToClientMessage message, final boolean printHighFrequencyMessages) { return LazyString.toLazyCompactString(message, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactString(builder, message, printHighFrequencyMessages); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactStringForObjectIds( final Collection<ObjectIdP> objectIds) { return LazyString.toLazyCompactString(objectIds, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactStringForObjectIds(builder, objectIds); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactStringForInvalidations( final Collection<InvalidationP> invalidations) { return LazyString.toLazyCompactString(invalidations, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactStringForInvalidations(builder, invalidations); } }); } /** See spec in implementation notes. */ public static Object toLazyCompactStringForRegistrations( final Collection<RegistrationP> registrations) { return LazyString.toLazyCompactString(registrations, new Receiver<TextBuilder>() { @Override public void accept(TextBuilder builder) { toCompactStringForRegistrations(builder, registrations); } }); } // // Implementation notes: The following helper methods do the actual conversion of the proto into // the compact representation in the given builder. Each method has the following spec: // Adds a compact representation for {@code <parameter-name>} to {@code builder} and // returns {@code builder}. // TODO: Look into building indirection tables for the collections to avoid // code duplication. // /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, ByteString byteString) { if (byteString == null) { return builder; } return Bytes.toCompactString(builder, byteString.toByteArray()); } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, ObjectIdP objectId) { if (objectId == null) { return builder; } builder.appendFormat("(Obj: %s, ", objectId.getSource()); toCompactString(builder, objectId.getName()); builder.append(')'); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, InvalidationP invalidation) { if (invalidation == null) { return builder; } builder.append("(Inv: "); toCompactString(builder, invalidation.getObjectId()); builder.append(", "); if (invalidation.getIsTrickleRestart()) { builder.append("<"); } builder.append(invalidation.getVersion()); if (invalidation.hasPayload()) { builder.append(", P:"); toCompactString(builder, invalidation.getPayload()); } builder.append(')'); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactStringForInvalidations(TextBuilder builder, final Collection<InvalidationP> invalidations) { if (invalidations == null) { return builder; } boolean first = true; for (InvalidationP invalidation : invalidations) { if (!first) { builder.append(", "); } toCompactString(builder, invalidation); first = false; } return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, StatusP status) { if (status == null) { return builder; } builder.appendFormat("Status: %s", status.getCode()); if (status.hasDescription()) { builder.appendFormat(", Desc: %s", status.getDescription()); } return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationP regOp) { if (regOp == null) { return builder; } builder.appendFormat("RegOp: %s, ", regOp.getOpType() == RegistrationP.OpType.REGISTER ? "R" : "U"); toCompactString(builder, regOp.getObjectId()); return builder; } public static TextBuilder toCompactString(TextBuilder builder, RegistrationStatus regStatus) { if (regStatus == null) { return builder; } builder.append('<'); toCompactString(builder, regStatus.getRegistration()); builder.append(", "); toCompactString(builder, regStatus.getStatus()); builder.append('>'); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactStringForRegistrations(TextBuilder builder, Collection<RegistrationP> registrations) { if (registrations == null) { return builder; } boolean first = true; builder.append("RegOps: "); for (RegistrationP registration : registrations) { if (!first) { builder.append(", "); } toCompactString(builder, registration); first = false; } return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactStringForRegistrationStatuses(TextBuilder builder, Collection<RegistrationStatus> registrationStatuses) { if (registrationStatuses == null) { return builder; } boolean first = true; builder.append("RegOps: "); for (RegistrationStatus registrationStatus : registrationStatuses) { if (!first) { builder.append(", "); } toCompactString(builder, registrationStatus); first = false; } return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactStringForObjectIds(TextBuilder builder, Collection<ObjectIdP> objectIds) { if (objectIds == null) { return builder; } boolean first = true; builder.append("ObjectIds: "); for (ObjectIdP objectId : objectIds) { if (!first) { builder.append(", "); } toCompactString(builder, objectId); first = false; } return builder; } /** See spec in implementation notes. */ private static TextBuilder toCompactString(TextBuilder builder, ApplicationClientIdP applicationClientId) { if (applicationClientId == null) { return builder; } builder.appendFormat("(Ceid: "); toCompactString(builder, applicationClientId.getClientName()); builder.append(')'); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationSummary regSummary) { if (regSummary == null) { return builder; } builder.appendFormat("<RegSummary: Num = %d, Hash = ", regSummary.getNumRegistrations()); CommonProtoStrings2.toCompactString(builder, regSummary.getRegistrationDigest()); builder.append('>'); return builder; } public static TextBuilder toCompactString(TextBuilder builder, ProtocolVersion protocolVersion) { if (protocolVersion == null) { return builder; } builder.appendFormat("%d.%d", protocolVersion.getVersion().getMajorVersion(), protocolVersion.getVersion().getMinorVersion()); return builder; } // Print methods for every client-to-server message type. /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, ClientHeader header) { if (header == null) { return builder; } builder.append("C2S: "); toCompactString(builder, header.getProtocolVersion()); builder.appendFormat(", MsgId: %s, Num regs = %s, Token = ", header.getMessageId(), header.getRegistrationSummary().getNumRegistrations()); toCompactString(builder, header.getClientToken()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, InitializeMessage initializeMessage) { if (initializeMessage == null) { return builder; } builder.appendFormat("InitMsg: Client Type: %d, ", initializeMessage.getClientType()); toCompactString(builder, initializeMessage.getApplicationClientId()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationMessage registrationMessage) { if (registrationMessage == null) { return builder; } builder.appendFormat("RegMsg: "); toCompactStringForRegistrations(builder, registrationMessage.getRegistrationList()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationSyncMessage syncMessage) { if (syncMessage == null) { return builder; } RegistrationSubtree subtree = syncMessage.getSubtree(0); builder.appendFormat("RegSyncMsg: Num regs: %d, Regs: ", subtree.getRegisteredObjectCount()); toCompactStringForObjectIds(builder, subtree.getRegisteredObjectList()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, InfoMessage infoMessage) { if (infoMessage == null) { return builder; } builder.appendFormat("InfoMsg: Platform = %s, Is_summary_requested = %s, Perf counters: ", infoMessage.getClientVersion().getPlatform(), infoMessage.getServerRegistrationSummaryRequested()); boolean first = true; for (PropertyRecord record : infoMessage.getPerformanceCounterList()) { if (!first) { builder.append(", "); } builder.appendFormat("%s = %d", record.getName(), record.getValue()); first = false; } return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, InvalidationMessage invMessage) { if (invMessage == null) { return builder; } builder.appendFormat("InvMsg: "); toCompactStringForInvalidations(builder, invMessage.getInvalidationList()); return builder; } // Print methods for every server-to-client message type. public static TextBuilder toCompactString(TextBuilder builder, ServerHeader header) { if (header == null) { return builder; } builder.append("S2C: "); toCompactString(builder, header.getProtocolVersion()); builder.appendFormat(", MsgId: %s, Num regs = %s, Token = ", header.getMessageId(), header.getRegistrationSummary().getNumRegistrations()); toCompactString(builder, header.getClientToken()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, TokenControlMessage tokenControlMessage) { if (tokenControlMessage == null) { return builder; } builder.append("TokenMsg: "); toCompactString(builder, tokenControlMessage.getNewToken()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationStatusMessage regStatusMessage) { if (regStatusMessage == null) { return builder; } builder.append("RegStatusMsg: "); toCompactStringForRegistrationStatuses(builder, regStatusMessage.getRegistrationStatusList()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, RegistrationSyncRequestMessage regSyncRequestMessage) { if (regSyncRequestMessage == null) { return builder; } builder.append("RegSyncRequestMsg: "); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, InfoRequestMessage infoRequestMessage) { if (infoRequestMessage == null) { return builder; } builder.append("InfoRequestMsg:"); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, ConfigChangeMessage configChangeMessage) { if (configChangeMessage == null) { return builder; } builder.appendFormat("ConfigChangeMsg: %d", configChangeMessage.getNextMessageDelayMs()); return builder; } /** See spec in implementation notes. */ public static TextBuilder toCompactString(TextBuilder builder, ErrorMessage errorMessage) { if (errorMessage == null) { return builder; } builder.appendFormat("ErrorMsg: %s, %s", errorMessage.getCode(), errorMessage.getDescription()); return builder; } /** * If {@code printHighFrequencyMessages} is true, logs sub-messages that are exchanged at a high * frequency between the client and the registrar, e.g., invalidation ack message, heartbeat * message. */ public static TextBuilder toCompactString(TextBuilder builder, ClientToServerMessage msg, boolean printHighFrequencyMessages) { // Print the header and any sub-messages in the message. toCompactString(builder, msg.getHeader()); builder.append(','); if (msg.hasInitializeMessage()) { toCompactString(builder, msg.getInitializeMessage()); builder.append(','); } if (msg.hasRegistrationMessage()) { toCompactString(builder, msg.getRegistrationMessage()); builder.append(','); } if (msg.hasRegistrationSyncMessage()) { toCompactString(builder, msg.getRegistrationSyncMessage()); builder.append(','); } if (printHighFrequencyMessages && msg.hasInvalidationAckMessage()) { toCompactString(builder, msg.getInvalidationAckMessage()); builder.append(','); } if (printHighFrequencyMessages && msg.hasInfoMessage()) { toCompactString(builder, msg.getInfoMessage()); builder.append(','); } return builder; } /** * If {@code printHighFrequencyMessages} is true, logs sub-messages that are exchanged at a high * frequency between the client and the registrar (if they are the only messages present), * e.g., invalidation message. */ public static TextBuilder toCompactString(TextBuilder builder, ServerToClientMessage msg, boolean printHighFrequencyMessages) { // Print the header and any sub-messages in the message. toCompactString(builder, msg.getHeader()); builder.append(','); if (msg.hasTokenControlMessage()) { toCompactString(builder, msg.getTokenControlMessage()); builder.append(','); } if (printHighFrequencyMessages && msg.hasInvalidationMessage()) { toCompactString(builder, msg.getInvalidationMessage()); builder.append(','); } if (msg.hasErrorMessage()) { toCompactString(builder, msg.getErrorMessage()); builder.append(','); } if (msg.hasRegistrationSyncRequestMessage()) { toCompactString(builder, msg.getRegistrationSyncRequestMessage()); builder.append(','); } if (msg.hasRegistrationStatusMessage()) { toCompactString(builder, msg.getRegistrationStatusMessage()); builder.append(','); } if (msg.hasInfoRequestMessage()) { toCompactString(builder, msg.getInfoRequestMessage()); builder.append(','); } if (msg.hasConfigChangeMessage()) { toCompactString(builder, msg.getConfigChangeMessage()); builder.append(','); } return builder; } private CommonProtoStrings2() { // To prevent instantiation } }