[shill] Enable the getting of properties, and wire to dbus.

PropertyStore exposes getters for iterators pointing to the beginning
and end of its property maps, and a static utility method in DBusAdaptor
uses these to iterate through all the properties in the PropertyStore and build
up a map of property name -> DBus::Variant-wrapped value.

BUG=chromium-os:16343
TEST=unit tests

Change-Id: I85ebbaee167ab2feed0fcf8fe654274de352aca0
Reviewed-on: http://gerrit.chromium.org/gerrit/3359
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/accessor_interface.h b/accessor_interface.h
index 916a976..dfaf0fb 100644
--- a/accessor_interface.h
+++ b/accessor_interface.h
@@ -34,16 +34,17 @@
   DISALLOW_COPY_AND_ASSIGN(AccessorInterface);
 };
 
+typedef std::vector<std::string> Strings;
+typedef std::map<std::string, std::string> Stringmap;
+
 // Using a smart pointer here allows pointers to classes derived from
 // AccessorInterface<> to be stored in maps and other STL container types.
 typedef std::tr1::shared_ptr<AccessorInterface<bool> > BoolAccessor;
 typedef std::tr1::shared_ptr<AccessorInterface<int16> > Int16Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<int32> > Int32Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<std::string> > StringAccessor;
-typedef std::tr1::shared_ptr<
-    AccessorInterface<std::map<std::string, std::string> > > StringmapAccessor;
-typedef std::tr1::shared_ptr<
-    AccessorInterface<std::vector<std::string> > > StringsAccessor;
+typedef std::tr1::shared_ptr<AccessorInterface<Stringmap> > StringmapAccessor;
+typedef std::tr1::shared_ptr<AccessorInterface<Strings> > StringsAccessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint8> > Uint8Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint16> > Uint16Accessor;
 typedef std::tr1::shared_ptr<AccessorInterface<uint32> > Uint32Accessor;
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 5efe938..75074ab 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -47,39 +47,52 @@
 }
 
 TEST_F(CellularTest, Dispatch) {
-  ::DBus::Error e1, e2, e3, e4, e5;
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(
-      device_.get(),
-      flimflam::kCellularAllowRoamingProperty,
-      PropertyStoreTest::kBoolV,
-      e1));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
-                                          flimflam::kScanIntervalProperty,
-                                          PropertyStoreTest::kUint16V,
-                                          e2));
-
-  // Ensure that an attempt to write a R/O property returns InvalidArgs error.
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
-                                           flimflam::kAddressProperty,
-                                           PropertyStoreTest::kStringV,
-                                           e3));
-  EXPECT_EQ(invalid_args_, e3.name());
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
-                                           flimflam::kCarrierProperty,
-                                           PropertyStoreTest::kStringV,
-                                           e4));
-  EXPECT_EQ(invalid_args_, e4.name());
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
-                                           flimflam::kPRLVersionProperty,
-                                           PropertyStoreTest::kInt16V,
-                                           e5));
-  EXPECT_EQ(invalid_args_, e5.name());
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(
+        device_.get(),
+        flimflam::kCellularAllowRoamingProperty,
+        PropertyStoreTest::kBoolV,
+        &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
+                                            flimflam::kScanIntervalProperty,
+                                            PropertyStoreTest::kUint16V,
+                                            &error));
+  }
+  // Ensure that attempting to write a R/O property returns InvalidArgs error.
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
+                                             flimflam::kAddressProperty,
+                                             PropertyStoreTest::kStringV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
+                                             flimflam::kCarrierProperty,
+                                             PropertyStoreTest::kStringV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
+                                             flimflam::kPRLVersionProperty,
+                                             PropertyStoreTest::kInt16V,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
 }
 
 TEST_P(CellularTest, TestProperty) {
   // Ensure that an attempt to write unknown properties returns InvalidProperty.
   ::DBus::Error error;
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), error));
+  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), &error));
   EXPECT_EQ(invalid_prop_, error.name());
 }
 
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index e93efd7..b6dcd28 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -34,9 +34,9 @@
 bool DBusAdaptor::DispatchOnType(PropertyStore *store,
                                  const string &name,
                                  const ::DBus::Variant &value,
-                                 ::DBus::Error &error) {
+                                 ::DBus::Error *error) {
   if (!store->Contains(name)) {
-    Error(Error::kInvalidProperty, name + " is invalid.").ToDBusError(&error);
+    Error(Error::kInvalidProperty, name + " is invalid.").ToDBusError(error);
     return false;
   }
   bool set = false;
@@ -68,11 +68,63 @@
     NOTREACHED();
 
   if (!set)
-    e.ToDBusError(&error);
+    e.ToDBusError(error);
   return set;
 }
 
 // static
