Deduplicate repeated code in DeviceTypeResolver (#36436)

* Dedup code in devicetyperesolver

* Restyle

* Add missing file

* Restyled by clang-format

* Restyled by gn

---------

Co-authored-by: Andrei Litvin <andreilitvin@google.com>
Co-authored-by: Restyled.io <commits@restyled.io>
diff --git a/src/access/BUILD.gn b/src/access/BUILD.gn
index 3f3aaaf..6637009 100644
--- a/src/access/BUILD.gn
+++ b/src/access/BUILD.gn
@@ -78,3 +78,12 @@
     ]
   }
 }
+
+source_set("provider-impl") {
+  sources = [ "ProviderDeviceTypeResolver.h" ]
+
+  public_deps = [
+    ":access",
+    "${chip_root}/src/app/data-model-provider",
+  ]
+}
diff --git a/src/access/ProviderDeviceTypeResolver.h b/src/access/ProviderDeviceTypeResolver.h
new file mode 100644
index 0000000..0a215d4
--- /dev/null
+++ b/src/access/ProviderDeviceTypeResolver.h
@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    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.
+ */
+#pragma once
+
+#include <access/AccessControl.h>
+#include <app/data-model-provider/Provider.h>
+
+namespace chip {
+namespace Access {
+
+/// A device type resolver where the DataModel::Provider is fetched dynamically (may change over time)
+class DynamicProviderDeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
+{
+public:
+    using ModelGetter = app::DataModel::Provider * (*) ();
+
+    DynamicProviderDeviceTypeResolver(ModelGetter model) : mModelGetter(model) {}
+
+    bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
+    {
+        app::DataModel::Provider * model = mModelGetter();
+        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
+        {
+            if (type->deviceTypeId == deviceType)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+private:
+    ModelGetter mModelGetter;
+};
+
+} // namespace Access
+} // namespace chip
diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn
index 2817939..b0cde09 100644
--- a/src/app/BUILD.gn
+++ b/src/app/BUILD.gn
@@ -264,6 +264,7 @@
     public_deps += [
       ":global-attributes",
       "${chip_root}/src/access",
+      "${chip_root}/src/access:provider-impl",
       "${chip_root}/src/app/common:attribute-type",
     ]
 
diff --git a/src/app/dynamic_server/AccessControl.cpp b/src/app/dynamic_server/AccessControl.cpp
index 9f39040..75385f4 100644
--- a/src/app/dynamic_server/AccessControl.cpp
+++ b/src/app/dynamic_server/AccessControl.cpp
@@ -18,6 +18,7 @@
 
 #include <access/AccessControl.h>
 #include <access/Privilege.h>
+#include <access/ProviderDeviceTypeResolver.h>
 #include <access/RequestPath.h>
 #include <access/SubjectDescriptor.h>
 #include <app-common/zap-generated/ids/Clusters.h>
@@ -34,22 +35,13 @@
 // DynamicDispatch.cpp.
 constexpr EndpointId kSupportedEndpoint = 0;
 
-class DeviceTypeResolver : public Access::AccessControl::DeviceTypeResolver
+class DeviceTypeResolver : public chip::Access::DynamicProviderDeviceTypeResolver
 {
 public:
-    bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) override
-    {
-        chip::app::DataModel::Provider * model = chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
-
-        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
-        {
-            if (type->deviceTypeId == deviceType)
-            {
-                return true;
-            }
-        }
-        return false;
-    }
+    DeviceTypeResolver() :
+        chip::Access::DynamicProviderDeviceTypeResolver(
+            [] { return chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider(); })
+    {}
 };
 
 // TODO: Make the policy more configurable by consumers.
diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn
index 4addf8e..42c4caf 100644
--- a/src/app/server/BUILD.gn
+++ b/src/app/server/BUILD.gn
@@ -52,6 +52,8 @@
   cflags = [ "-Wconversion" ]
 
   public_deps = [
+    "${chip_root}/src/access",
+    "${chip_root}/src/access:provider-impl",
     "${chip_root}/src/app",
     "${chip_root}/src/app:test-event-trigger",
     "${chip_root}/src/app/icd/server:icd-server-config",
diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp
index cfb8d21..6808431 100644
--- a/src/app/server/Server.cpp
+++ b/src/app/server/Server.cpp
@@ -17,6 +17,7 @@
 
 #include <app/server/Server.h>
 
+#include <access/ProviderDeviceTypeResolver.h>
 #include <access/examples/ExampleAccessControlDelegate.h>
 
 #include <app/AppConfig.h>
@@ -82,23 +83,9 @@
 
 namespace {
 
-class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
-{
-public:
-    bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
-    {
-        chip::app::DataModel::Provider * model = chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
-
-        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
-        {
-            if (type->deviceTypeId == deviceType)
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-} sDeviceTypeResolver;
+chip::Access::DynamicProviderDeviceTypeResolver sDeviceTypeResolver([] {
+    return chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
+});
 
 } // namespace
 
diff --git a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
index 35f602e..67d546b 100644
--- a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
+++ b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
@@ -26,6 +26,7 @@
 
 #include <access/AccessControl.h>
 #include <access/Privilege.h>
+#include <access/ProviderDeviceTypeResolver.h>
 #include <access/RequestPath.h>
 #include <access/SubjectDescriptor.h>
 #include <app/InteractionModelEngine.h>
@@ -42,18 +43,12 @@
 
 namespace {
 
-class DeviceTypeResolver : public Access::AccessControl::DeviceTypeResolver {
+class DeviceTypeResolver : public chip::Access::DynamicProviderDeviceTypeResolver {
 public:
-    bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) override
+    DeviceTypeResolver()
+        : chip::Access::DynamicProviderDeviceTypeResolver(
+            [] { return chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider(); })
     {
-        app::DataModel::Provider * model = app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
-
-        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type)) {
-            if (type->deviceTypeId == deviceType) {
-                return true;
-            }
-        }
-        return false;
     }
 };