Index: chromecast/base/device_capabilities.h |
diff --git a/chromecast/base/device_capabilities.h b/chromecast/base/device_capabilities.h |
index bffd37a0e6a60782dcfe8b8b690c2bc188428529..d5552d1caa6e8feaa71db225a216005f0ced7cd4 100644 |
--- a/chromecast/base/device_capabilities.h |
+++ b/chromecast/base/device_capabilities.h |
@@ -7,6 +7,8 @@ |
#include <string> |
+#include "base/macros.h" |
+#include "base/memory/ref_counted.h" |
#include "base/memory/scoped_ptr.h" |
namespace base { |
@@ -28,14 +30,22 @@ namespace chromecast { |
// system beforehand and are introduced by external parties. These capabilites |
// are stored and then forwarded to app servers that use them to determine how |
// to interact with the device. |
+// |
+// Thread Safety: |
+// Observers can be added from any thread. Each Observer is guaranteed to be |
+// notified on same thread that it was added on and must be removed on the same |
+// thread that it was added on. |
+// |
+// Validators can be registered from any thread. Each Validator's Validate() |
+// method is guaranteed to be called on same thread that the Validator was |
+// registered on. The Validator must be unregistered on the same thread |
+// that it was registered on. |
+// |
+// All other methods can be called safely from any thread. |
// TODO(esum): |
-// 1) A pure virtual interface with implementation files is no longer needed |
-// now that this file resides in chromecast/base. Change it such that there |
-// is just device_capabilities.h/cc. |
-// 2) Make class thread-safe with locking. |
-// 3) Add WifiSupported, HotspotSupported, and MultizoneSupported capabilities. |
-// 4) It's not ideal to have the accessors (BluetoothSupported(), etc.) not |
+// 1) Add WifiSupported, HotspotSupported, and MultizoneSupported capabilities. |
+// 2) It's not ideal to have the accessors (BluetoothSupported(), etc.) not |
// be valid initially until the capability gets registered. We might want |
// to use some kind of builder class to solve this. |
class DeviceCapabilities { |
@@ -86,10 +96,44 @@ class DeviceCapabilities { |
DISALLOW_COPY_AND_ASSIGN(Validator); |
}; |
+ // Class used to store/own capabilities-related data. It is immutable and |
+ // RefCountedThreadSafe, so client code can freely query it throughout its |
+ // lifetime without worrying about the data getting invalidated in any way. |
+ class Data : public base::RefCountedThreadSafe<Data> { |
+ public: |
+ // Accessor for complete capabilities in dictionary format. |
+ const base::DictionaryValue& dictionary() const { |
+ return *dictionary_.get(); |
+ } |
+ |
+ // Accessor for complete capabilities string in JSON format. |
+ const std::string& json_string() const { return *json_string_.get(); } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<Data>; |
+ // DeviceCapabilities should be the only one responsible for Data |
+ // construction. See CreateData() methods. |
+ friend class DeviceCapabilities; |
+ |
+ // Constructs empty dictionary with no capabilities. |
+ Data(); |
+ // Uses |dictionary| as capabilities dictionary. |
+ explicit Data(scoped_ptr<const base::DictionaryValue> dictionary); |
+ ~Data(); |
+ |
+ const scoped_ptr<const base::DictionaryValue> dictionary_; |
+ const scoped_ptr<const std::string> json_string_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Data); |
+ }; |
+ |
// Default Capability keys |
static const char kKeyBluetoothSupported[]; |
static const char kKeyDisplaySupported[]; |
+ // This class should get destroyed after all Validators have been |
+ // unregistered, all Observers have been removed, and the class is no longer |
+ // being accessed. |
virtual ~DeviceCapabilities() {} |
// Create empty instance with no capabilities. Although the class is not |
@@ -109,16 +153,17 @@ class DeviceCapabilities { |
// farther down. For example, "foo" is a valid value for |key|, but "foo.bar" |
// is not. Note that if "foo.bar" is updated in SetCapability(), the |
// Validate() method for "foo"'s Validator will be called, with a |path| of |
- // "foo.bar". Both Register() and Unregister() must be called on cast |
- // receiver main thread; the Validator provided will also be called on cast |
- // receiver main thread. Note that this method does not add or modify |
- // the capability. To do this, SetCapability() should be called, or |
- // Validators can call SetValidatedValue(). |
+ // "foo.bar". Note that this method does not add or modify the capability. |
+ // To do this, SetCapability() should be called, or Validators can call |
+ // SetValidatedValue(). This method is synchronous to ensure Validators know |
+ // exactly when they may start receiving validation requests. |
virtual void Register(const std::string& key, |
Validator* validator) = 0; |
// Unregisters Validator for |key|. |validator| argument must match |
// |validator| argument that was passed in to Register() for |key|. Note that |
- // the capability and its value remain untouched. |
+ // the capability and its value remain untouched. This method is synchronous |
+ // to ensure Validators know exactly when they will stop receiving validation |
+ // requests. |
virtual void Unregister(const std::string& key, |
const Validator* validator) = 0; |
// Gets the Validator currently registered for |key|. Returns nullptr if |
@@ -131,18 +176,17 @@ class DeviceCapabilities { |
virtual bool BluetoothSupported() const = 0; |
virtual bool DisplaySupported() const = 0; |
- // Gets the value of |path|. If capability at |path| does not exist, |
- // |out_value| remains untouched. Returns true if the capability has been |
- // successfully retrieved. Note that this does NOT perform a deep copy, and |
- // DeviceCapabilities still owns the memory returned through |out_value|. |
- virtual bool GetCapability(const std::string& path, |
- const base::Value** out_value) const = 0; |
- |
- // Returns the complete capability string (JSON format). |
- virtual const std::string& GetCapabilitiesString() const = 0; |
+ // Returns a deep copy of the value at |path|. If the capability at |path| |
+ // does not exist, a null scoped_ptr is returned. |
+ virtual scoped_ptr<base::Value> GetCapability( |
+ const std::string& path) const = 0; |
- // Returns the capabilities dictionary. |
- virtual const base::DictionaryValue* GetCapabilities() const = 0; |
+ // Use this method to access dictionary and JSON string. No deep copying is |
+ // performed, so this method is inexpensive. Note that any capability updates |
+ // that occur after GetData() has been called will not be reflected in the |
+ // returned scoped_refptr. You can think of this method as taking a snapshot |
+ // of the capabilities when it gets called. |
+ virtual scoped_refptr<Data> GetData() const = 0; |
// Updates the value at |path| to |proposed_value| if |path| already exists |
// and adds new capability if |path| doesn't. Note that if a key has been |
@@ -151,11 +195,11 @@ class DeviceCapabilities { |
// Ex: If "foo" has a Validator registered, a |path| of "foo.bar" |
// will cause |proposed_value| to go through the Validator's Validate() |
// method. Client code may use the Observer interface to determine the |
- // ultimate value used. |
+ // ultimate value used. This method is asynchronous. |
virtual void SetCapability(const std::string& path, |
scoped_ptr<base::Value> proposed_value) = 0; |
// Iterates through entries in |dict_value| and calls SetCapability() for |
- // each one. |
+ // each one. This method is asynchronous. |
virtual void MergeDictionary(const base::DictionaryValue& dict_value) = 0; |
// Adds/removes an observer. It doesn't take the ownership of |observer|. |
@@ -165,10 +209,18 @@ class DeviceCapabilities { |
protected: |
DeviceCapabilities() {} |
+ // For derived implementation classes to create Data instances since they do |
+ // not have access to Data constructors. |
+ // Creates empty dictionary with no capabilities. |
+ static scoped_refptr<Data> CreateData(); |
+ // Uses |dictionary| as capabilities dictionary. |
+ static scoped_refptr<Data> CreateData( |
+ scoped_ptr<const base::DictionaryValue> dictionary); |
+ |
private: |
// Does actual internal update of |path| to |new_value|. |
- virtual void SetValidatedValueInternal(const std::string& path, |
- scoped_ptr<base::Value> new_value) = 0; |
+ virtual void SetValidatedValue(const std::string& path, |
+ scoped_ptr<base::Value> new_value) = 0; |
DISALLOW_COPY_AND_ASSIGN(DeviceCapabilities); |
}; |