+bool DBusAdaptor::GetProperties(PropertyStore *store,
+                                map<string, ::DBus::Variant> *out,
+                                ::DBus::Error *error) {
+  {
+    PropertyConstIterator<bool> it = store->GetBoolPropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = BoolToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<int16> it = store->GetInt16PropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = Int16ToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<int32> it = store->GetInt32PropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = Int32ToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<string> it = store->GetStringPropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = StringToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<Stringmap> it = store->GetStringmapPropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = StringmapToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<Strings> it = store->GetStringsPropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = StringsToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<uint8> it = store->GetUint8PropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = ByteToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<uint16> it = store->GetUint16PropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = Uint16ToVariant(it.Value());
+  }
+  {
+    PropertyConstIterator<uint32> it = store->GetUint32PropertiesIter();
+    for ( ; !it.AtEnd(); it.Advance())
+      (*out)[it.Key()] = Uint32ToVariant(it.Value());
+  }
+  return true;
+}
+
+// static
 ::DBus::Variant DBusAdaptor::BoolToVariant(bool value) {
   ::DBus::Variant v;
   v.writer().append_bool(value);
diff --git a/dbus_adaptor.h b/dbus_adaptor.h
index 5de652b..42c8d48 100644
--- a/dbus_adaptor.h
+++ b/dbus_adaptor.h
@@ -28,7 +28,10 @@
   static bool DispatchOnType(PropertyStore *store,
                              const std::string &name,
                              const ::DBus::Variant &value,
-                             ::DBus::Error &error);
+                             ::DBus::Error *error);
+  static bool GetProperties(PropertyStore *store,
+                            std::map<std::string, ::DBus::Variant> *out,
+                            ::DBus::Error *error);
 
   static ::DBus::Variant BoolToVariant(bool value);
   static ::DBus::Variant ByteToVariant(uint8 value);
diff --git a/dbus_adaptor_unittest.cc b/dbus_adaptor_unittest.cc
index 0454a51..4aeba6b 100644
--- a/dbus_adaptor_unittest.cc
+++ b/dbus_adaptor_unittest.cc
@@ -156,17 +156,16 @@
   EXPECT_CALL(store, SetStringProperty("", StrEq(string_path), _))
       .WillOnce(Return(true));
 
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", bool_v_, e1));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", path_v, e2));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", string_v_, e3));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", strings_v_, e4));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", int16_v_, e5));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", int32_v_, e6));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", uint16_v_, e7));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", uint32_v_, e8));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", stringmap_v_, e9));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", byte_v_, e10));
-
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", bool_v_, &e1));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", path_v, &e2));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", string_v_, &e3));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", strings_v_, &e4));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", int16_v_, &e5));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", int32_v_, &e6));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", uint16_v_, &e7));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", uint32_v_, &e8));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", stringmap_v_, &e9));
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", byte_v_, &e10));
 }
 
 }  // namespace shill
diff --git a/device_dbus_adaptor.cc b/device_dbus_adaptor.cc
index 9beec49..8ed8b86 100644
--- a/device_dbus_adaptor.cc
+++ b/device_dbus_adaptor.cc
@@ -51,13 +51,15 @@
 
 map<string, ::DBus::Variant> DeviceDBusAdaptor::GetProperties(
     ::DBus::Error &error) {
-  return map<string, ::DBus::Variant>();
+  map<string, ::DBus::Variant> properties;
+  DBusAdaptor::GetProperties(device_, &properties, &error);
+  return properties;
 }
 
 void DeviceDBusAdaptor::SetProperty(const string& name,
                                     const ::DBus::Variant& value,
                                     ::DBus::Error &error) {
-  DBusAdaptor::DispatchOnType(device_, name, value, error);
+  DBusAdaptor::DispatchOnType(device_, name, value, &error);
 }
 
 void DeviceDBusAdaptor::ClearProperty(const std::string& ,
diff --git a/device_unittest.cc b/device_unittest.cc
index 5910fd0..24a28eb 100644
--- a/device_unittest.cc
+++ b/device_unittest.cc
@@ -56,25 +56,46 @@
   EXPECT_FALSE(device_->Contains(""));
 }
 
