class HazelcastClusterTopology {

    static Map<MemberId,ReadReplicaInfo> readReplicas( HazelcastInstance hazelcastInstance, Log log )
    {
        Pair<Set<String>,Map<String,IMap<String,String>>> validatedSimpleAttrMaps = validatedSimpleAttrMaps( hazelcastInstance );
        Set<String> missingAttrKeys = validatedSimpleAttrMaps.first();
        Map<String,IMap<String,String>> simpleAttrMaps = validatedSimpleAttrMaps.other();

        MultiMap<String,String> serverGroupsMap = hazelcastInstance.getMultiMap( SERVER_GROUPS_MULTIMAP );

        if ( serverGroupsMap == null )
        {
            missingAttrKeys.add( SERVER_GROUPS_MULTIMAP );
        }

        if ( !missingAttrKeys.isEmpty() )
        {
            // We might well not have any read replicas, in which case missing maps is not an error, but we *can't* have some maps and not others
            boolean missingAllKeys = missingAttrKeys.containsAll( RR_ATTR_KEYS ) && missingAttrKeys.contains( SERVER_GROUPS_MULTIMAP );
            if ( !missingAllKeys )
            {
                String missingAttrs = String.join( ", ", missingAttrKeys );
                log.warn( "Some, but not all, of the read replica attribute maps are null, including %s", missingAttrs );
            }

            return emptyMap();
        }

        Stream<String> readReplicaHzIds = simpleAttrMaps.get( READ_REPLICA_BOLT_ADDRESS_MAP ).keySet().stream();

        Map<MemberId,ReadReplicaInfo> validatedReadReplicas = readReplicaHzIds
                .flatMap( hzId -> Streams.ofNullable( buildReadReplicaFromAttrMap( hzId, simpleAttrMaps, serverGroupsMap, log ) ) )
                .collect( Collectors.toMap( Pair::first, Pair::other ) );

        return validatedReadReplicas;
    }

    private  HazelcastClusterTopology();

}