public Map endpointProperties()

in core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java [491:701]


    public Map<String, String> endpointProperties(String uri) throws URISyntaxException {
        // need to normalize uri first
        URI u = URISupport.normalizeUriAsURI(uri);
        String scheme = u.getScheme();

        // grab the syntax
        ComponentModel model = componentModel(scheme);
        if (model == null) {
            throw new IllegalArgumentException("Cannot find endpoint with scheme " + scheme);
        }
        String syntax = model.getSyntax();
        String alternativeSyntax = model.getAlternativeSyntax();
        if (syntax == null) {
            throw new IllegalArgumentException("Endpoint with scheme " + scheme + " has no syntax defined in the json schema");
        }

        // only if we support alternative syntax, and the uri contains the username and password in the authority
        // part of the uri, then we would need some special logic to capture that information and strip those
        // details from the uri, so we can continue parsing the uri using the normal syntax
        Map<String, String> userInfoOptions = new LinkedHashMap<>();
        if (alternativeSyntax != null && alternativeSyntax.contains("@")) {
            // clip the scheme from the syntax
            alternativeSyntax = StringHelper.after(alternativeSyntax, ":");
            // trim so only userinfo
            int idx = alternativeSyntax.indexOf('@');
            String fields = alternativeSyntax.substring(0, idx);
            String[] names = fields.split(":");

            // grab authority part and grab username and/or password
            String authority = u.getAuthority();
            if (authority != null && authority.contains("@")) {
                String username;
                String password;

                // grab unserinfo part before @
                String userInfo = authority.substring(0, authority.indexOf('@'));
                String[] parts = userInfo.split(":");
                if (parts.length == 2) {
                    username = parts[0];
                    password = parts[1];
                } else {
                    // only username
                    username = userInfo;
                    password = null;
                }

                // remember the username and/or password which we add later to the options
                if (names.length == 2) {
                    userInfoOptions.put(names[0], username);
                    if (password != null) {
                        // password is optional
                        userInfoOptions.put(names[1], password);
                    }
                }
            }
        }

        // clip the scheme from the syntax
        syntax = StringHelper.after(syntax, ":");
        // clip the scheme from the uri
        uri = StringHelper.after(uri, ":");
        String uriPath = URISupport.stripQuery(uri);

        // the uri path may use {{env:xxx}} or {{sys:xxx}} placeholders so ignore those
        Matcher matcher = ENV_OR_SYS_PATTERN.matcher(uriPath);
        uriPath = matcher.replaceAll("");

        // strip user info from uri path
        if (!userInfoOptions.isEmpty()) {
            uriPath = StringHelper.after(uriPath, "@", uriPath);
        }

        // strip double slash in the start
        if (uriPath != null && uriPath.startsWith("//")) {
            uriPath = uriPath.substring(2);
        }

        // parse the syntax and find the names of each option
        matcher = SYNTAX_PATTERN.matcher(syntax);
        List<String> word = new ArrayList<>();
        while (matcher.find()) {
            String s = matcher.group(1);
            if (!scheme.equals(s)) {
                word.add(s);
            }
        }
        // parse the syntax and find each token between each option
        final List<String> word2 = findTokens(syntax, scheme, uriPath);

        boolean defaultValueAdded = false;

        // now parse the uri to know which part isw what
        Map<String, String> options = new LinkedHashMap<>();

        // include the username and password from the userinfo section
        if (!userInfoOptions.isEmpty()) {
            options.putAll(userInfoOptions);
        }

        Map<String, BaseOptionModel> rows = new HashMap<>();
        model.getComponentOptions().forEach(o -> rows.put(o.getName(), o));
        // endpoint options have higher priority so overwrite component options
        model.getEndpointOptions().forEach(o -> rows.put(o.getName(), o));
        model.getEndpointPathOptions().forEach(o -> rows.put(o.getName(), o));

        // is this an api component then there may be additional options
        if (model.isApi()) {
            String[] apiSyntax = StringHelper.splitWords(model.getSyntax());
            int pos = word.indexOf(apiSyntax[0]);
            if (pos != -1) {
                String key = word2.size() > pos ? word2.get(pos) : null;
                // key2 should be null as its fine to get all the options for api name
                Map<String, BaseOptionModel> apiProperties = extractApiProperties(model, key, null);
                rows.putAll(apiProperties);
            }
        }

        // word contains the syntax path elements
        Iterator<String> it = word2.iterator();
        for (int i = 0; i < word.size(); i++) {
            String key = word.get(i);
            BaseOptionModel option = rows.get(key);
            boolean allOptions = word.size() == word2.size();

            // we have all options so no problem
            if (allOptions) {
                String value = it.next();
                options.put(key, value);
            } else {
                // we have a little problem as we do not not have all options
                if (!option.isRequired()) {
                    Object value = null;

                    boolean last = i == word.size() - 1;
                    if (last) {
                        // if its the last value then use it instead of the default value
                        value = it.hasNext() ? it.next() : null;
                        if (value != null) {
                            options.put(key, value.toString());
                        } else {
                            value = option.getDefaultValue();
                        }
                    }
                    if (value != null) {
                        options.put(key, value.toString());
                        defaultValueAdded = true;
                    }
                } else {
                    String value = it.hasNext() ? it.next() : null;
                    if (value != null) {
                        options.put(key, value);
                    }
                }
            }
        }

        Map<String, String> answer = new LinkedHashMap<>();

        // remove all options which are using default values and are not required
        for (Map.Entry<String, String> entry : options.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            BaseOptionModel row = rows.get(key);
            if (defaultValueAdded) {
                boolean required = row.isRequired();
                Object defaultValue = row.getDefaultValue();

                if (!required && defaultValue != null) {
                    if (defaultValue.toString().equals(value)) {
                        continue;
                    }
                }
            }

            // we should keep this in the answer
            answer.put(key, value);
        }

        // now parse the uri parameters
        Map<String, Object> parameters = CatalogHelper.parseParameters(u);

        // and covert the values to String so its JMX friendly
        while (!parameters.isEmpty()) {
            Map.Entry<String, Object> entry = parameters.entrySet().iterator().next();
            String key = entry.getKey();
            String value = entry.getValue() != null ? entry.getValue().toString() : "";
            BaseOptionModel row = rows.get(key);
            if (row != null && row.isMultiValue()) {
                String prefix = row.getPrefix();
                if (prefix != null) {
                    // extra all the multi valued options
                    Map<String, Object> values = URISupport.extractProperties(parameters, prefix);
                    // build a string with the extra multi valued options with the prefix and & as separator
                    String csb = values.entrySet().stream()
                            .map(multi -> prefix + multi.getKey() + "="
                                          + (multi.getValue() != null ? multi.getValue().toString() : ""))
                            .collect(Collectors.joining("&"));
                    // append the extra multi-values to the existing (which contains the first multi value)
                    if (!csb.isEmpty()) {
                        value = value + "&" + csb;
                    }
                }
            }

            answer.put(key, value);
            // remove the parameter as we run in a while loop until no more parameters
            parameters.remove(key);
        }

        return answer;
    }