+TEST_F(DeviceTest, GetProperties) {
+  map<string, ::DBus::Variant> props;
+  Error error(Error::kInvalidProperty, "");
+  {
+    ::DBus::Error dbus_error;
+    bool expected = true;
+    device_->SetBoolProperty(flimflam::kPoweredProperty, expected, &error);
+    DBusAdaptor::GetProperties(device_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kPoweredProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kPoweredProperty].reader().get_bool(),
+              expected);
+  }
+  {
+    ::DBus::Error dbus_error;
+    DBusAdaptor::GetProperties(device_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kNameProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kNameProperty].reader().get_string(),
+              string(kDeviceName));
+  }
+}
+
 TEST_F(DeviceTest, Dispatch) {
   ::DBus::Error error;
   EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
                                           flimflam::kPoweredProperty,
                                           PropertyStoreTest::kBoolV,
-                                          error));
+                                          &error));
 
   // Ensure that an attempt to write a R/O property returns InvalidArgs error.
   EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
                                            flimflam::kAddressProperty,
                                            PropertyStoreTest::kStringV,
-                                           error));
+                                           &error));
   EXPECT_EQ(invalid_args_, error.name());
 }
 
 TEST_P(DeviceTest, TestProperty) {
   // Ensure that an attempt to write unknown properties returns InvalidProperty.
   ::DBus::Error error;
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), error));
+  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), &error));
   EXPECT_EQ(invalid_prop_, error.name());
 }
 
diff --git a/manager.cc b/manager.cc
index be39401..2667dc1 100644
--- a/manager.cc
+++ b/manager.cc
@@ -169,14 +169,11 @@
       StringAccessor(new CustomAccessor<Manager, string>(this, get, set));
 }
 
