class EnforcerRetriever {

    public CompletionStage<Contextual<WithDittoHeaders>> retrieve(final EntityIdWithResourceType entityKey,
            final BiFunction<Entry<EntityIdWithResourceType>, Entry<Enforcer>, CompletionStage<Contextual<WithDittoHeaders>>> handler) {
        return idCache.get(entityKey).thenCompose(enforcerKeyEntryOptional -> {
            if (enforcerKeyEntryOptional.isEmpty()) {
                // may happen due to namespace blocking
                LOGGER.info("Did not get id-cache value for entityKey <{}>.", entityKey);
                return handler.apply(Entry.nonexistent(), Entry.nonexistent());
            } else {
                final Entry<EntityIdWithResourceType> enforcerKeyEntry = enforcerKeyEntryOptional.get();
                if (enforcerKeyEntry.exists()) {
                    final EntityIdWithResourceType enforcerKey = enforcerKeyEntry.getValueOrThrow();
                    final String resourceType = enforcerKey.getResourceType();
                    final Cache<EntityIdWithResourceType, Entry<Enforcer>> enforcerCache =
                            enforcerCacheFunction.apply(resourceType);
                    if (enforcerCache == null) {
                        LOGGER.error("No enforcerCache for resource type: <{}>", resourceType);
                        throw GatewayInternalErrorException.newBuilder()
                                .build();
                    }
                    return retrieveByEnforcerKey(enforcerKey, enforcerEntry ->
                            handler.apply(enforcerKeyEntry, enforcerEntry));
                } else {
                    return handler.apply(enforcerKeyEntry, Entry.nonexistent());
                }
            }
        });
    }

    public  EnforcerRetriever(
            final Cache<EntityIdWithResourceType, Entry<EntityIdWithResourceType>> idCache,
            final Cache<EntityIdWithResourceType, Entry<Enforcer>> enforcerCache);
    private  EnforcerRetriever(
            final Cache<EntityIdWithResourceType, Entry<EntityIdWithResourceType>> idCache,
            final Function<String, Cache<EntityIdWithResourceType, Entry<Enforcer>>> enforcerCacheFunction);
    public  EnforcerRetriever(
            final Cache<EntityIdWithResourceType, Entry<EntityIdWithResourceType>> idCache,
            final Map<String, Cache<EntityIdWithResourceType, Entry<Enforcer>>> enforcerCaches);

}