blob: 68cfe02a98402855c1fa02cdd80622a893f480f5 [file] [log] [blame]
// Copyright 2012 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.
// Useful utility functions for the TICL
#include "google/cacheinvalidation/impl/proto-helpers.h"
#include <sstream>
#include "google/cacheinvalidation/client_test_internal.pb.h"
#include "google/cacheinvalidation/deps/string_util.h"
namespace invalidation {
using ::ipc::invalidation::RegistrationManagerStateP;
// Defines a ToString template method specialization for the given type.
#define DEFINE_TO_STRING(type) \
template<> \
string ProtoHelpers::ToString(const type& message)
// Creates a stringstream |stream| and emits a leading "{ " to it.
#define BEGIN() \
std::stringstream stream; \
stream << "{ "
// Emits a closing " }" on |stream| and returns the string that has been built.
#define END() \
stream << " }"; \
return stream.str()
// Defines a trivial ToString method for a type (which just returns "<type>").
#define DEFINE_TRIVIAL_TO_STRING(type) \
DEFINE_TO_STRING(type) { \
return "<" #type ">"; \
}
// Emits "field: <field value as string>" if |field| is present in |message|.
#define OPTIONAL(field) \
if (message.has_##field()) { \
stream << #field << ": " << ToString(message.field()) << " "; \
}
// Emits "field: <field value as string>" for each instance of field in message.
#define REPEATED(field) \
for (int i = 0; i < message.field##_size(); ++i) { \
stream << #field << ": " << ToString(message.field(i)) << " "; \
}
// Expands to a case branch that returns "name" if the implicitly tested
// expression is equal to the enum constant |name| in the given |type|.
#define ENUM_VALUE(type, name) case type##_##name: return #name
// Expands to a default case branch that returns the string representation of
// |message|.
#define ENUM_UNKNOWN() default: return SimpleItoa(message)
DEFINE_TO_STRING(bool) {
return message ? "true" : "false";
}
DEFINE_TO_STRING(int) {
std::stringstream stream;
stream << message;
return stream.str();
}
DEFINE_TO_STRING(int64) {
std::stringstream stream;
stream << message;
return stream.str();
}
/*
* Three arrays that store the representation of each character from 0 to 255.
* The ith number's octal representation is: CHAR_OCTAL_STRINGS1[i],
* CHAR_OCTAL_STRINGS2[i], CHAR_OCTAL_STRINGS3[i]
* <p>
* E.g., if the number 128, these arrays contain 2, 0, 0 at index 128. We use
* 3 char arrays instead of an array of strings since the code path for a
* character append operation is quite a bit shorterthan the append operation
* for strings.
*/
char ProtoHelpers::CHAR_OCTAL_STRINGS1[];
char ProtoHelpers::CHAR_OCTAL_STRINGS2[];
char ProtoHelpers::CHAR_OCTAL_STRINGS3[];
bool ProtoHelpers::is_initialized = false;
template<>
string ProtoHelpers::ToString(const string& bytes) {
// This is a racy initialization but that is ok since we are initializing to
// the same values.
if (!is_initialized) {
// Initialize the array with the Octal string values so that we do not have
// to do string.format for every byte during runtime.
for (int i = 0; i < ProtoHelpers::NUM_CHARS; i++) {
string value = StringPrintf("%03o", i);
ProtoHelpers::CHAR_OCTAL_STRINGS1[i] = value[0];
ProtoHelpers::CHAR_OCTAL_STRINGS2[i] = value[1];
ProtoHelpers::CHAR_OCTAL_STRINGS3[i] = value[2];
}
is_initialized = true;
}
string builder;
builder.reserve(3 * bytes.length() + 2);
builder += "\"";
for (size_t i = 0; i < bytes.length(); i++) {
char c = bytes[i];
switch (c) {
case '\n': builder += '\\'; builder += 'n'; break;
case '\r': builder += '\\'; builder += 'r'; break;
case '\t': builder += '\\'; builder += 't'; break;
case '\"': builder += '\\'; builder += '"'; break;
case '\\': builder += '\\'; builder += '\\'; break;
default:
if ((c >= 32) && (c < 127) && c != '\'') {
builder += c;
} else {
int byteValue = c;
if (c < 0) {
byteValue = c + 256;
}
builder += '\\';
builder += CHAR_OCTAL_STRINGS1[byteValue];
builder += CHAR_OCTAL_STRINGS2[byteValue];
builder += CHAR_OCTAL_STRINGS3[byteValue];
}
break;
}
}
builder += "\"";
return builder;
}
void ProtoHelpers::InitRegistrationP(const ObjectIdP& oid,
RegistrationP::OpType op_type, RegistrationP* reg) {
reg->mutable_object_id()->CopyFrom(oid);
reg->set_op_type(op_type);
}
void ProtoHelpers::InitRateLimitP(int window_ms, int count,
RateLimitP *rate_limit) {
rate_limit->set_window_ms(window_ms);
rate_limit->set_count(count);
}
void ProtoHelpers::InitInitializeMessage(
const ApplicationClientIdP& application_client_id, const string& nonce,
InitializeMessage* init_msg) {
init_msg->set_client_type(application_client_id.client_type());
init_msg->mutable_application_client_id()->CopyFrom(
application_client_id);
init_msg->set_nonce(nonce);
init_msg->set_digest_serialization_type(
InitializeMessage_DigestSerializationType_BYTE_BASED);
}
void ProtoHelpers::InitClientVersion(const string& platform,
const string& application_info, ClientVersion* client_version) {
Version* version = client_version->mutable_version();
version->set_major_version(Constants::kClientMajorVersion);
version->set_minor_version(Constants::kClientMinorVersion);
client_version->set_platform(platform);
client_version->set_language("C++");
client_version->set_application_info(application_info);
}
void ProtoHelpers::InitProtocolVersion(ProtocolVersion* protocol_version) {
Version* version = protocol_version->mutable_version();
version->set_major_version(Constants::kProtocolMajorVersion);
version->set_minor_version(Constants::kProtocolMinorVersion);
}
void ProtoHelpers::InitConfigVersion(Version* config_version) {
config_version->set_major_version(Constants::kConfigMajorVersion);
config_version->set_minor_version(Constants::kConfigMinorVersion);
}
DEFINE_TO_STRING(ErrorMessage::Code) {
switch (message) {
ENUM_VALUE(ErrorMessage_Code, AUTH_FAILURE);
ENUM_VALUE(ErrorMessage_Code, UNKNOWN_FAILURE);
ENUM_UNKNOWN();
}
}
DEFINE_TO_STRING(InfoRequestMessage::InfoType) {
switch (message) {
ENUM_VALUE(InfoRequestMessage_InfoType, GET_PERFORMANCE_COUNTERS);
ENUM_UNKNOWN();
}
}
DEFINE_TO_STRING(InitializeMessage::DigestSerializationType) {
switch (message) {
ENUM_VALUE(InitializeMessage_DigestSerializationType, BYTE_BASED);
ENUM_VALUE(InitializeMessage_DigestSerializationType, NUMBER_BASED);
ENUM_UNKNOWN();
}
}
DEFINE_TO_STRING(StatusP::Code) {
switch (message) {
ENUM_VALUE(StatusP_Code, SUCCESS);
ENUM_VALUE(StatusP_Code, TRANSIENT_FAILURE);
ENUM_VALUE(StatusP_Code, PERMANENT_FAILURE);
ENUM_UNKNOWN();
}
}
DEFINE_TO_STRING(RegistrationP::OpType) {
switch (message) {
ENUM_VALUE(RegistrationP_OpType, REGISTER);
ENUM_VALUE(RegistrationP_OpType, UNREGISTER);
ENUM_UNKNOWN();
}
}
DEFINE_TO_STRING(RegistrationSyncRequestMessage) {
BEGIN();
END();
}
DEFINE_TO_STRING(Version) {
BEGIN();
OPTIONAL(major_version);
OPTIONAL(minor_version);
END();
}
DEFINE_TO_STRING(ClientVersion) {
BEGIN();
OPTIONAL(version);
OPTIONAL(platform);
OPTIONAL(language);
OPTIONAL(application_info);
END();
}
DEFINE_TO_STRING(ProtocolVersion) {
BEGIN();
OPTIONAL(version);
END();
}
DEFINE_TO_STRING(InfoRequestMessage) {
BEGIN();
REPEATED(info_type);
END();
}
DEFINE_TO_STRING(ConfigChangeMessage) {
BEGIN();
OPTIONAL(next_message_delay_ms);
END();
}
DEFINE_TO_STRING(PropertyRecord) {
BEGIN();
OPTIONAL(name);
OPTIONAL(value);
END();
}
DEFINE_TO_STRING(RateLimitP) {
BEGIN();
OPTIONAL(window_ms);
OPTIONAL(count);
END();
}
DEFINE_TO_STRING(ProtocolHandlerConfigP) {
BEGIN();
OPTIONAL(batching_delay_ms);
REPEATED(rate_limit);
END();
}
DEFINE_TO_STRING(ClientConfigP) {
BEGIN();
OPTIONAL(version);
OPTIONAL(network_timeout_delay_ms);
OPTIONAL(write_retry_delay_ms);
OPTIONAL(heartbeat_interval_ms);
OPTIONAL(perf_counter_delay_ms);
OPTIONAL(max_exponential_backoff_factor);
OPTIONAL(smear_percent);
OPTIONAL(is_transient);
OPTIONAL(initial_persistent_heartbeat_delay_ms);
OPTIONAL(protocol_handler_config);
END();
}
DEFINE_TO_STRING(InfoMessage) {
BEGIN();
OPTIONAL(client_version);
REPEATED(config_parameter);
REPEATED(performance_counter);
OPTIONAL(server_registration_summary_requested);
END();
}
DEFINE_TO_STRING(ErrorMessage) {
BEGIN();
OPTIONAL(code);
OPTIONAL(description);
END();
}
DEFINE_TO_STRING(RegistrationSummary) {
BEGIN();
OPTIONAL(num_registrations);
OPTIONAL(registration_digest);
END();
}
DEFINE_TO_STRING(ObjectIdP) {
BEGIN();
OPTIONAL(source);
OPTIONAL(name);
END();
}
DEFINE_TO_STRING(InvalidationP) {
BEGIN();
OPTIONAL(object_id);
OPTIONAL(is_known_version);
OPTIONAL(version);
OPTIONAL(is_trickle_restart);
OPTIONAL(payload);
END();
}
DEFINE_TO_STRING(AckHandleP) {
BEGIN();
OPTIONAL(invalidation);
END();
}
DEFINE_TO_STRING(ApplicationClientIdP) {
BEGIN();
OPTIONAL(client_type);
OPTIONAL(client_name);
END();
}
DEFINE_TO_STRING(StatusP) {
BEGIN();
OPTIONAL(code);
OPTIONAL(description);
END();
}
DEFINE_TO_STRING(RegistrationP) {
BEGIN();
OPTIONAL(object_id);
OPTIONAL(op_type);
END();
}
DEFINE_TO_STRING(RegistrationStatus) {
BEGIN();
OPTIONAL(registration);
OPTIONAL(status);
END();
}
DEFINE_TO_STRING(ClientHeader) {
BEGIN();
OPTIONAL(protocol_version);
OPTIONAL(client_token);
OPTIONAL(registration_summary);
OPTIONAL(client_time_ms);
OPTIONAL(max_known_server_time_ms);
OPTIONAL(message_id);
END();
}
DEFINE_TO_STRING(InitializeMessage) {
BEGIN();
OPTIONAL(client_type);
OPTIONAL(nonce);
OPTIONAL(application_client_id);
OPTIONAL(digest_serialization_type);
END();
}
DEFINE_TO_STRING(RegistrationMessage) {
BEGIN();
REPEATED(registration);
END();
}
DEFINE_TO_STRING(InvalidationMessage) {
BEGIN();
REPEATED(invalidation);
END();
}
DEFINE_TO_STRING(RegistrationSubtree) {
BEGIN();
REPEATED(registered_object);
END();
}
DEFINE_TO_STRING(RegistrationSyncMessage) {
BEGIN();
REPEATED(subtree);
END();
}
DEFINE_TO_STRING(ClientToServerMessage) {
BEGIN();
OPTIONAL(header);
OPTIONAL(initialize_message);
OPTIONAL(registration_message);
OPTIONAL(registration_sync_message);
OPTIONAL(invalidation_ack_message);
OPTIONAL(info_message);
END();
}
DEFINE_TO_STRING(ServerHeader) {
BEGIN();
OPTIONAL(protocol_version);
OPTIONAL(client_token);
OPTIONAL(registration_summary);
OPTIONAL(server_time_ms);
OPTIONAL(message_id);
END();
}
DEFINE_TO_STRING(TokenControlMessage) {
BEGIN();
OPTIONAL(new_token);
END();
}
DEFINE_TO_STRING(RegistrationStatusMessage) {
BEGIN();
REPEATED(registration_status);
END();
}
DEFINE_TO_STRING(ServerToClientMessage) {
BEGIN();
OPTIONAL(header);
OPTIONAL(token_control_message);
OPTIONAL(invalidation_message);
OPTIONAL(registration_status_message);
OPTIONAL(registration_sync_request_message);
OPTIONAL(info_request_message);
END();
}
DEFINE_TO_STRING(RegistrationManagerStateP) {
BEGIN();
OPTIONAL(client_summary);
OPTIONAL(server_summary);
REPEATED(registered_objects);
END();
}
} // namespace invalidation