-void Manager::RegisterDerivedStrings(
-    const string &name,
-    std::vector<string>(Manager::*get)(void),
-    bool(Manager::*set)(const vector<string>&)) {
+void Manager::RegisterDerivedStrings(const string &name,
+                                     Strings(Manager::*get)(void),
+                                     bool(Manager::*set)(const Strings&)) {
   strings_properties_[name] =
-      StringsAccessor(new CustomAccessor<Manager, vector<string> >(this,
-                                                                   get,
-                                                                   set));
+      StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set));
 }
 
 string Manager::CalculateState() {
diff --git a/manager.h b/manager.h
index d18d300..a8d2083 100644
--- a/manager.h
+++ b/manager.h
@@ -56,10 +56,9 @@
   void RegisterDerivedString(const std::string &name,
                              std::string(Manager::*get)(void),
                              bool(Manager::*set)(const std::string&));
-  void RegisterDerivedStrings(
-      const std::string &name,
-      std::vector<std::string>(Manager::*get)(void),
-      bool(Manager::*set)(const std::vector<std::string>&));
+  void RegisterDerivedStrings(const std::string &name,
+                              Strings(Manager::*get)(void),
+                              bool(Manager::*set)(const Strings&));
 
  private:
   std::string CalculateState();
diff --git a/manager_dbus_adaptor.cc b/manager_dbus_adaptor.cc
index 91cd9f5..bd7500c 100644
--- a/manager_dbus_adaptor.cc
+++ b/manager_dbus_adaptor.cc
@@ -60,13 +60,15 @@
 
 map<string, ::DBus::Variant> ManagerDBusAdaptor::GetProperties(
     ::DBus::Error &error) {
-  return map<string, ::DBus::Variant>();
+  map<string, ::DBus::Variant> properties;
+  DBusAdaptor::GetProperties(manager_, &properties, &error);
+  return properties;
 }
 
 void ManagerDBusAdaptor::SetProperty(const string &name,
                                      const ::DBus::Variant &value,
                                      ::DBus::Error &error) {
-  if (DBusAdaptor::DispatchOnType(manager_, name, value, error)) {
+  if (DBusAdaptor::DispatchOnType(manager_, name, value, &error)) {
     PropertyChanged(name, value);
   }
 }
diff --git a/manager_unittest.cc b/manager_unittest.cc
index 424e520..406bc42 100644
--- a/manager_unittest.cc
+++ b/manager_unittest.cc
@@ -135,42 +135,79 @@
   EXPECT_TRUE(manager_.FindService(kService2).get() != NULL);
 }
 
+TEST_F(ManagerTest, GetProperties) {
+  map<string, ::DBus::Variant> props;
+  Error error(Error::kInvalidProperty, "");
+  {
+    ::DBus::Error dbus_error;
+    string expected("portal_list");
+    manager_.SetStringProperty(flimflam::kCheckPortalListProperty,
+                               expected,
+                               &error);
+    DBusAdaptor::GetProperties(&manager_, &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kCheckPortalListProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kCheckPortalListProperty].reader().get_string(),
+              expected);
+  }
+  {
+    ::DBus::Error dbus_error;
+    bool expected = true;
+    manager_.SetBoolProperty(flimflam::kOfflineModeProperty, expected, &error);
+    DBusAdaptor::GetProperties(&manager_, &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kOfflineModeProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kOfflineModeProperty].reader().get_bool(),
+              expected);
+  }
+}
+
 TEST_F(ManagerTest, Dispatch) {
-  ::DBus::Error e1, e2, e3, e4, e5;
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&manager_,
-                                          flimflam::kOfflineModeProperty,
-                                          PropertyStoreTest::kBoolV,
-                                          e1));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(&manager_,
-                                          flimflam::kCountryProperty,
-                                          PropertyStoreTest::kStringV,
-                                          e2));
-
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(&manager_,
+                                            flimflam::kOfflineModeProperty,
+                                            PropertyStoreTest::kBoolV,
+                                            &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(&manager_,
+                                            flimflam::kCountryProperty,
+                                            PropertyStoreTest::kStringV,
+                                            &error));
+  }
   // Attempt to write with value of wrong type should return InvalidArgs.
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_,
-                                           flimflam::kCountryProperty,
-                                           PropertyStoreTest::kBoolV,
-                                           e3));
-  EXPECT_EQ(invalid_args_, e3.name());
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_,
-                                           flimflam::kOfflineModeProperty,
-                                           PropertyStoreTest::kStringV,
-                                           e4));
-  EXPECT_EQ(invalid_args_, e4.name());
-
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_,
+                                             flimflam::kCountryProperty,
+                                             PropertyStoreTest::kBoolV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_,
+                                             flimflam::kOfflineModeProperty,
+                                             PropertyStoreTest::kStringV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
   // Attempt to write R/O property should return InvalidArgs.
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(
-      &manager_,
-      flimflam::kEnabledTechnologiesProperty,
-      PropertyStoreTest::kStringsV,
-      e5));
-  EXPECT_EQ(invalid_args_, e5.name());
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(
+        &manager_,
+        flimflam::kEnabledTechnologiesProperty,
+        PropertyStoreTest::kStringsV,
+        &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
 }
 
 TEST_P(ManagerTest, TestProperty) {
   // Ensure that an attempt to write unknown properties returns InvalidProperty.
   ::DBus::Error error;
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), error));
+  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), &error));
   EXPECT_EQ(invalid_prop_, error.name());
 }
 
diff --git a/mock_property_store.h b/mock_property_store.h
index 8042292..0956545 100644
--- a/mock_property_store.h
+++ b/mock_property_store.h
@@ -28,12 +28,11 @@
   MOCK_METHOD3(SetStringProperty, bool(const std::string&,
                                        const std::string&,
                                        Error*));
