You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/01/19 11:06:44 UTC
[04/17] camel git commit: CAMEL-10721: camel-connector
CAMEL-10721: camel-connector
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/c473d0b9
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/c473d0b9
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/c473d0b9
Branch: refs/heads/master
Commit: c473d0b9627ff8b6a817c31092c55f86904a5137
Parents: c4ee179
Author: Claus Ibsen <da...@apache.org>
Authored: Wed Jan 18 14:27:14 2017 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Jan 19 11:00:00 2017 +0100
----------------------------------------------------------------------
connectors/camel-connector-maven-plugin/pom.xml | 90 ++++
.../maven/connector/CollectionStringBuffer.java | 57 +++
.../camel/maven/connector/ConnectorMojo.java | 501 +++++++++++++++++++
.../camel/maven/connector/FileHelper.java | 56 +++
.../apache/camel/maven/connector/GitHelper.java | 123 +++++
.../camel/maven/connector/JSonSchemaHelper.java | 356 +++++++++++++
.../src/main/resources/META-INF/MANIFEST.MF | 4 +
connectors/pom.xml | 1 +
parent/pom.xml | 2 +
9 files changed, 1190 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/pom.xml b/connectors/camel-connector-maven-plugin/pom.xml
new file mode 100644
index 0000000..6eaaf29
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>connectors</artifactId>
+ <version>2.19.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-connector-maven-plugin</artifactId>
+ <name>Camel :: Connector :: Camel Connector Maven Plugin</name>
+ <packaging>maven-plugin</packaging>
+
+ <dependencies>
+
+ <!-- we extend this existing maven plugin -->
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>${maven-jar-plugin-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.2</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- use jackson json parser -->
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson2-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>${jackson2-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson2-version}</version>
+ </dependency>
+
+ <!-- logging -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j-version}</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>${maven-jar-plugin-version}</version>
+ <configuration>
+ <!-- must include our own dummy manifest -->
+ <archive>
+ <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/CollectionStringBuffer.java
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/CollectionStringBuffer.java b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/CollectionStringBuffer.java
new file mode 100644
index 0000000..bd11654
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/CollectionStringBuffer.java
@@ -0,0 +1,57 @@
+/**
+ * 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.maven.connector;
+
+public class CollectionStringBuffer {
+ private final StringBuilder buffer = new StringBuilder();
+ private String separator;
+ private boolean first = true;
+
+ public CollectionStringBuffer() {
+ this(", ");
+ }
+
+ public CollectionStringBuffer(String separator) {
+ this.separator = separator;
+ }
+
+ @Override
+ public String toString() {
+ return buffer.toString();
+ }
+
+ public void append(Object value) {
+ if (first) {
+ first = false;
+ } else {
+ buffer.append(separator);
+ }
+ buffer.append(value);
+ }
+
+ public String getSeparator() {
+ return separator;
+ }
+
+ public void setSeparator(String separator) {
+ this.separator = separator;
+ }
+
+ public boolean isEmpty() {
+ return first;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/ConnectorMojo.java
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/ConnectorMojo.java b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/ConnectorMojo.java
new file mode 100644
index 0000000..4683db7
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/ConnectorMojo.java
@@ -0,0 +1,501 @@
+/**
+ * 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.maven.connector;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.plugin.jar.AbstractJarMojo;
+
+@Mojo(name = "jar", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresProject = true, threadSafe = true,
+ requiresDependencyResolution = ResolutionScope.RUNTIME)
+public class ConnectorMojo extends AbstractJarMojo {
+
+ /**
+ * Directory containing the classes and resource files that should be packaged into the JAR.
+ */
+ @Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
+ private File classesDirectory;
+
+ @Override
+ protected File getClassesDirectory() {
+ return classesDirectory;
+ }
+
+ @Override
+ protected String getClassifier() {
+ return "camel-connector";
+ }
+
+ @Override
+ protected String getType() {
+ return "jar";
+ }
+
+ @Override
+ public File createArchive() throws MojoExecutionException {
+
+ String gitUrl;
+
+ // find the component dependency and get its .json file
+
+ File file = new File(classesDirectory, "camel-connector.json");
+ if (file.exists()) {
+
+ // we want to include the git url of the project
+ File gitFolder = GitHelper.findGitFolder();
+ try {
+ gitUrl = GitHelper.extractGitUrl(gitFolder);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Cannot extract gitUrl due " + e.getMessage(), e);
+ }
+ if (gitUrl == null) {
+ getLog().warn("No .git directory found for connector");
+ }
+
+ try {
+
+ ObjectMapper mapper = new ObjectMapper();
+ Map dto = mapper.readValue(file, Map.class);
+
+ // embed girUrl in camel-connector.json file
+ if (gitUrl != null) {
+ String existingGitUrl = (String) dto.get("gitUrl");
+ if (existingGitUrl == null || !existingGitUrl.equals(gitUrl)) {
+ dto.put("gitUrl", gitUrl);
+ // update file
+ mapper.writerWithDefaultPrettyPrinter().writeValue(file, dto);
+ // update source file also
+ File root = classesDirectory.getParentFile().getParentFile();
+ file = new File(root, "src/main/resources/camel-connector.json");
+ if (file.exists()) {
+ getLog().info("Updating gitUrl to " + file);
+ mapper.writerWithDefaultPrettyPrinter().writeValue(file, dto);
+ }
+ }
+ }
+
+ File schema = embedCamelComponentSchema(file);
+ if (schema != null) {
+ String json = FileHelper.loadText(new FileInputStream(schema));
+
+ List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false);
+ String header = buildComponentHeaderSchema(rows, dto, gitUrl);
+ getLog().debug(header);
+
+ rows = JSonSchemaHelper.parseJsonSchema("componentProperties", json, true);
+ // we do not offer editing component properties (yet) so clear the rows
+ rows.clear();
+ String componentOptions = buildComponentOptionsSchema(rows, dto);
+ getLog().debug(componentOptions);
+
+ rows = JSonSchemaHelper.parseJsonSchema("properties", json, true);
+ String endpointOptions = buildEndpointOptionsSchema(rows, dto);
+ getLog().debug(endpointOptions);
+
+ // generate the json file
+ StringBuilder jsonSchema = new StringBuilder();
+ jsonSchema.append("{\n");
+ jsonSchema.append(header);
+ jsonSchema.append(componentOptions);
+ jsonSchema.append(endpointOptions);
+ jsonSchema.append("}\n");
+
+ String newJson = jsonSchema.toString();
+
+ // parse ourselves
+ rows = JSonSchemaHelper.parseJsonSchema("component", newJson, false);
+ String newScheme = getOption(rows, "scheme");
+
+ // write the json file to the target directory as if camel apt would do it
+ String javaType = (String) dto.get("javaType");
+ String dir = javaType.substring(0, javaType.lastIndexOf("."));
+ dir = dir.replace('.', '/');
+ File subDir = new File(classesDirectory, dir);
+ String name = newScheme + ".json";
+ File out = new File(subDir, name);
+
+ FileOutputStream fos = new FileOutputStream(out, false);
+ fos.write(newJson.getBytes());
+ fos.close();
+ }
+
+ // build json schema for component that only has the selectable options
+ } catch (Exception e) {
+ throw new MojoExecutionException("Error in connector-maven-plugin", e);
+ }
+ }
+
+ return super.createArchive();
+ }
+
+ private String extractJavaType(String scheme) throws Exception {
+ File file = new File(classesDirectory, "META-INF/services/org/apache/camel/component/" + scheme);
+ if (file.exists()) {
+ List<String> lines = loadFile(file);
+ String fqn = extractClass(lines);
+ return fqn;
+ }
+ return null;
+ }
+
+ private String getOption(List<Map<String, String>> rows, String key) {
+ for (Map<String, String> row : rows) {
+ if (row.containsKey(key)) {
+ return row.get(key);
+ }
+ }
+ return null;
+ }
+
+ private String buildComponentOptionsSchema(List<Map<String, String>> rows, Map dto) throws JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(" \"componentProperties\": {\n");
+
+ for (int i = 0; i < rows.size(); i++) {
+ Map<String, String> row = rows.get(i);
+ String key = row.get("name");
+ row.remove("name");
+ String line = mapper.writeValueAsString(row);
+
+ sb.append(" \"" + key + "\": ");
+ sb.append(line);
+ if (i < rows.size() - 1) {
+ sb.append(",\n");
+ } else {
+ sb.append("\n");
+ }
+ }
+
+ sb.append(" },\n");
+ return sb.toString();
+ }
+
+ private String buildEndpointOptionsSchema(List<Map<String, String>> rows, Map dto) throws JsonProcessingException {
+ // find the endpoint options
+ List options = (List) dto.get("endpointOptions");
+ Map values = (Map) dto.get("endpointValues");
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(" \"properties\": {\n");
+
+ boolean first = true;
+ for (int i = 0; i < rows.size(); i++) {
+ Map<String, String> row = rows.get(i);
+ String key = row.get("name");
+ row.remove("name");
+
+ // TODO: if no options should we include all by default instead?
+ if (options == null || !options.contains(key)) {
+ continue;
+ }
+
+ // do we have a new default value for this row?
+ if (values != null && values.containsKey(key)) {
+ String newDefaultValue = (String) values.get(key);
+ if (newDefaultValue != null) {
+ row.put("defaultValue", newDefaultValue);
+ }
+ }
+
+ // we should build the json as one-line which is how Camel does it today
+ // which makes its internal json parser support loading our generated schema file
+ String line = mapper.writeValueAsString(row);
+
+ if (!first) {
+ sb.append(",\n");
+ }
+ sb.append(" \"" + key + "\": ");
+ sb.append(line);
+
+ first = false;
+ }
+ if (!first) {
+ sb.append("\n");
+ }
+
+ sb.append(" }\n");
+ return sb.toString();
+ }
+
+ private String buildComponentHeaderSchema(List<Map<String, String>> rows, Map dto, String gitUrl) throws Exception {
+ String baseScheme = (String) dto.get("baseScheme");
+ String source = (String) dto.get("source");
+ String title = (String) dto.get("name");
+ String scheme = camelCaseToDash(title);
+ String baseSyntax = getOption(rows, "syntax");
+ String syntax = baseSyntax.replaceFirst(baseScheme, scheme);
+
+ String description = (String) dto.get("description");
+ // dto has labels
+ String label = null;
+ List<String> labels = (List<String>) dto.get("labels");
+ if (labels != null) {
+ CollectionStringBuffer csb = new CollectionStringBuffer(",");
+ for (String s : labels) {
+ csb.append(s);
+ }
+ label = csb.toString();
+ }
+ String async = getOption(rows, "async");
+ String producerOnly = "To".equals(source) ? "true" : null;
+ String consumerOnly = "From".equals(source) ? "true" : null;
+ String lenientProperties = getOption(rows, "lenientProperties");
+ String javaType = extractJavaType(scheme);
+ String groupId = getProject().getGroupId();
+ String artifactId = getProject().getArtifactId();
+ String version = getProject().getVersion();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(" \"component\": {\n");
+ sb.append(" \"girUrl\": \"" + nullSafe(gitUrl) + "\",\n");
+ sb.append(" \"kind\": \"component\",\n");
+ sb.append(" \"baseScheme\": \"" + nullSafe(baseScheme) + "\",\n");
+ sb.append(" \"scheme\": \"" + scheme + "\",\n");
+ sb.append(" \"syntax\": \"" + syntax + "\",\n");
+ sb.append(" \"title\": \"" + title + "\",\n");
+ if (description != null) {
+ sb.append(" \"description\": \"" + description + "\",\n");
+ }
+ if (label != null) {
+ sb.append(" \"label\": \"" + label + "\",\n");
+ }
+ sb.append(" \"deprecated\": \"false\",\n");
+ if (async != null) {
+ sb.append(" \"async\": \"" + async + "\",\n");
+ }
+ if (producerOnly != null) {
+ sb.append(" \"producerOnly\": \"" + producerOnly + "\",\n");
+ } else if (consumerOnly != null) {
+ sb.append(" \"consumerOnly\": \"" + consumerOnly + "\",\n");
+ }
+ if (lenientProperties != null) {
+ sb.append(" \"lenientProperties\": \"" + lenientProperties + "\",\n");
+ }
+ sb.append(" \"javaType\": \"" + javaType + "\",\n");
+ sb.append(" \"groupId\": \"" + groupId + "\",\n");
+ sb.append(" \"artifactId\": \"" + artifactId + "\",\n");
+ sb.append(" \"version\": \"" + version + "\"\n");
+ sb.append(" },\n");
+
+ return sb.toString();
+ }
+
+ private static String nullSafe(String text) {
+ return text != null ? text : "";
+ }
+
+ /**
+ * Finds and embeds the Camel component JSon schema file
+ */
+ private File embedCamelComponentSchema(File file) throws MojoExecutionException {
+ try {
+ List<String> json = loadFile(file);
+
+ String scheme = extractScheme(json);
+ String groupId = extractGroupId(json);
+ String artifactId = extractArtifactId(json);
+ String version = extractVersion(json); // version not in use
+
+ // find the artifact on the classpath that has the Camel component this connector is using
+ // then we want to grab its json schema file to embed in this JAR so we have all files together
+
+ if (scheme != null && groupId != null && artifactId != null) {
+ for (Object obj : getProject().getDependencyArtifacts()) {
+ Artifact artifact = (Artifact) obj;
+ if ("jar".equals(artifact.getType())) {
+ if (groupId.equals(artifact.getGroupId()) && artifactId.equals(artifact.getArtifactId())) {
+ // load the component file inside the file
+ URL url = new URL("file:" + artifact.getFile());
+ URLClassLoader child = new URLClassLoader(new URL[]{url}, this.getClass().getClassLoader());
+
+ InputStream is = child.getResourceAsStream("META-INF/services/org/apache/camel/component/" + scheme);
+ if (is != null) {
+ List<String> lines = loadFile(is);
+ String fqn = extractClass(lines);
+ is.close();
+
+ // only keep package
+ String pck = fqn.substring(0, fqn.lastIndexOf("."));
+ String name = pck.replace(".", "/") + "/" + scheme + ".json";
+
+ is = child.getResourceAsStream(name);
+ if (is != null) {
+ List<String> schema = loadFile(is);
+ is.close();
+
+ // write schema to file
+ File out = new File(classesDirectory, "camel-component-schema.json");
+ FileOutputStream fos = new FileOutputStream(out, false);
+ for (String line : schema) {
+ fos.write(line.getBytes());
+ fos.write("\n".getBytes());
+ }
+ fos.close();
+
+ getLog().info("Embedded camel-component-schema.json file for Camel component " + scheme);
+
+ return out;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ throw new MojoExecutionException("Cannot read file camel-connector.json", e);
+ }
+
+ return null;
+ }
+
+ private String extractClass(List<String> lines) {
+ for (String line : lines) {
+ line = line.trim();
+ if (line.startsWith("class=")) {
+ return line.substring(6);
+ }
+ }
+ return null;
+ }
+
+ private String extractScheme(List<String> json) {
+ for (String line : json) {
+ line = line.trim();
+ if (line.startsWith("\"baseScheme\":")) {
+ String answer = line.substring(14);
+ return answer.substring(0, answer.length() - 2);
+ }
+ }
+ return null;
+ }
+
+ private String extractGroupId(List<String> json) {
+ for (String line : json) {
+ line = line.trim();
+ if (line.startsWith("\"baseGroupId\":")) {
+ String answer = line.substring(15);
+ return answer.substring(0, answer.length() - 2);
+ }
+ }
+ return null;
+ }
+
+ private String extractArtifactId(List<String> json) {
+ for (String line : json) {
+ line = line.trim();
+ if (line.startsWith("\"baseArtifactId\":")) {
+ String answer = line.substring(18);
+ return answer.substring(0, answer.length() - 2);
+ }
+ }
+ return null;
+ }
+
+ private String extractVersion(List<String> json) {
+ for (String line : json) {
+ line = line.trim();
+ if (line.startsWith("\"baseVersion\":")) {
+ String answer = line.substring(15);
+ return answer.substring(0, answer.length() - 2);
+ }
+ }
+ return null;
+ }
+
+ private List<String> loadFile(File file) throws Exception {
+ List<String> lines = new ArrayList<>();
+ LineNumberReader reader = new LineNumberReader(new FileReader(file));
+
+ String line;
+ do {
+ line = reader.readLine();
+ if (line != null) {
+ lines.add(line);
+ }
+ } while (line != null);
+ reader.close();
+
+ return lines;
+ }
+
+ private 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;
+ }
+
+ public static String camelCaseToDash(String value) {
+ StringBuilder sb = new StringBuilder(value.length());
+ boolean dash = false;
+
+ for (char c : value.toCharArray()) {
+ // skip dash in start
+ if (sb.length() > 0 & Character.isUpperCase(c)) {
+ dash = true;
+ }
+ if (dash) {
+ sb.append('-');
+ sb.append(Character.toLowerCase(c));
+ } else {
+ // lower case first
+ if (sb.length() == 0) {
+ sb.append(Character.toLowerCase(c));
+ } else {
+ sb.append(c);
+ }
+ }
+ dash = false;
+ }
+ return sb.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/FileHelper.java
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/FileHelper.java b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/FileHelper.java
new file mode 100644
index 0000000..caecd16
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/FileHelper.java
@@ -0,0 +1,56 @@
+/**
+ * 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.maven.connector;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+public class FileHelper {
+
+ /**
+ * Loads the entire stream into memory as a String and returns it.
+ * <p/>
+ * <b>Notice:</b> This implementation appends a <tt>\n</tt> as line
+ * terminator at the of the text.
+ * <p/>
+ * Warning, don't use for crazy big streams :)
+ */
+ public static String loadText(InputStream in) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ InputStreamReader isr = new InputStreamReader(in);
+ try {
+ BufferedReader reader = new LineNumberReader(isr);
+ while (true) {
+ String line = reader.readLine();
+ if (line != null) {
+ builder.append(line);
+ builder.append("\n");
+ } else {
+ break;
+ }
+ }
+ return builder.toString();
+ } finally {
+ isr.close();
+ in.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/GitHelper.java
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/GitHelper.java b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/GitHelper.java
new file mode 100644
index 0000000..92c50ee
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/GitHelper.java
@@ -0,0 +1,123 @@
+/**
+ * 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.maven.connector;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GitHelper {
+
+ public static File findGitFolder() {
+ File baseDir = new File("").getAbsoluteFile();
+ return findGitFolder(baseDir);
+ }
+
+ private static File findGitFolder(File basedir) {
+ File gitDir = new File(basedir, ".git");
+ if (gitDir.exists() && gitDir.isDirectory()) {
+ return gitDir;
+ }
+
+ File parent = basedir.getParentFile();
+ if (parent != null) {
+ return findGitFolder(parent);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the remote git URL for the given folder; looking for the .git/config file in the current directory or a parent directory
+ */
+ public static String extractGitUrl(File basedir) throws IOException {
+ if (basedir == null) {
+ return null;
+ }
+ if (basedir.exists() && basedir.isDirectory()) {
+ File gitConfig = new File(basedir, ".git/config");
+ if (gitConfig.isFile() && gitConfig.exists()) {
+ String text = FileHelper.loadText(new FileInputStream(gitConfig));
+ return extractGitUrl(text);
+ }
+ }
+ File parentFile = basedir.getParentFile();
+ if (parentFile != null) {
+ return extractGitUrl(parentFile);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the remote git URL for the given git config file text lets extract the
+ */
+ private static String extractGitUrl(String configText) {
+ String remote = null;
+ String lastUrl = null;
+ String firstUrl = null;
+ BufferedReader reader = new BufferedReader(new StringReader(configText));
+ Map<String, String> remoteUrls = new HashMap<>();
+ while (true) {
+ String line = null;
+ try {
+ line = reader.readLine();
+ } catch (IOException e) {
+ // ignore should never happen!
+ }
+ if (line == null) {
+ break;
+ }
+ if (line.startsWith("[remote ")) {
+ String[] parts = line.split("\"");
+ if (parts.length > 1) {
+ remote = parts[1];
+ }
+ } else if (line.startsWith("[")) {
+ remote = null;
+ } else if (remote != null && line.length() > 0 && Character.isWhitespace(line.charAt(0))) {
+ String trimmed = line.trim();
+ if (trimmed.startsWith("url ")) {
+ String[] parts = trimmed.split("=", 2);
+ if (parts.length > 1) {
+ lastUrl = parts[1].trim();
+ if (firstUrl == null) {
+ firstUrl = lastUrl;
+ }
+ remoteUrls.put(remote, lastUrl);
+ }
+ }
+
+ }
+ }
+ String answer = null;
+ if (remoteUrls.size() == 1) {
+ return lastUrl;
+ } else if (remoteUrls.size() > 1) {
+ answer = remoteUrls.get("origin");
+ if (answer == null) {
+ answer = firstUrl;
+ }
+ }
+ return answer;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/JSonSchemaHelper.java
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/JSonSchemaHelper.java b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/JSonSchemaHelper.java
new file mode 100644
index 0000000..d42e5e3
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/java/org/apache/camel/maven/connector/JSonSchemaHelper.java
@@ -0,0 +1,356 @@
+/**
+ * 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.maven.connector;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class JSonSchemaHelper {
+
+ private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]");
+ private static final String QUOT = """;
+
+ private JSonSchemaHelper() {
+ }
+
+ /**
+ * Parses the json schema to split it into a list or rows, where each row contains key value pairs with the metadata
+ *
+ * @param group the group to parse from such as <tt>component</tt>, <tt>componentProperties</tt>, or <tt>properties</tt>.
+ * @param json the json
+ * @return a list of all the rows, where each row is a set of key value pairs with metadata
+ */
+ public static List<Map<String, String>> parseJsonSchema(String group, String json, boolean parseProperties) {
+ List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
+ if (json == null) {
+ return answer;
+ }
+
+ boolean found = false;
+
+ // parse line by line
+ String[] lines = json.split("\n");
+ for (String line : lines) {
+ // we need to find the group first
+ if (!found) {
+ String s = line.trim();
+ found = s.startsWith("\"" + group + "\":") && s.endsWith("{");
+ continue;
+ }
+
+ // we should stop when we end the group
+ if (line.equals(" },") || line.equals(" }")) {
+ break;
+ }
+
+ // need to safe encode \" so we can parse the line
+ line = line.replaceAll("\"\\\\\"\"", '"' + QUOT + '"');
+
+ Map<String, String> row = new LinkedHashMap<String, String>();
+ Matcher matcher = PATTERN.matcher(line);
+
+ String key;
+ if (parseProperties) {
+ // when parsing properties the first key is given as name, so the first parsed token is the value of the name
+ key = "name";
+ } else {
+ key = null;
+ }
+ while (matcher.find()) {
+ if (key == null) {
+ key = matcher.group(1);
+ } else {
+ String value = matcher.group(1);
+ if (value == null) {
+ value = matcher.group(2);
+ // its an enum so strip out " and trim spaces after comma
+ value = value.replaceAll("\"", "");
+ value = value.replaceAll(", ", ",");
+ }
+ if (value != null) {
+ value = value.trim();
+ // decode
+ value = value.replaceAll(QUOT, "\"");
+ value = decodeJson(value);
+ }
+ row.put(key, value);
+ // reset
+ key = null;
+ }
+ }
+ if (!row.isEmpty()) {
+ answer.add(row);
+ }
+ }
+
+ return answer;
+ }
+
+ private static String decodeJson(String value) {
+ // json encodes a \ as \\ so we need to decode from \\ back to \
+ if ("\\\\".equals(value)) {
+ value = "\\";
+ }
+ return value;
+ }
+
+ public static boolean isComponentLenientProperties(List<Map<String, String>> rows) {
+ for (Map<String, String> row : rows) {
+ if (row.containsKey("lenientProperties")) {
+ return "true".equals(row.get("lenientProperties"));
+ }
+ }
+ return false;
+ }
+
+ public static boolean isPropertyRequired(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ boolean required = false;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("required")) {
+ required = "true".equals(row.get("required"));
+ }
+ if (found) {
+ return required;
+ }
+ }
+ return false;
+ }
+
+ public static String getPropertyKind(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String kind = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("kind")) {
+ kind = row.get("kind");
+ }
+ if (found) {
+ return kind;
+ }
+ }
+ return null;
+ }
+
+ public static boolean isPropertyBoolean(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String type = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("type")) {
+ type = row.get("type");
+ }
+ if (found) {
+ return "boolean".equals(type);
+ }
+ }
+ return false;
+ }
+
+ public static boolean isPropertyInteger(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String type = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("type")) {
+ type = row.get("type");
+ }
+ if (found) {
+ return "integer".equals(type);
+ }
+ }
+ return false;
+ }
+
+ public static boolean isPropertyNumber(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String type = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("type")) {
+ type = row.get("type");
+ }
+ if (found) {
+ return "number".equals(type);
+ }
+ }
+ return false;
+ }
+
+ public static boolean isPropertyObject(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String type = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("type")) {
+ type = row.get("type");
+ }
+ if (found) {
+ return "object".equals(type);
+ }
+ }
+ return false;
+ }
+
+ public static String getPropertyDefaultValue(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String defaultValue = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("defaultValue")) {
+ defaultValue = row.get("defaultValue");
+ }
+ if (found) {
+ return defaultValue;
+ }
+ }
+ return null;
+ }
+
+ public static String stripOptionalPrefixFromName(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String optionalPrefix = null;
+ boolean found = false;
+ if (row.containsKey("optionalPrefix")) {
+ optionalPrefix = row.get("optionalPrefix");
+ }
+ if (row.containsKey("name")) {
+ if (optionalPrefix != null && name.startsWith(optionalPrefix)) {
+ name = name.substring(optionalPrefix.length());
+ // try again
+ return stripOptionalPrefixFromName(rows, name);
+ } else {
+ found = name.equals(row.get("name"));
+ }
+ }
+ if (found) {
+ return name;
+ }
+ }
+ return name;
+ }
+
+ public static String getPropertyEnum(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String enums = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("enum")) {
+ enums = row.get("enum");
+ }
+ if (found) {
+ return enums;
+ }
+ }
+ return null;
+ }
+
+ public static String getPropertyPrefix(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String prefix = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("prefix")) {
+ prefix = row.get("prefix");
+ }
+ if (found) {
+ return prefix;
+ }
+ }
+ return null;
+ }
+
+ public static boolean isPropertyMultiValue(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ boolean multiValue = false;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ found = name.equals(row.get("name"));
+ }
+ if (row.containsKey("multiValue")) {
+ multiValue = "true".equals(row.get("multiValue"));
+ }
+ if (found) {
+ return multiValue;
+ }
+ }
+ return false;
+ }
+
+ public static String getPropertyNameFromNameWithPrefix(List<Map<String, String>> rows, String name) {
+ for (Map<String, String> row : rows) {
+ String propertyName = null;
+ boolean found = false;
+ if (row.containsKey("name")) {
+ propertyName = row.get("name");
+ }
+ if (row.containsKey("prefix")) {
+ String preifx = row.get("prefix");
+ found = name.startsWith(preifx);
+ }
+ if (found) {
+ return propertyName;
+ }
+ }
+ return null;
+ }
+
+ public static Map<String, String> getRow(List<Map<String, String>> rows, String key) {
+ for (Map<String, String> row : rows) {
+ if (key.equals(row.get("name"))) {
+ return row;
+ }
+ }
+ return null;
+ }
+
+ public static Set<String> getNames(List<Map<String, String>> rows) {
+ Set<String> answer = new LinkedHashSet<String>();
+ for (Map<String, String> row : rows) {
+ if (row.containsKey("name")) {
+ answer.add(row.get("name"));
+ }
+ }
+ return answer;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/camel-connector-maven-plugin/src/main/resources/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/connectors/camel-connector-maven-plugin/src/main/resources/META-INF/MANIFEST.MF b/connectors/camel-connector-maven-plugin/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..8428f49
--- /dev/null
+++ b/connectors/camel-connector-maven-plugin/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Implementation-Title: Camel :: Connector :: Camel Connector Maven Plugin
+Implementation-Vendor: The Apache Software Foundation
+Implementation-Vendor-Id: org.apache.camel
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/connectors/pom.xml
----------------------------------------------------------------------
diff --git a/connectors/pom.xml b/connectors/pom.xml
index 43e285d..acb3aef 100644
--- a/connectors/pom.xml
+++ b/connectors/pom.xml
@@ -33,6 +33,7 @@
<modules>
<module>camel-connector</module>
+ <module>camel-connector-maven-plugin</module>
</modules>
</project>
http://git-wip-us.apache.org/repos/asf/camel/blob/c473d0b9/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 180a989..15c3330 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -425,6 +425,8 @@
<maven-jar-plugin-version>2.6</maven-jar-plugin-version>
<maven-javadoc-plugin-version>2.9.1</maven-javadoc-plugin-version>
<maven-jboss-as-maven-plugin-version>7.7.Final</maven-jboss-as-maven-plugin-version>
+ <!-- plugin-plugin 3.5 does not work -->
+ <maven-plugin-plugin-version>3.4</maven-plugin-plugin-version>
<maven-remote-resources-plugin-version>1.5</maven-remote-resources-plugin-version>
<!-- resources plugin needed by Camel maven archetypes -->
<maven-resources-plugin-version>3.0.1</maven-resources-plugin-version>