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;
}