|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "components/invalidation/public/invalidation.h" | 
|  |  | 
|  | #include <cstddef> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/json/json_string_value_serializer.h" | 
|  | #include "base/location.h" | 
|  | #include "base/rand_util.h" | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/values.h" | 
|  | #include "components/invalidation/public/ack_handler.h" | 
|  | #include "components/invalidation/public/invalidation_util.h" | 
|  |  | 
|  | namespace syncer { | 
|  |  | 
|  | namespace { | 
|  | const char kObjectIdKey[] = "objectId"; | 
|  | const char kIsUnknownVersionKey[] = "isUnknownVersion"; | 
|  | const char kVersionKey[] = "version"; | 
|  | const char kPayloadKey[] = "payload"; | 
|  | const int64 kInvalidVersion = -1; | 
|  | } | 
|  |  | 
|  | Invalidation Invalidation::Init(const invalidation::ObjectId& id, | 
|  | int64 version, | 
|  | const std::string& payload) { | 
|  | return Invalidation(id, false, version, payload, AckHandle::CreateUnique()); | 
|  | } | 
|  |  | 
|  | Invalidation Invalidation::InitUnknownVersion( | 
|  | const invalidation::ObjectId& id) { | 
|  | return Invalidation( | 
|  | id, true, kInvalidVersion, std::string(), AckHandle::CreateUnique()); | 
|  | } | 
|  |  | 
|  | Invalidation Invalidation::InitFromDroppedInvalidation( | 
|  | const Invalidation& dropped) { | 
|  | return Invalidation( | 
|  | dropped.id_, true, kInvalidVersion, std::string(), dropped.ack_handle_); | 
|  | } | 
|  |  | 
|  | scoped_ptr<Invalidation> Invalidation::InitFromValue( | 
|  | const base::DictionaryValue& value) { | 
|  | invalidation::ObjectId id; | 
|  |  | 
|  | const base::DictionaryValue* object_id_dict; | 
|  | if (!value.GetDictionary(kObjectIdKey, &object_id_dict) || | 
|  | !ObjectIdFromValue(*object_id_dict, &id)) { | 
|  | DLOG(WARNING) << "Failed to parse id"; | 
|  | return scoped_ptr<Invalidation>(); | 
|  | } | 
|  | bool is_unknown_version; | 
|  | if (!value.GetBoolean(kIsUnknownVersionKey, &is_unknown_version)) { | 
|  | DLOG(WARNING) << "Failed to parse is_unknown_version flag"; | 
|  | return scoped_ptr<Invalidation>(); | 
|  | } | 
|  | if (is_unknown_version) { | 
|  | return scoped_ptr<Invalidation>(new Invalidation( | 
|  | id, | 
|  | true, | 
|  | kInvalidVersion, | 
|  | std::string(), | 
|  | AckHandle::CreateUnique())); | 
|  | } | 
|  | int64 version = 0; | 
|  | std::string version_as_string; | 
|  | if (!value.GetString(kVersionKey, &version_as_string) | 
|  | || !base::StringToInt64(version_as_string, &version)) { | 
|  | DLOG(WARNING) << "Failed to parse version"; | 
|  | return scoped_ptr<Invalidation>(); | 
|  | } | 
|  | std::string payload; | 
|  | if (!value.GetString(kPayloadKey, &payload)) { | 
|  | DLOG(WARNING) << "Failed to parse payload"; | 
|  | return scoped_ptr<Invalidation>(); | 
|  | } | 
|  | return scoped_ptr<Invalidation>(new Invalidation( | 
|  | id, | 
|  | false, | 
|  | version, | 
|  | payload, | 
|  | AckHandle::CreateUnique())); | 
|  | } | 
|  |  | 
|  | Invalidation::~Invalidation() { | 
|  | } | 
|  |  | 
|  | invalidation::ObjectId Invalidation::object_id() const { | 
|  | return id_; | 
|  | } | 
|  |  | 
|  | bool Invalidation::is_unknown_version() const { | 
|  | return is_unknown_version_; | 
|  | } | 
|  |  | 
|  | int64 Invalidation::version() const { | 
|  | DCHECK(!is_unknown_version_); | 
|  | return version_; | 
|  | } | 
|  |  | 
|  | const std::string& Invalidation::payload() const { | 
|  | DCHECK(!is_unknown_version_); | 
|  | return payload_; | 
|  | } | 
|  |  | 
|  | const AckHandle& Invalidation::ack_handle() const { | 
|  | return ack_handle_; | 
|  | } | 
|  |  | 
|  | void Invalidation::SetAckHandler( | 
|  | base::WeakPtr<AckHandler> handler, | 
|  | scoped_refptr<base::SequencedTaskRunner> handler_task_runner) { | 
|  | ack_handler_ = handler; | 
|  | ack_handler_task_runner_ = handler_task_runner; | 
|  | } | 
|  |  | 
|  | bool Invalidation::SupportsAcknowledgement() const { | 
|  | return !!ack_handler_task_runner_.get(); | 
|  | } | 
|  |  | 
|  | void Invalidation::Acknowledge() const { | 
|  | if (SupportsAcknowledgement()) { | 
|  | ack_handler_task_runner_->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&AckHandler::Acknowledge, ack_handler_, id_, ack_handle_)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Invalidation::Drop() { | 
|  | if (SupportsAcknowledgement()) { | 
|  | ack_handler_task_runner_->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&AckHandler::Drop, ack_handler_, id_, ack_handle_)); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Invalidation::Equals(const Invalidation& other) const { | 
|  | return id_ == other.id_ && is_unknown_version_ == other.is_unknown_version_ && | 
|  | version_ == other.version_ && payload_ == other.payload_; | 
|  | } | 
|  |  | 
|  | scoped_ptr<base::DictionaryValue> Invalidation::ToValue() const { | 
|  | scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | 
|  | value->Set(kObjectIdKey, ObjectIdToValue(id_).release()); | 
|  | if (is_unknown_version_) { | 
|  | value->SetBoolean(kIsUnknownVersionKey, true); | 
|  | } else { | 
|  | value->SetBoolean(kIsUnknownVersionKey, false); | 
|  | value->SetString(kVersionKey, base::Int64ToString(version_)); | 
|  | value->SetString(kPayloadKey, payload_); | 
|  | } | 
|  | return value.Pass(); | 
|  | } | 
|  |  | 
|  | std::string Invalidation::ToString() const { | 
|  | std::string output; | 
|  | JSONStringValueSerializer serializer(&output); | 
|  | serializer.set_pretty_print(true); | 
|  | serializer.Serialize(*ToValue().get()); | 
|  | return output; | 
|  | } | 
|  |  | 
|  | Invalidation::Invalidation(const invalidation::ObjectId& id, | 
|  | bool is_unknown_version, | 
|  | int64 version, | 
|  | const std::string& payload, | 
|  | AckHandle ack_handle) | 
|  | : id_(id), | 
|  | is_unknown_version_(is_unknown_version), | 
|  | version_(version), | 
|  | payload_(payload), | 
|  | ack_handle_(ack_handle) { | 
|  | } | 
|  |  | 
|  | }  // namespace syncer |