-  MOCK_METHOD3(SetStringmapProperty,
-               bool(const std::string&,
-                    const std::map<std::string, std::string>&,
-                    Error*));
+  MOCK_METHOD3(SetStringmapProperty, bool(const std::string&,
+                                          const Stringmap&,
+                                          Error*));
   MOCK_METHOD3(SetStringsProperty, bool(const std::string&,
-                                        const std::vector<std::string>&,
+                                        const Strings&,
                                         Error*));
   MOCK_METHOD3(SetUint8Property, bool(const std::string&, uint8, Error*));
   MOCK_METHOD3(SetUint16Property, bool(const std::string&, uint16, Error*));
diff --git a/property_iterator.h b/property_iterator.h
new file mode 100644
index 0000000..9c52d5a
--- /dev/null
+++ b/property_iterator.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_PROPERTY_ITERATOR_
+#define SHILL_PROPERTY_ITERATOR_
+
+#include <map>
+#include <string>
+
+#include "shill/accessor_interface.h"
+
+namespace shill {
+
+// An iterator wrapper class to hide the details of what kind of data structure
+// we're using to store key/value pairs for properties.
+// Intended for use with PropertyStore.
+template <class V>
+class PropertyConstIterator {
+ public:
+  virtual ~PropertyConstIterator() {}
+
+  void Advance() { ++it_; }
+
+  bool AtEnd() { return it_ == collection_.end(); }
+
+  const std::string &Key() const { return it_->first; }
+
+  const V &Value() { return it_->second->Get(); }
+
+ private:
+  friend class PropertyStore;
+
+  typedef std::tr1::shared_ptr<AccessorInterface<V> > VAccessorPtr;
+
+  explicit PropertyConstIterator(
+      const typename std::map<std::string, VAccessorPtr> &collection)
+      : collection_(collection),
+        it_(collection_.begin()) {
+  }
+
+  const typename std::map<std::string, VAccessorPtr> &collection_;
+  typename std::map<std::string, VAccessorPtr>::const_iterator it_;
+};
+
+
+
+}  // namespace shill
+
+#endif  // SHILL_PROPERTY_ITERATOR_
diff --git a/property_store.cc b/property_store.cc
index 8f66ed2..c2ceac4 100644
--- a/property_store.cc
+++ b/property_store.cc
@@ -91,6 +91,42 @@
   return ReturnError(name, error);
 }
 
+PropertyConstIterator<bool> PropertyStore::GetBoolPropertiesIter() {
+  return PropertyConstIterator<bool>(bool_properties_);
+}
+
+PropertyConstIterator<int16> PropertyStore::GetInt16PropertiesIter() {
+  return PropertyConstIterator<int16>(int16_properties_);
+}
+
+PropertyConstIterator<int32> PropertyStore::GetInt32PropertiesIter() {
+  return PropertyConstIterator<int32>(int32_properties_);
+}
+
+PropertyConstIterator<std::string> PropertyStore::GetStringPropertiesIter() {
+  return PropertyConstIterator<std::string>(string_properties_);
+}
+
+PropertyConstIterator<Stringmap> PropertyStore::GetStringmapPropertiesIter() {
+  return PropertyConstIterator<Stringmap>(stringmap_properties_);
+}
+
+PropertyConstIterator<Strings> PropertyStore::GetStringsPropertiesIter() {
+  return PropertyConstIterator<Strings>(strings_properties_);
+}
+
+PropertyConstIterator<uint8> PropertyStore::GetUint8PropertiesIter() {
+  return PropertyConstIterator<uint8>(uint8_properties_);
+}
+
+PropertyConstIterator<uint16> PropertyStore::GetUint16PropertiesIter() {
+  return PropertyConstIterator<uint16>(uint16_properties_);
+}
+
+PropertyConstIterator<uint32> PropertyStore::GetUint32PropertiesIter() {
+  return PropertyConstIterator<uint32>(uint32_properties_);
+}
+
 void PropertyStore::RegisterBool(const string &name, bool *prop) {
   bool_properties_[name] = BoolAccessor(new PropertyAccessor<bool>(prop));
 }
diff --git a/property_store.h b/property_store.h
index 3ba6530..42f3cd4 100644
--- a/property_store.h
+++ b/property_store.h
@@ -12,6 +12,7 @@
 #include <base/basictypes.h>
 
 #include "shill/accessor_interface.h"
+#include "shill/property_iterator.h"
 
 namespace shill {
 
@@ -66,6 +67,17 @@
                                  uint32 value,
                                  Error *error);
 
