/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.connector; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.camel.util.StringHelper; import org.apache.camel.util.function.Suppliers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class ConnectorModel { private static final Logger LOGGER = LoggerFactory.getLogger(ConnectorModel.class); private static final Pattern NAME_PATTERN = Pattern.compile("\"name\"\\s?:\\s?\"([\\w|.-]+)\".*"); private static final Pattern JAVA_TYPE_PATTERN = Pattern.compile("\"javaType\"\\s?:\\s?\"([\\w|.]+)\".*"); private static final Pattern BASE_JAVA_TYPE_PATTERN = Pattern.compile("\"baseJavaType\"\\s?:\\s?\"([\\w|.]+)\".*"); private static final Pattern BASE_SCHEME_PATTERN = Pattern.compile("\"baseScheme\"\\s?:\\s?\"([\\w|.-]+)\".*"); private static final Pattern SCHEDULER_PATTERN = Pattern.compile("\"scheduler\"\\s?:\\s?\"([\\w|.-]+)\".*"); private static final Pattern INPUT_DATA_TYPE_PATTERN = Pattern.compile("\"inputDataType\"\\s?:\\s?\"(\\*|[\\w|.:*]+)\".*"); private static final Pattern OUTPUT_DATA_TYPE_PATTERN = Pattern.compile("\"outputDataType\"\\s?:\\s?\"([\\w|.:*]+)\".*"); private final String componentName; private final String className; private final Supplier<List<String>> lines; private String baseScheme; private String baseJavaType; private String scheduler; private String connectorJSon; private String connectorName; private DataType inputDataType; private DataType outputDataType; private Map<String, String> defaultComponentOptions; private Map<String, String> defaultEndpointOptions; private List<String> endpointOptions; private List<String> componentOptions; ConnectorModel(String componentName, String className) { this.componentName = componentName; this.className = className; this.lines = Suppliers.memorize(() -> findCamelConnectorJSonSchema()); } public String getComponentName() { return componentName; } public String getClassName() { return className; } public String getBaseScheme() { if (baseScheme == null) { baseScheme = extractBaseScheme(lines.get()); } return baseScheme; } public String getBaseJavaType() { if (baseJavaType == null) { baseJavaType = extractBaseJavaType(lines.get()); } return baseJavaType; } public String getScheduler() { if (scheduler == null) { scheduler = extractScheduler(lines.get()); } return scheduler; } public String getConnectorName() { if (connectorName == null) { connectorName = extractName(lines.get()); } return connectorName; } public String getConnectorJSon() { if (connectorJSon == null) { connectorJSon = lines.get().stream().collect(Collectors.joining("\n")); } return connectorJSon; } public Map<String, String> getDefaultComponentOptions() { if (defaultComponentOptions == null) { defaultComponentOptions = Collections.unmodifiableMap(extractComponentDefaultValues(lines.get())); } return defaultComponentOptions; } public Map<String, String> getDefaultEndpointOptions() { if (defaultEndpointOptions == null) { defaultEndpointOptions = Collections.unmodifiableMap(extractEndpointDefaultValues(lines.get())); } return defaultEndpointOptions; } public List<String> getEndpointOptions() { if (endpointOptions == null) { endpointOptions = Collections.unmodifiableList(extractEndpointOptions(lines.get())); } return endpointOptions; } public List<String> getComponentOptions() { if (endpointOptions == null) { endpointOptions = Collections.unmodifiableList(extractComponentOptions(lines.get())); } return endpointOptions; } public DataType getInputDataType() { if (inputDataType == null) { String line = extractInputDataType(lines.get()); if (line != null) { inputDataType = new DataType(line); } } return inputDataType; } public DataType getOutputDataType() { if (outputDataType == null) { String line = extractOutputDataType(lines.get()); if (line != null) { outputDataType = new DataType(line); } } return outputDataType; } // *************************************** // Helpers // *************************************** private List<String> findCamelConnectorJSonSchema() { LOGGER.debug("Finding camel-connector.json in classpath for connector: {}", componentName); Enumeration<URL> urls; try { urls = ConnectorModel.class.getClassLoader().getResources("camel-connector.json"); } catch (IOException e) { throw new IllegalArgumentException("Cannot open camel-connector.json in classpath for connector " + componentName); } while (urls.hasMoreElements()) { try (InputStream is = urls.nextElement().openStream()) { List<String> lines = loadFile(is); String javaType = extractJavaType(lines); LOGGER.debug("Found camel-connector.json in classpath with javaType: {}", javaType); if (className.equals(javaType)) { return lines; } } catch (Exception e) { throw new IllegalArgumentException("Cannot read camel-connector.json in classpath for connector " + componentName); } } return Collections.emptyList(); } private static List<String> loadFile(InputStream fis) throws Exception { List<String> lines = new ArrayList<>(); LineNumberReader reader = new LineNumberReader(new InputStreamReader(fis)); String line; do { line = reader.readLine(); if (line != null) { lines.add(line); } } while (line != null); reader.close(); return lines; } private static String extractName(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = NAME_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractJavaType(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = JAVA_TYPE_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractBaseJavaType(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = BASE_JAVA_TYPE_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractScheduler(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = SCHEDULER_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractBaseScheme(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = BASE_SCHEME_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractInputDataType(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = INPUT_DATA_TYPE_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private static String extractOutputDataType(List<String> json) { for (String line : json) { line = line.trim(); Matcher matcher = OUTPUT_DATA_TYPE_PATTERN.matcher(line); if (matcher.matches()) { return matcher.group(1); } } return null; } private Map<String, String> extractComponentDefaultValues(List<String> lines) { Map<String, String> answer = new LinkedHashMap<>(); // extract the default options boolean found = false; for (String line : lines) { line = line.trim(); if (line.startsWith("\"componentValues\"")) { found = true; } else if (line.startsWith("}")) { found = false; } else if (found) { int pos = line.indexOf(':'); String key = line.substring(0, pos); String value = line.substring(pos + 1); value = value.trim(); key = key.trim(); if (value.endsWith(",")) { value = value.substring(0, value.length() - 1); } key = StringHelper.removeLeadingAndEndingQuotes(key); value = StringHelper.removeLeadingAndEndingQuotes(value); answer.put(key, value); } } return answer; } private Map<String, String> extractEndpointDefaultValues(List<String> lines) { Map<String, String> answer = new LinkedHashMap<>(); // extract the default options boolean found = false; for (String line : lines) { line = line.trim(); if (line.startsWith("\"endpointValues\"")) { found = true; } else if (line.startsWith("}")) { found = false; } else if (found) { int pos = line.indexOf(':'); String key = line.substring(0, pos); String value = line.substring(pos + 1); value = value.trim(); key = key.trim(); if (value.endsWith(",")) { value = value.substring(0, value.length() - 1); } key = StringHelper.removeLeadingAndEndingQuotes(key); value = StringHelper.removeLeadingAndEndingQuotes(value); answer.put(key, value); } } return answer; } private List<String> extractComponentOptions(List<String> lines) { List<String> answer = new ArrayList<>(); // extract the default options for (String line : lines) { line = line.trim(); if (line.startsWith("\"componentOptions\"")) { int start = line.indexOf('['); if (start == -1) { throw new IllegalStateException("Malformed camel-connector.json"); } int end = line.indexOf(']', start); if (end == -1) { throw new IllegalStateException("Malformed camel-connector.json"); } line = line.substring(start + 1, end).trim(); for (String option : line.split(",")) { answer.add(StringHelper.removeLeadingAndEndingQuotes(option)); } break; } } return answer; } private List<String> extractEndpointOptions(List<String> lines) { List<String> answer = new ArrayList<>(); // extract the default options for (String line : lines) { line = line.trim(); if (line.startsWith("\"endpointOptions\"")) { int start = line.indexOf('['); if (start == -1) { throw new IllegalStateException("Malformed camel-connector.json"); } int end = line.indexOf(']', start); if (end == -1) { throw new IllegalStateException("Malformed camel-connector.json"); } line = line.substring(start + 1, end).trim(); for (String option : line.split(",")) { answer.add(StringHelper.removeLeadingAndEndingQuotes(option)); } break; } } return answer; } }