class ServiceInstancesChangedListener implements ConditionalEventListener<ServiceInstancesChangedEvent> {

    public synchronized void onEvent(ServiceInstancesChangedEvent event) {
        logger.info("Received instance notification, serviceName: " + event.getServiceName() + ", instances: " + event.getServiceInstances().size());
        String appName = event.getServiceName();
        allInstances.put(appName, event.getServiceInstances());

        Map<String, List<ServiceInstance>> revisionToInstances = new HashMap<>();
        Map<String, Set<String>> localServiceToRevisions = new HashMap<>();
        Map<Set<String>, List<URL>> revisionsToUrls = new HashMap();
        for (Map.Entry<String, List<ServiceInstance>> entry : allInstances.entrySet()) {
            List<ServiceInstance> instances = entry.getValue();
            for (ServiceInstance instance : instances) {
                String revision = getExportedServicesRevision(instance);
                if (DEFAULT_REVISION.equals(revision)) {
                    logger.info("Find instance without valid service metadata: " + instance.getAddress());
                    continue;
                }
                List<ServiceInstance> subInstances = revisionToInstances.computeIfAbsent(revision, r -> new LinkedList<>());
                subInstances.add(instance);

                MetadataInfo metadata = revisionToMetadata.get(revision);
                if (metadata == null) {
                    metadata = getMetadataInfo(instance);
                    logger.info("MetadataInfo for instance " + instance.getAddress() + "?revision=" + revision + " is " + metadata);
                    if (metadata != null) {
                        revisionToMetadata.put(revision, getMetadataInfo(instance));
                    } else {

                    }
                }

                if (metadata != null) {
                    parseMetadata(revision, metadata, localServiceToRevisions);
                    ((DefaultServiceInstance) instance).setServiceMetadata(metadata);
                }
//                else {
//                    logger.error("Failed to load service metadata for instance " + instance);
//                    Set<String> set = localServiceToRevisions.computeIfAbsent(url.getServiceKey(), k -> new TreeSet<>());
//                    set.add(revision);
//                }

                localServiceToRevisions.forEach((serviceKey, revisions) -> {
                    List<URL> urls = revisionsToUrls.get(revisions);
                    if (urls != null) {
                        serviceUrls.put(serviceKey, urls);
                    } else {
                        urls = new ArrayList<>();
                        for (String r : revisions) {
                            for (ServiceInstance i : revisionToInstances.get(r)) {
                                urls.add(i.toURL());
                            }
                        }
                        revisionsToUrls.put(revisions, urls);
                        serviceUrls.put(serviceKey, urls);
                    }
                });
            }
        }

        this.notifyAddressChanged();
    }

    public  ServiceInstancesChangedListener(Set<String> serviceNames, ServiceDiscovery serviceDiscovery);

}