+  // Accessors for iterators over property maps.
+  PropertyConstIterator<bool> GetBoolPropertiesIter();
+  PropertyConstIterator<int16> GetInt16PropertiesIter();
+  PropertyConstIterator<int32> GetInt32PropertiesIter();
+  PropertyConstIterator<std::string> GetStringPropertiesIter();
+  PropertyConstIterator<Stringmap> GetStringmapPropertiesIter();
+  PropertyConstIterator<Strings> GetStringsPropertiesIter();
+  PropertyConstIterator<uint8> GetUint8PropertiesIter();
+  PropertyConstIterator<uint16> GetUint16PropertiesIter();
+  PropertyConstIterator<uint32> GetUint32PropertiesIter();
+
  protected:
   PropertyStore();
 
diff --git a/property_store_unittest.cc b/property_store_unittest.cc
index aa22e0d..03b6ee1 100644
--- a/property_store_unittest.cc
+++ b/property_store_unittest.cc
@@ -40,13 +40,13 @@
     DBusAdaptor::StringToVariant("");
 // static
 const ::DBus::Variant PropertyStoreTest::kStringmapV =
-    DBusAdaptor::StringmapToVariant(map<string, string>());
+    DBusAdaptor::StringmapToVariant(Stringmap());
 // static
 const ::DBus::Variant PropertyStoreTest::kStringmapsV =
     DBusAdaptor::StringmapsToVariant(vector<map<string, string> >());
 // static
 const ::DBus::Variant PropertyStoreTest::kStringsV =
-    DBusAdaptor::StringsToVariant(vector<string>(1, ""));
+    DBusAdaptor::StringsToVariant(Strings(1, ""));
 // static
 const ::DBus::Variant PropertyStoreTest::kUint16V =
     DBusAdaptor::Uint16ToVariant(0);
diff --git a/service_dbus_adaptor.cc b/service_dbus_adaptor.cc
index 7d96812..10c132d 100644
--- a/service_dbus_adaptor.cc
+++ b/service_dbus_adaptor.cc
@@ -53,13 +53,15 @@
 
 map<string, ::DBus::Variant> ServiceDBusAdaptor::GetProperties(
     ::DBus::Error &error) {
-  return map<string, ::DBus::Variant>();
+  map<string, ::DBus::Variant> properties;
+  DBusAdaptor::GetProperties(service_, &properties, &error);
+  return properties;
 }
 
 void ServiceDBusAdaptor::SetProperty(const string& name,
                                      const ::DBus::Variant& value,
                                      ::DBus::Error &error) {
-  DBusAdaptor::DispatchOnType(service_, name, value, error);
+  DBusAdaptor::DispatchOnType(service_, name, value, &error);
 }
 
 void ServiceDBusAdaptor::ClearProperty(const string& , ::DBus::Error &error) {
diff --git a/service_unittest.cc b/service_unittest.cc
index fedf834..5a8014c 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -46,27 +46,77 @@
   ServiceRefPtr service_;
 };
 
-TEST_F(ServiceTest, Dispatch) {
-  ::DBus::Error e1, e2, e3, e4;
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
-                                          flimflam::kSaveCredentialsProperty,
-                                          PropertyStoreTest::kBoolV,
-                                          e1));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
-                                          flimflam::kPriorityProperty,
-                                          PropertyStoreTest::kInt32V,
-                                          e2));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
-                                          flimflam::kEAPEAPProperty,
-                                          PropertyStoreTest::kStringV,
-                                          e3));
+TEST_F(ServiceTest, GetProperties) {
+  map<string, ::DBus::Variant> props;
+  Error error(Error::kInvalidProperty, "");
+  {
+    ::DBus::Error dbus_error;
+    string expected("portal_list");
+    service_->SetStringProperty(flimflam::kCheckPortalProperty,
+                                expected,
+                                &error);
+    DBusAdaptor::GetProperties(service_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kCheckPortalProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kCheckPortalProperty].reader().get_string(),
+              expected);
+  }
+  {
+    ::DBus::Error dbus_error;
+    bool expected = true;
+    service_->SetBoolProperty(flimflam::kAutoConnectProperty, expected, &error);
+    DBusAdaptor::GetProperties(service_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kAutoConnectProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kAutoConnectProperty].reader().get_bool(),
+              expected);
+  }
+  {
+    ::DBus::Error dbus_error;
+    DBusAdaptor::GetProperties(service_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kConnectableProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kConnectableProperty].reader().get_bool(), false);
+  }
+  {
+    ::DBus::Error dbus_error;
+    int32 expected = 127;
+    service_->SetInt32Property(flimflam::kPriorityProperty, expected, &error);
+    DBusAdaptor::GetProperties(service_.get(), &props, &dbus_error);
+    ASSERT_FALSE(props.find(flimflam::kPriorityProperty) == props.end());
+    EXPECT_EQ(props[flimflam::kPriorityProperty].reader().get_int32(),
+              expected);
+  }
+}
 
