Motown: Factor FactoryServiceBase out of MediaFactoryService
Extracts FactoryServiceBase from MediaFactoryService so it can be used
for other services (the new logging service will use it).
FactoryServiceBase defines the relationship between a factory service
and its 'products' and provides a means for controlling the lifetime of
products.

R=kulakowski@chromium.org

Review URL: https://codereview.chromium.org/2007593004 .
diff --git a/services/media/factory_service/BUILD.gn b/services/media/factory_service/BUILD.gn
index c93cee3..21a1e4b 100644
--- a/services/media/factory_service/BUILD.gn
+++ b/services/media/factory_service/BUILD.gn
@@ -49,6 +49,7 @@
     "//services/media/framework_create",
     "//services/media/framework_ffmpeg",
     "//services/media/framework_mojo",
+    "//services/util/cpp",
     "//url",
   ]
 }
diff --git a/services/media/factory_service/factory_service.cc b/services/media/factory_service/factory_service.cc
index 6fe73f1..94b4c9b 100644
--- a/services/media/factory_service/factory_service.cc
+++ b/services/media/factory_service/factory_service.cc
@@ -13,21 +13,10 @@
 namespace mojo {
 namespace media {
 
-MediaFactoryService::ProductBase::ProductBase(MediaFactoryService* owner)
-    : owner_(owner) {
-  DCHECK(owner_);
-}
-
-MediaFactoryService::ProductBase::~ProductBase() {}
-
 MediaFactoryService::MediaFactoryService() {}
 
 MediaFactoryService::~MediaFactoryService() {}
 
-void MediaFactoryService::Initialize(ApplicationImpl* app) {
-  app_ = app;
-}
-
 bool MediaFactoryService::ConfigureIncomingConnection(
     ServiceProviderImpl* service_provider_impl) {
   service_provider_impl->AddService<MediaFactory>(
@@ -40,43 +29,39 @@
 
 void MediaFactoryService::CreatePlayer(InterfaceHandle<SeekingReader> reader,
                                        InterfaceRequest<MediaPlayer> player) {
-  products_.insert(std::static_pointer_cast<ProductBase>(
-      MediaPlayerImpl::Create(reader.Pass(), player.Pass(), this)));
+  AddProduct(MediaPlayerImpl::Create(reader.Pass(), player.Pass(), this));
 }
 
 void MediaFactoryService::CreateSource(InterfaceHandle<SeekingReader> reader,
                                        Array<MediaTypeSetPtr> media_types,
                                        InterfaceRequest<MediaSource> source) {
-  products_.insert(
-      std::static_pointer_cast<ProductBase>(MediaSourceImpl::Create(
-          reader.Pass(), media_types, source.Pass(), this)));
+  AddProduct(
+      MediaSourceImpl::Create(reader.Pass(), media_types, source.Pass(), this));
 }
 
 void MediaFactoryService::CreateSink(const String& destination_url,
                                      MediaTypePtr media_type,
                                      InterfaceRequest<MediaSink> sink) {
-  products_.insert(std::static_pointer_cast<ProductBase>(MediaSinkImpl::Create(
-      destination_url, media_type.Pass(), sink.Pass(), this)));
+  AddProduct(MediaSinkImpl::Create(destination_url, media_type.Pass(),
+                                   sink.Pass(), this));
 }
 
 void MediaFactoryService::CreateDemux(InterfaceHandle<SeekingReader> reader,
                                       InterfaceRequest<MediaDemux> demux) {
-  products_.insert(std::static_pointer_cast<ProductBase>(
-      MediaDemuxImpl::Create(reader.Pass(), demux.Pass(), this)));
+  AddProduct(MediaDemuxImpl::Create(reader.Pass(), demux.Pass(), this));
 }
 
 void MediaFactoryService::CreateDecoder(
     MediaTypePtr input_media_type,
     InterfaceRequest<MediaTypeConverter> decoder) {
-  products_.insert(std::static_pointer_cast<ProductBase>(
-      MediaDecoderImpl::Create(input_media_type.Pass(), decoder.Pass(), this)));
+  AddProduct(
+      MediaDecoderImpl::Create(input_media_type.Pass(), decoder.Pass(), this));
 }
 
 void MediaFactoryService::CreateNetworkReader(
     const String& url,
     InterfaceRequest<SeekingReader> reader) {
-  products_.insert(std::static_pointer_cast<ProductBase>(
-      NetworkReaderImpl::Create(url, reader.Pass(), this)));
+  AddProduct(NetworkReaderImpl::Create(url, reader.Pass(), this));
 }
 
 }  // namespace media
diff --git a/services/media/factory_service/factory_service.h b/services/media/factory_service/factory_service.h
index f2a7fd5..8b4f520 100644
--- a/services/media/factory_service/factory_service.h
+++ b/services/media/factory_service/factory_service.h
@@ -5,77 +5,23 @@
 #ifndef MOJO_SERVICES_MEDIA_FACTORY_FACTORY_SERVICE_H_
 #define MOJO_SERVICES_MEDIA_FACTORY_FACTORY_SERVICE_H_
 
-#include <unordered_set>
-
 #include "mojo/common/binding_set.h"
 #include "mojo/public/cpp/application/application_delegate.h"
 #include "mojo/public/cpp/application/application_impl.h"
 #include "mojo/services/media/control/interfaces/media_factory.mojom.h"
+#include "services/util/cpp/factory_service_base.h"
 
 namespace mojo {
 namespace media {
 
-class MediaFactoryService : public ApplicationDelegate,
+class MediaFactoryService : public util::FactoryServiceBase,
                             public MediaFactory {
  public:
-  // Provides common behavior for all objects created by the factory service.
-  class ProductBase : public std::enable_shared_from_this<ProductBase> {
-   public:
-    virtual ~ProductBase();
-
-   protected:
-    ProductBase(MediaFactoryService* owner);
-
-    // Returns the ApplicationImpl.
-    ApplicationImpl* app() {
-      DCHECK(owner_->app_);
-      return owner_->app_;
-    }
-
-    // Tells the factory service to release this product.
-    void ReleaseFromOwner() {
-      size_t erased = owner_->products_.erase(shared_from_this());
-      DCHECK(erased);
-    }
-
-   private:
-    MediaFactoryService* owner_;
-  };
-
-  template <typename Interface>
-  class Product : public ProductBase {
-   public:
-    virtual ~Product() {}
-
-   protected:
-    Product(Interface* impl,
-            InterfaceRequest<Interface> request,
-            MediaFactoryService* owner)
-        : ProductBase(owner), binding_(impl, request.Pass()) {
-      DCHECK(impl);
-      binding_.set_connection_error_handler([this]() { ReleaseFromOwner(); });
-    }
-
-    // Closes the binding and calls ReleaseFromOwner.
-    void UnbindAndReleaseFromOwner() {
-      if (binding_.is_bound()) {
-        binding_.Close();
-      }
-
-      ReleaseFromOwner();
-    }
-
-   private:
-    Binding<Interface> binding_;
-  };
-
   MediaFactoryService();
 
   ~MediaFactoryService() override;
 
   // ApplicationDelegate implementation.
-  void Initialize(ApplicationImpl* app) override;
-
   bool ConfigureIncomingConnection(
       ServiceProviderImpl* service_provider_impl) override;
 
@@ -102,21 +48,8 @@
 
  private:
   BindingSet<MediaFactory> bindings_;
-  ApplicationImpl* app_;
-  std::unordered_set<std::shared_ptr<ProductBase>> products_;
 };
 
-// For use by products when handling mojo requests.
-// Checks the condition, and, if it's false, unbinds, releases from the owner
-// and calls return. Doesn't support stream arguments.
-// TODO(dalesat): Support stream arguments.
-#define RCHECK(condition)                                         \
-  if (!(condition)) {                                             \
-    LOG(ERROR) << "request precondition failed: " #condition "."; \
-    UnbindAndReleaseFromOwner();                                  \
-    return;                                                       \
-  }
-
 }  // namespace media
 }  // namespace mojo
 
diff --git a/services/util/cpp/BUILD.gn b/services/util/cpp/BUILD.gn
new file mode 100644
index 0000000..6a917c3
--- /dev/null
+++ b/services/util/cpp/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2016 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.
+
+import("//build/module_args/mojo.gni")
+import("//mojo/public/mojo_application.gni")
+import("$mojo_sdk_root/mojo/public/mojo_sdk.gni")
+
+source_set("cpp") {
+  sources = [
+    "factory_service_base.cc",
+    "factory_service_base.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/application",
+    "//mojo/common",
+    "//mojo/public/cpp/application",
+  ]
+}
diff --git a/services/util/cpp/factory_service_base.cc b/services/util/cpp/factory_service_base.cc
new file mode 100644
index 0000000..cc00c1b
--- /dev/null
+++ b/services/util/cpp/factory_service_base.cc
@@ -0,0 +1,27 @@
+// Copyright 2016 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 "base/logging.h"
+#include "services/util/cpp/factory_service_base.h"
+
+namespace mojo {
+namespace util {
+
+FactoryServiceBase::ProductBase::ProductBase(FactoryServiceBase* owner)
+    : owner_(owner) {
+  DCHECK(owner_);
+}
+
+FactoryServiceBase::ProductBase::~ProductBase() {}
+
+FactoryServiceBase::FactoryServiceBase() {}
+
+FactoryServiceBase::~FactoryServiceBase() {}
+
+void FactoryServiceBase::Initialize(ApplicationImpl* app) {
+  app_ = app;
+}
+
+}  // namespace util
+}  // namespace mojo
diff --git a/services/util/cpp/factory_service_base.h b/services/util/cpp/factory_service_base.h
new file mode 100644
index 0000000..9a5ec4a
--- /dev/null
+++ b/services/util/cpp/factory_service_base.h
@@ -0,0 +1,103 @@
+// Copyright 2016 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.
+
+#ifndef MOJO_SERVICES_UTIL_CPP_FACTORY_SERVICE_BASE_H_
+#define MOJO_SERVICES_UTIL_CPP_FACTORY_SERVICE_BASE_H_
+
+#include <memory>
+#include <unordered_set>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+
+namespace mojo {
+namespace util {
+
+class FactoryServiceBase : public ApplicationDelegate {
+ public:
+  // Provides common behavior for all objects created by the factory service.
+  class ProductBase : public std::enable_shared_from_this<ProductBase> {
+   public:
+    virtual ~ProductBase();
+
+   protected:
+    ProductBase(FactoryServiceBase* owner);
+
+    // Returns the ApplicationImpl.
+    ApplicationImpl* app() {
+      DCHECK(owner_->app_);
+      return owner_->app_;
+    }
+
+    // Tells the factory service to release this product.
+    void ReleaseFromOwner() {
+      size_t erased = owner_->products_.erase(shared_from_this());
+      DCHECK(erased);
+    }
+
+   private:
+    FactoryServiceBase* owner_;
+  };
+
+  template <typename Interface>
+  class Product : public ProductBase {
+   public:
+    virtual ~Product() {}
+
+   protected:
+    Product(Interface* impl,
+            InterfaceRequest<Interface> request,
+            FactoryServiceBase* owner)
+        : ProductBase(owner), binding_(impl, request.Pass()) {
+      DCHECK(impl);
+      binding_.set_connection_error_handler([this]() { ReleaseFromOwner(); });
+    }
+
+    // Closes the binding and calls ReleaseFromOwner.
+    void UnbindAndReleaseFromOwner() {
+      if (binding_.is_bound()) {
+        binding_.Close();
+      }
+
+      ReleaseFromOwner();
+    }
+
+   private:
+    Binding<Interface> binding_;
+  };
+
+  FactoryServiceBase();
+
+  ~FactoryServiceBase() override;
+
+  // ApplicationDelegate implementation.
+  void Initialize(ApplicationImpl* app) override;
+
+ protected:
+  template <typename ProductImpl>
+  void AddProduct(std::shared_ptr<ProductImpl> product) {
+    products_.insert(std::static_pointer_cast<ProductBase>(product));
+  }
+
+ private:
+  ApplicationImpl* app_;
+  std::unordered_set<std::shared_ptr<ProductBase>> products_;
+};
+
+// For use by products when handling mojo requests.
+// Checks the condition, and, if it's false, unbinds, releases from the owner
+// and calls return. Doesn't support stream arguments.
+// TODO(dalesat): Support stream arguments.
+#define RCHECK(condition)                                         \
+  if (!(condition)) {                                             \
+    LOG(ERROR) << "request precondition failed: " #condition "."; \
+    UnbindAndReleaseFromOwner();                                  \
+    return;                                                       \
+  }
+
+}  // namespace util
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_UTIL_CPP_FACTORY_SERVICE_BASE_H_