private static Map generateTopology()

in gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java [395:635]


    private static Map<String, File> generateTopology(final SimpleDescriptor desc,
                                                      final File srcDirectory,
                                                      final File destDirectory,
                                                      final ServiceDiscovery.Cluster cluster,
                                                      final List<String> declaredServiceNames,
                                                      final Set<String> validServiceNames,
                                                      final Map<String, String> serviceVersions,
                                                      final Map<String, List<String>> serviceURLs,
                                                      final Map<String, Map<String, String>> serviceParams,
                                                      final GatewayServices gwServices) {
        Map<String, File> result = new HashMap<>();
        File topologyDescriptor = null;
        try (StringWriter sw = new StringWriter()) {
            // Handle the referenced provider configuration
            File providerConfigFile = null;
            ProviderConfiguration providerConfiguration = null;
            String providerConfigReference = desc.getProviderConfig();
            if (providerConfigReference != null) {
                // Resolve and parse the referenced provider configuration
                providerConfigFile = resolveProviderConfigurationReference(providerConfigReference, srcDirectory);
                providerConfiguration = handleProviderConfiguration(desc, providerConfigFile);
            }
            if (providerConfiguration == null) {
                throw new IllegalArgumentException("Invalid provider configuration: " + providerConfigReference);
            }
            result.put(RESULT_REFERENCE, providerConfigFile);

            ProviderConfiguration.Provider haProvider = null;
            for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
                if ("ha".equals(provider.getRole())) {
                    haProvider = provider;
                    break;
                }
            }

            // Collect HA-related service parameters
            Map<String, ServiceDiscovery.Cluster.ZooKeeperConfig> haServiceParams = new HashMap<>();
            if (cluster != null) {
                if (haProvider != null) {
                    // Collect tne roles declared by the HaProvider
                    Map<String, String> haProviderParams = haProvider.getParams();
                    if (haProviderParams != null) {
                        Set<String> haProviderRoles = haProviderParams.keySet();
                        for (String haProviderRole : haProviderRoles) {
                            // For each role declared by the HaProvider, which supports ZooKeeper, try to get
                            // the ZK ensemble and namespace from the cluster.
                            ServiceDiscovery.Cluster.ZooKeeperConfig zkConfig =
                                cluster.getZooKeeperConfiguration(haProviderRole);
                            if (zkConfig != null) {
                                haServiceParams.put(haProviderRole, zkConfig);
                            }
                        }
                    }
                }
            }

            // Generate the topology content
            sw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
            sw.write("<!--==============================================-->\n");
            sw.write("<!-- DO NOT EDIT. This is an auto-generated file. -->\n");
            sw.write("<!--==============================================-->\n");

            sw.write("<topology>\n");

            // KNOX-1105 Indicate that this topology was auto-generated
            sw.write("    <generated>true</generated>\n");

            // Incorporate the externalized provider configuration content into the topology descriptor
            sw.write("    <gateway>\n");
            for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
                sw.write("        <provider>\n");
                sw.write("            <role>" + provider.getRole() + "</role>\n");
                sw.write("            <name>" + provider.getName() + "</name>\n");
                sw.write("            <enabled>" + provider.isEnabled() + "</enabled>\n");

                for (Map.Entry<String, String> param : provider.getParams().entrySet()) {
                    sw.write("            <param>\n");
                    sw.write("                <name>" + param.getKey() + "</name>\n");
                    sw.write("                <value>" + getXmlEscapedValue(param.getValue()) + "</value>\n");
                    sw.write("            </param>\n");
                }

                sw.write("        </provider>\n");
            }
            sw.write("    </gateway>\n");

            // Services
            // Sort the service names to write the services alphabetically
            Set<String> serviceNames = new TreeSet<>(validServiceNames);

            // Add any declared services, which were not validated, but which have ZK-based HA provider config
            for (String haServiceName : haServiceParams.keySet()) {
                // If the service configured for HA was declared in the descriptor, then add it to the services to be
                // serialized (if it's not already included)
                if (declaredServiceNames.contains(haServiceName)) {
                    if (!serviceNames.contains(haServiceName)) {
                        serviceNames.add(haServiceName);
                    }
                }
            }

            // Write the service declarations
            for (String serviceName : serviceNames) {
                sw.write("\n");
                sw.write("    <service>\n");
                sw.write("        <role>" + serviceName + "</role>\n");

                if (serviceVersions.containsKey(serviceName)) {
                    sw.write("        <version>" + serviceVersions.get(serviceName) + "</version>\n");
                }

                // Add the service params to the map for serialization
                Map<String,String> params = serviceParams.computeIfAbsent(serviceName, k -> new HashMap<>());

                ServiceDiscovery.Cluster.ZooKeeperConfig zkConf = haServiceParams.get(serviceName);

                // Determine whether to persist the haEnabled param, and to what value
                boolean isServiceHaEnabledAuto = false;
                boolean isServiceHaEnabled = false;

                if (haProvider != null) {
                    Map<String, String> haParams = haProvider.getParams();
                    if (haParams != null && haParams.containsKey(serviceName)) {
                        String serviceHaParams = haParams.get(serviceName);
                        Map<String,String> parsedServiceHaParams = parseHaProviderParam(serviceHaParams);
                        String enabledValue = parsedServiceHaParams.get("enabled");
                        if (enabledValue != null) {
                            if ("auto".equalsIgnoreCase(enabledValue)) {
                                isServiceHaEnabledAuto = true;
                                isServiceHaEnabled = (zkConf != null && zkConf.isEnabled());
                            } else {
                                isServiceHaEnabled = "true".equalsIgnoreCase(enabledValue);
                            }
                        }
                    }
                }

                // If the HA provider configuration for this service indicates an enabled value of "auto", then
                // persist the derived enabled value.
                if (isServiceHaEnabledAuto) {
                    params.put(org.apache.knox.gateway.topology.Service.HA_ENABLED_PARAM,
                               String.valueOf(isServiceHaEnabled));
                }

                // If the service is configured for ZooKeeper-based HA
                if (zkConf != null && zkConf.getEnsemble() != null && isServiceHaEnabled) {
                    String ensemble = zkConf.getEnsemble();
                    if (ensemble != null && !ensemble.isEmpty()) {
                        params.put("zookeeperEnsemble", ensemble);
                    }

                    String namespace = zkConf.getNamespace();
                    if (namespace != null && !namespace.isEmpty() ) {
                        params.put("zookeeperNamespace", namespace);
                    }
                } else {
                    // Serialize the service URLs
                    List<String> urls = serviceURLs.get(serviceName);
                    if (urls != null) {
                        for (String url : urls) {
                            sw.write("        <url>" + url + "</url>\n");
                        }
                    }
                }

                // Params
                Map<String, String> svcParams = serviceParams.get(serviceName);
                if (svcParams != null) {
                    for (Entry<String, String> svcParam : svcParams.entrySet()) {
                        if (!(svcParam.getKey().toLowerCase(Locale.ROOT)).startsWith(SimpleDescriptor.DISCOVERY_PARAM_PREFIX)) {
                            sw.write("        <param>\n");
                            sw.write("            <name>" + svcParam.getKey() + "</name>\n");
                            sw.write("            <value>" + getXmlEscapedValue(svcParam.getValue()) + "</value>\n");
                            sw.write("        </param>\n");
                        }
                    }
                }

                sw.write("    </service>\n");
            }

            // Applications
            List<SimpleDescriptor.Application> apps = desc.getApplications();
            if (apps != null) {
                for (SimpleDescriptor.Application app : apps) {
                    sw.write("    <application>\n");
                    sw.write("        <name>" + app.getName() + "</name>\n");

                    // URLs
                    List<String> urls = app.getURLs();
                    if (urls != null) {
                        for (String url : urls) {
                            sw.write("        <url>" + url + "</url>\n");
                        }
                    }

                    // Params
                    Map<String, String> appParams = app.getParams();
                    if (appParams != null) {
                        for (Entry<String, String> entry : appParams.entrySet()) {
                            sw.write("        <param>\n");
                            sw.write("            <name>" + entry.getKey() + "</name>\n");
                            sw.write("            <value>" + getXmlEscapedValue(entry.getValue()) + "</value>\n");
                            sw.write("        </param>\n");
                        }
                    }

                    sw.write("    </application>\n");
                }
            }

            sw.write("</topology>\n");

            // Write the generated content to a file
            String topologyFilename = desc.getName();
            if (topologyFilename == null) {
                topologyFilename = desc.getCluster();
            }

            topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");

            if (shouldPersistGeneratedTopology(topologyFilename, topologyDescriptor, sw.toString(), gwServices)) {
                log.persistingGeneratedTopology(topologyFilename);
                try (OutputStream outputStream = Files.newOutputStream(topologyDescriptor.toPath());
                     OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
                     BufferedWriter fw = new BufferedWriter(outputStreamWriter)) {
                    fw.write(sw.toString());
                    fw.flush();
                }
            } else {
                log.skippingDeploymentOfGeneratedTopology(topologyFilename); // KNOX-2302
            }
        } catch (IOException e) {
            log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
            topologyDescriptor.delete();
        }

        result.put(RESULT_TOPOLOGY, topologyDescriptor);

        return result;
    }