+TEST_F(ServiceTest, Dispatch) {
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
+                                            flimflam::kSaveCredentialsProperty,
+                                            PropertyStoreTest::kBoolV,
+                                            &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
+                                            flimflam::kPriorityProperty,
+                                            PropertyStoreTest::kInt32V,
+                                            &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(service_.get(),
+                                            flimflam::kEAPEAPProperty,
+                                            PropertyStoreTest::kStringV,
+                                            &error));
+  }
   // Ensure that an attempt to write a R/O property returns InvalidArgs error.
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(service_.get(),
-                                           flimflam::kFavoriteProperty,
-                                           PropertyStoreTest::kBoolV,
-                                           e4));
-  EXPECT_EQ(invalid_args_, e4.name());
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(service_.get(),
+                                             flimflam::kFavoriteProperty,
+                                             PropertyStoreTest::kBoolV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
 }
 
 TEST_P(ServiceTest, TestProperty) {
@@ -75,7 +125,7 @@
   EXPECT_FALSE(DBusAdaptor::DispatchOnType(service_.get(),
                                            "",
                                            GetParam(),
-                                           error));
+                                           &error));
   EXPECT_EQ(invalid_prop_, error.name());
 }
 
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index a1ec8d3..1e24d7b 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -47,33 +47,43 @@
 }
 
 TEST_F(WiFiTest, Dispatch) {
-  ::DBus::Error e1, e2, e3, e4;
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
-                                          flimflam::kBgscanMethodProperty,
-                                          PropertyStoreTest::kStringV,
-                                          e1));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(
-      device_.get(),
-      flimflam::kBgscanSignalThresholdProperty,
-      PropertyStoreTest::kInt32V,
-      e2));
-  EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
-                                          flimflam::kScanIntervalProperty,
-                                          PropertyStoreTest::kUint16V,
-                                          e3));
-
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
+                                            flimflam::kBgscanMethodProperty,
+                                            PropertyStoreTest::kStringV,
+                                            &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(
+        device_.get(),
+        flimflam::kBgscanSignalThresholdProperty,
+        PropertyStoreTest::kInt32V,
+        &error));
+  }
+  {
+    ::DBus::Error error;
+    EXPECT_TRUE(DBusAdaptor::DispatchOnType(device_.get(),
+                                            flimflam::kScanIntervalProperty,
+                                            PropertyStoreTest::kUint16V,
+                                            &error));
+  }
   // Ensure that an attempt to write a R/O property returns InvalidArgs error.
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
-                                           flimflam::kScanningProperty,
-                                           PropertyStoreTest::kBoolV,
-                                           e4));
-  EXPECT_EQ(invalid_args_, e4.name());
+  {
+    ::DBus::Error error;
+    EXPECT_FALSE(DBusAdaptor::DispatchOnType(device_.get(),
+                                             flimflam::kScanningProperty,
+                                             PropertyStoreTest::kBoolV,
+                                             &error));
+    EXPECT_EQ(invalid_args_, error.name());
+  }
 }
 
 TEST_P(WiFiTest, TestProperty) {
   // Ensure that an attempt to write unknown properties returns InvalidProperty.
   ::DBus::Error error;
-  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), error));
+  EXPECT_FALSE(DBusAdaptor::DispatchOnType(&manager_, "", GetParam(), &error));
   EXPECT_EQ(invalid_prop_, error.name());
 }