Camel component docs. Add group as a way of combining the options in a number of coheret groups based on their labels.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/c850a6e0 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/c850a6e0 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/c850a6e0 Branch: refs/heads/master Commit: c850a6e0ec291dd04ec925eaeb387ee073aaa091 Parents: 0471a55 Author: Claus Ibsen <[email protected]> Authored: Wed Nov 11 20:08:02 2015 +0100 Committer: Claus Ibsen <[email protected]> Committed: Thu Nov 12 09:19:11 2015 +0100 ---------------------------------------------------------------------- .../tools/apt/AbstractAnnotationProcessor.java | 6 +- .../camel/tools/apt/CollectionStringBuffer.java | 58 --- .../camel/tools/apt/DocumentationHelper.java | 4 +- .../camel/tools/apt/EipAnnotationProcessor.java | 12 +- .../tools/apt/EndpointAnnotationProcessor.java | 498 ++----------------- .../java/org/apache/camel/tools/apt/Func1.java | 2 + .../org/apache/camel/tools/apt/IOHelper.java | 82 --- .../camel/tools/apt/JsonSchemaHelper.java | 361 -------------- .../org/apache/camel/tools/apt/Strings.java | 103 ---- .../apt/helper/CollectionStringBuffer.java | 58 +++ .../camel/tools/apt/helper/EndpointHelper.java | 127 +++++ .../apache/camel/tools/apt/helper/IOHelper.java | 82 +++ .../tools/apt/helper/JsonSchemaHelper.java | 367 ++++++++++++++ .../apache/camel/tools/apt/helper/Strings.java | 103 ++++ .../camel/tools/apt/model/ComponentModel.java | 129 +++++ .../camel/tools/apt/model/ComponentOption.java | 137 +++++ .../camel/tools/apt/model/EndpointOption.java | 137 +++++ .../camel/tools/apt/model/EndpointPath.java | 122 +++++ .../tools/apt/EndpointOptionComparatorTest.java | 61 +++ 19 files changed, 1388 insertions(+), 1061 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java index 051b5e2..9a49110 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/AbstractAnnotationProcessor.java @@ -41,9 +41,9 @@ import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.StandardLocation; -import static org.apache.camel.tools.apt.IOHelper.loadText; -import static org.apache.camel.tools.apt.Strings.canonicalClassName; -import static org.apache.camel.tools.apt.Strings.isNullOrEmpty; +import static org.apache.camel.tools.apt.helper.IOHelper.loadText; +import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName; +import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty; /** * Abstract class for Camel apt plugins. http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/CollectionStringBuffer.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CollectionStringBuffer.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CollectionStringBuffer.java deleted file mode 100644 index 21daf95..0000000 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CollectionStringBuffer.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * 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.tools.apt; - -/** - * A little helper class for converting a collection of values to a (usually comma separated) string. - */ -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; - } - -} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java index 6de021d..c3e72c5 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/DocumentationHelper.java @@ -26,7 +26,9 @@ import java.io.LineNumberReader; import java.util.List; import java.util.Map; -import static org.apache.camel.tools.apt.JsonSchemaHelper.parseJsonSchema; +import org.apache.camel.tools.apt.helper.IOHelper; + +import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.parseJsonSchema; /** * Helper to find documentation for inherited options when a component extends another. http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java index 53bc12d..bab6360 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EipAnnotationProcessor.java @@ -44,11 +44,13 @@ import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlValue; import org.apache.camel.spi.Metadata; +import org.apache.camel.tools.apt.helper.JsonSchemaHelper; +import org.apache.camel.tools.apt.helper.Strings; -import static org.apache.camel.tools.apt.JsonSchemaHelper.sanitizeDescription; -import static org.apache.camel.tools.apt.Strings.canonicalClassName; -import static org.apache.camel.tools.apt.Strings.isNullOrEmpty; -import static org.apache.camel.tools.apt.Strings.safeNull; +import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription; +import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName; +import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty; +import static org.apache.camel.tools.apt.helper.Strings.safeNull; /** * Process all camel-core's model classes (EIPs and DSL) and generate json schema documentation @@ -201,7 +203,7 @@ public class EipAnnotationProcessor extends AbstractAnnotationProcessor { String doc = entry.getDocumentation(); doc = sanitizeDescription(doc, false); buffer.append(JsonSchemaHelper.toJson(entry.getName(), entry.getKind(), entry.isRequired(), entry.getType(), entry.getDefaultValue(), doc, - entry.isDeprecated(), null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes())); + entry.isDeprecated(), null, null, entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes())); } buffer.append("\n }"); http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java index 00a35e7..c04c628 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/EndpointAnnotationProcessor.java @@ -17,6 +17,8 @@ package org.apache.camel.tools.apt; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -42,12 +44,19 @@ import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriParams; import org.apache.camel.spi.UriPath; - -import static org.apache.camel.tools.apt.JsonSchemaHelper.sanitizeDescription; -import static org.apache.camel.tools.apt.Strings.canonicalClassName; -import static org.apache.camel.tools.apt.Strings.getOrElse; -import static org.apache.camel.tools.apt.Strings.isNullOrEmpty; -import static org.apache.camel.tools.apt.Strings.safeNull; +import org.apache.camel.tools.apt.helper.EndpointHelper; +import org.apache.camel.tools.apt.helper.JsonSchemaHelper; +import org.apache.camel.tools.apt.helper.Strings; +import org.apache.camel.tools.apt.model.ComponentModel; +import org.apache.camel.tools.apt.model.ComponentOption; +import org.apache.camel.tools.apt.model.EndpointOption; +import org.apache.camel.tools.apt.model.EndpointPath; + +import static org.apache.camel.tools.apt.helper.JsonSchemaHelper.sanitizeDescription; +import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName; +import static org.apache.camel.tools.apt.helper.Strings.getOrElse; +import static org.apache.camel.tools.apt.helper.Strings.isNullOrEmpty; +import static org.apache.camel.tools.apt.helper.Strings.safeNull; /** * Processes all Camel {@link UriEndpoint}s and generate json schema and html documentation for the endpoint/component. @@ -95,7 +104,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() { @Override public Void call(PrintWriter writer) { - writeHtmlDocumentation(writer, roundEnv, classElement, uriEndpoint, aliasTitle, alias, label); + writeHtmlDocumentation(writer, roundEnv, classElement, uriEndpoint, aliasTitle, alias, extendsAlias, label); return null; } }; @@ -117,7 +126,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } protected void writeHtmlDocumentation(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, UriEndpoint uriEndpoint, - String title, String scheme, String label) { + String title, String scheme, String extendsScheme, String label) { writer.println("<html>"); writer.println("<header>"); writer.println("<title>" + title + "</title>"); @@ -135,7 +144,10 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { writer.println("</ul>"); } - showDocumentationAndFieldInjections(writer, roundEnv, classElement, ""); + // gather component information + ComponentModel componentModel = findComponentProperties(roundEnv, uriEndpoint, title, scheme, extendsScheme, label); + + writeHtmlDocumentationAndFieldInjections(writer, roundEnv, componentModel, classElement, ""); // This code is not my fault, it seems to honestly be the hacky way to find a class name in APT :) TypeMirror consumerType = null; @@ -153,7 +165,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { TypeElement consumerElement = findTypeElement(roundEnv, consumerClassName); if (consumerElement != null) { writer.println("<h2>" + scheme + " consumer" + "</h2>"); - showDocumentationAndFieldInjections(writer, roundEnv, consumerElement, consumerPrefix); + writeHtmlDocumentationAndFieldInjections(writer, roundEnv, componentModel, consumerElement, consumerPrefix); found = true; } } @@ -165,7 +177,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } protected void writeJSonSchemeDocumentation(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, UriEndpoint uriEndpoint, - String title, String scheme, final String extendsScheme, String label) { + String title, String scheme, String extendsScheme, String label) { // gather component information ComponentModel componentModel = findComponentProperties(roundEnv, uriEndpoint, title, scheme, extendsScheme, label); @@ -176,10 +188,10 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { TypeElement componentClassElement = findTypeElement(roundEnv, componentModel.getJavaType()); if (componentClassElement != null) { - findComponentClassProperties(writer, roundEnv, componentOptions, componentClassElement, ""); + findComponentClassProperties(writer, roundEnv, componentModel, componentOptions, componentClassElement, ""); } - findClassProperties(writer, roundEnv, endpointPaths, endpointOptions, classElement, ""); + findClassProperties(writer, roundEnv, componentModel, endpointPaths, endpointOptions, classElement, ""); String json = createParameterJsonSchema(componentModel, componentOptions, endpointPaths, endpointOptions); writer.println(json); @@ -235,7 +247,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } buffer.append(JsonSchemaHelper.toJson(entry.getName(), "property", required, entry.getType(), defaultValue, doc, - entry.isDeprecated(), entry.getLabel(), entry.isEnumType(), entry.getEnums(), false, null)); + entry.isDeprecated(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(), false, null)); } buffer.append("\n },"); @@ -275,11 +287,16 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } buffer.append(JsonSchemaHelper.toJson(entry.getName(), "path", required, entry.getType(), defaultValue, doc, - entry.isDeprecated(), label, entry.isEnumType(), entry.getEnums(), false, null)); + entry.isDeprecated(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(), false, null)); } + // sort the endpoint options in the standard order we prefer + List<EndpointOption> options = new ArrayList<EndpointOption>(); + options.addAll(endpointOptions); + Collections.sort(options, EndpointHelper.createGroupAndLabelComparator()); + // and then regular parameter options - for (EndpointOption entry : endpointOptions) { + for (EndpointOption entry : options) { String label = entry.getLabel(); if (label != null) { // skip options which are either consumer or producer labels but the component does not support them @@ -311,7 +328,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } buffer.append(JsonSchemaHelper.toJson(entry.getName(), "parameter", required, entry.getType(), defaultValue, - doc, entry.isDeprecated(), label, entry.isEnumType(), entry.getEnums(), false, null)); + doc, entry.isDeprecated(), entry.getGroup(), entry.getLabel(), entry.isEnumType(), entry.getEnums(), false, null)); } buffer.append("\n }"); @@ -319,7 +336,8 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { return buffer.toString(); } - protected void showDocumentationAndFieldInjections(PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, String prefix) { + protected void writeHtmlDocumentationAndFieldInjections(PrintWriter writer, RoundEnvironment roundEnv, ComponentModel componentModel, + TypeElement classElement, String prefix) { String classDoc = processingEnv.getElementUtils().getDocComment(classElement); if (!isNullOrEmpty(classDoc)) { // remove dodgy @version that we may have in class javadoc @@ -330,7 +348,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { Set<EndpointPath> endpointPaths = new LinkedHashSet<EndpointPath>(); Set<EndpointOption> endpointOptions = new LinkedHashSet<EndpointOption>(); - findClassProperties(writer, roundEnv, endpointPaths, endpointOptions, classElement, prefix); + findClassProperties(writer, roundEnv, componentModel, endpointPaths, endpointOptions, classElement, prefix); if (!endpointOptions.isEmpty() || !endpointPaths.isEmpty()) { writer.println("<table class='table'>"); @@ -442,7 +460,8 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { return model; } - protected void findComponentClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<ComponentOption> componentOptions, TypeElement classElement, String prefix) { + protected void findComponentClassProperties(PrintWriter writer, RoundEnvironment roundEnv, ComponentModel componentModel, + Set<ComponentOption> componentOptions, TypeElement classElement, String prefix) { Elements elementUtils = processingEnv.getElementUtils(); while (true) { List<ExecutableElement> methods = ElementFilter.methodsIn(classElement.getEnclosedElements()); @@ -515,8 +534,9 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } } + String group = EndpointHelper.labelAsGroupName(label, componentModel.isConsumerOnly(), componentModel.isProducerOnly()); ComponentOption option = new ComponentOption(name, fieldTypeName, required, defaultValue, defaultValueNote, - docComment.trim(), deprecated, label, isEnum, enums); + docComment.trim(), deprecated, group, label, isEnum, enums); componentOptions.add(option); } @@ -535,7 +555,9 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } } - protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, Set<EndpointPath> endpointPaths, Set<EndpointOption> endpointOptions, TypeElement classElement, String prefix) { + protected void findClassProperties(PrintWriter writer, RoundEnvironment roundEnv, ComponentModel componentModel, + Set<EndpointPath> endpointPaths, Set<EndpointOption> endpointOptions, + TypeElement classElement, String prefix) { Elements elementUtils = processingEnv.getElementUtils(); while (true) { List<VariableElement> fieldElements = ElementFilter.fieldsIn(classElement.getEnclosedElements()); @@ -598,7 +620,8 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } } - EndpointPath ep = new EndpointPath(name, fieldTypeName, required, defaultValue, docComment, deprecated, label, isEnum, enums); + String group = EndpointHelper.labelAsGroupName(label, componentModel.isConsumerOnly(), componentModel.isProducerOnly()); + EndpointPath ep = new EndpointPath(name, fieldTypeName, required, defaultValue, docComment, deprecated, group, label, isEnum, enums); endpointPaths.add(ep); } @@ -636,7 +659,7 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { if (!isNullOrEmpty(extraPrefix)) { nestedPrefix += extraPrefix; } - findClassProperties(writer, roundEnv, endpointPaths, endpointOptions, fieldTypeElement, nestedPrefix); + findClassProperties(writer, roundEnv, componentModel, endpointPaths, endpointOptions, fieldTypeElement, nestedPrefix); } else { String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, name, classElement, false); if (isNullOrEmpty(docComment)) { @@ -668,8 +691,10 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { } } + + String group = EndpointHelper.labelAsGroupName(label, componentModel.isConsumerOnly(), componentModel.isProducerOnly()); EndpointOption option = new EndpointOption(name, fieldTypeName, required, defaultValue, defaultValueNote, - docComment.trim(), deprecated, label, isEnum, enums); + docComment.trim(), deprecated, group, label, isEnum, enums); endpointOptions.add(option); } } @@ -704,427 +729,4 @@ public class EndpointAnnotationProcessor extends AbstractAnnotationProcessor { return answer; } - private static final class ComponentModel { - - private String scheme; - private String extendsScheme; - private String syntax; - private String javaType; - private String title; - private String description; - private String groupId; - private String artifactId; - private String versionId; - private String label; - private boolean consumerOnly; - private boolean producerOnly; - - private ComponentModel(String scheme) { - this.scheme = scheme; - } - - public String getScheme() { - return scheme; - } - - public String getExtendsScheme() { - return extendsScheme; - } - - public void setExtendsScheme(String extendsScheme) { - this.extendsScheme = extendsScheme; - } - - public String getSyntax() { - return syntax; - } - - public void setSyntax(String syntax) { - this.syntax = syntax; - } - - public String getJavaType() { - return javaType; - } - - public void setJavaType(String javaType) { - this.javaType = javaType; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getGroupId() { - return groupId; - } - - public void setGroupId(String groupId) { - this.groupId = groupId; - } - - public String getArtifactId() { - return artifactId; - } - - public void setArtifactId(String artifactId) { - this.artifactId = artifactId; - } - - public String getVersionId() { - return versionId; - } - - public void setVersionId(String versionId) { - this.versionId = versionId; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public boolean isConsumerOnly() { - return consumerOnly; - } - - public void setConsumerOnly(boolean consumerOnly) { - this.consumerOnly = consumerOnly; - } - - public boolean isProducerOnly() { - return producerOnly; - } - - public void setProducerOnly(boolean producerOnly) { - this.producerOnly = producerOnly; - } - } - - private static final class ComponentOption { - - private String name; - private String type; - private String required; - private String defaultValue; - private String defaultValueNote; - private String documentation; - private boolean deprecated; - private String label; - private boolean enumType; - private Set<String> enums; - - private ComponentOption(String name, String type, String required, String defaultValue, String defaultValueNote, - String documentation, boolean deprecated, String label, boolean enumType, Set<String> enums) { - this.name = name; - this.type = type; - this.required = required; - this.defaultValue = defaultValue; - this.defaultValueNote = defaultValueNote; - this.documentation = documentation; - this.deprecated = deprecated; - this.label = label; - this.enumType = enumType; - this.enums = enums; - } - - public String getName() { - return name; - } - - public String getType() { - return type; - } - - public String getRequired() { - return required; - } - - public String getDefaultValue() { - return defaultValue; - } - - public String getDocumentation() { - return documentation; - } - - public boolean isDeprecated() { - return deprecated; - } - - public String getEnumValuesAsHtml() { - CollectionStringBuffer csb = new CollectionStringBuffer("<br/>"); - if (enums != null && enums.size() > 0) { - for (String e : enums) { - csb.append(e); - } - } - return csb.toString(); - } - - public String getDocumentationWithNotes() { - StringBuilder sb = new StringBuilder(); - sb.append(documentation); - - if (!isNullOrEmpty(defaultValueNote)) { - sb.append(". Default value notice: ").append(defaultValueNote); - } - - return sb.toString(); - } - - public boolean isEnumType() { - return enumType; - } - - public Set<String> getEnums() { - return enums; - } - - public String getLabel() { - return label; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ComponentOption that = (ComponentOption) o; - - if (!name.equals(that.name)) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - - private static final class EndpointOption { - - private String name; - private String type; - private String required; - private String defaultValue; - private String defaultValueNote; - private String documentation; - private boolean deprecated; - private String label; - private boolean enumType; - private Set<String> enums; - - private EndpointOption(String name, String type, String required, String defaultValue, String defaultValueNote, - String documentation, boolean deprecated, String label, boolean enumType, Set<String> enums) { - this.name = name; - this.type = type; - this.required = required; - this.defaultValue = defaultValue; - this.defaultValueNote = defaultValueNote; - this.documentation = documentation; - this.deprecated = deprecated; - this.label = label; - this.enumType = enumType; - this.enums = enums; - } - - public String getName() { - return name; - } - - public String getType() { - return type; - } - - public String getRequired() { - return required; - } - - public String getDefaultValue() { - return defaultValue; - } - - public String getDocumentation() { - return documentation; - } - - public boolean isDeprecated() { - return deprecated; - } - - public String getEnumValuesAsHtml() { - CollectionStringBuffer csb = new CollectionStringBuffer("<br/>"); - if (enums != null && enums.size() > 0) { - for (String e : enums) { - csb.append(e); - } - } - return csb.toString(); - } - - public String getDocumentationWithNotes() { - StringBuilder sb = new StringBuilder(); - sb.append(documentation); - - if (!isNullOrEmpty(defaultValueNote)) { - sb.append(". Default value notice: ").append(defaultValueNote); - } - - return sb.toString(); - } - - public boolean isEnumType() { - return enumType; - } - - public Set<String> getEnums() { - return enums; - } - - public String getLabel() { - return label; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - EndpointOption that = (EndpointOption) o; - - if (!name.equals(that.name)) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - - private static final class EndpointPath { - - private String name; - private String type; - private String required; - private String defaultValue; - private String documentation; - private boolean deprecated; - private String label; - private boolean enumType; - private Set<String> enums; - - private EndpointPath(String name, String type, String required, String defaultValue, String documentation, boolean deprecated, - String label, boolean enumType, Set<String> enums) { - this.name = name; - this.type = type; - this.required = required; - this.defaultValue = defaultValue; - this.documentation = documentation; - this.deprecated = deprecated; - this.label = label; - this.enumType = enumType; - this.enums = enums; - } - - public String getName() { - return name; - } - - public String getType() { - return type; - } - - public String getRequired() { - return required; - } - - public String getDefaultValue() { - return defaultValue; - } - - public String getDocumentation() { - return documentation; - } - - public boolean isDeprecated() { - return deprecated; - } - - public String getEnumValuesAsHtml() { - CollectionStringBuffer csb = new CollectionStringBuffer("<br/>"); - if (enums != null && enums.size() > 0) { - for (String e : enums) { - csb.append(e); - } - } - return csb.toString(); - } - - public boolean isEnumType() { - return enumType; - } - - public Set<String> getEnums() { - return enums; - } - - public String getLabel() { - return label; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - EndpointPath that = (EndpointPath) o; - - if (!name.equals(that.name)) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - } - } http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/Func1.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/Func1.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/Func1.java index 59830ae..6c6ab8d 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/Func1.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/Func1.java @@ -20,5 +20,7 @@ package org.apache.camel.tools.apt; * Represents a function with 1 argument */ interface Func1<T1, R> { + R call(T1 t1); + } http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/IOHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/IOHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/IOHelper.java deleted file mode 100644 index d4c1717..0000000 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/IOHelper.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * 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.tools.apt; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -final class IOHelper { - - private IOHelper() { - } - - /** - * 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, boolean skipCommentOrEmptyLines) throws IOException { - StringBuilder builder = new StringBuilder(); - InputStreamReader isr = new InputStreamReader(in); - try { - BufferedReader reader = new BufferedReader(isr); - while (true) { - String line = reader.readLine(); - if (line != null) { - - boolean empty = Strings.isNullOrEmpty(line); - boolean comment = line.trim().startsWith("#"); - if (skipCommentOrEmptyLines && (empty || comment)) { - continue; - } - - builder.append(line); - builder.append("\n"); - } else { - break; - } - } - return builder.toString(); - } finally { - close(isr, in); - } - } - - /** - * Closes the given resources if they are available. - * - * @param closeables the objects to close - */ - public static void close(Closeable... closeables) { - for (Closeable closeable : closeables) { - try { - closeable.close(); - } catch (IOException e) { - // ignore - } - } - } - - - -} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java deleted file mode 100644 index 0df1eb1..0000000 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/JsonSchemaHelper.java +++ /dev/null @@ -1,361 +0,0 @@ -/** - * 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.tools.apt; - -import java.net.URI; -import java.net.URL; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A helper class for <a href="http://json-schema.org/">JSON schema</a>. - */ -final class JsonSchemaHelper { - - private static final String VALID_CHARS = ".-='/\\!&():;"; - private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]"); - private static final String QUOT = """; - - private JsonSchemaHelper() { - } - - public static String toJson(String name, String kind, Boolean required, String type, String defaultValue, String description, - Boolean deprecated, String label, boolean enumType, Set<String> enums, boolean oneOfType, Set<String> oneOffTypes) { - String typeName = JsonSchemaHelper.getType(type, enumType); - - StringBuilder sb = new StringBuilder(); - sb.append(Strings.doubleQuote(name)); - sb.append(": { \"kind\": "); - sb.append(Strings.doubleQuote(kind)); - - // we want label early so its easier to spot - if (!Strings.isNullOrEmpty(label)) { - sb.append(", \"label\": "); - sb.append(Strings.doubleQuote(label)); - } - - if (required != null) { - sb.append(", \"required\": "); - sb.append(Strings.doubleQuote(required.toString())); - } - - sb.append(", \"type\": "); - if ("enum".equals(typeName)) { - sb.append(Strings.doubleQuote("string")); - sb.append(", \"javaType\": \"" + type + "\""); - CollectionStringBuffer enumValues = new CollectionStringBuffer(); - for (Object value : enums) { - enumValues.append(Strings.doubleQuote(value.toString())); - } - sb.append(", \"enum\": [ "); - sb.append(enumValues.toString()); - sb.append(" ]"); - } else if (oneOfType) { - sb.append(Strings.doubleQuote(typeName)); - sb.append(", \"javaType\": \"" + type + "\""); - CollectionStringBuffer oneOfValues = new CollectionStringBuffer(); - for (Object value : oneOffTypes) { - oneOfValues.append(Strings.doubleQuote(value.toString())); - } - sb.append(", \"oneOf\": [ "); - sb.append(oneOfValues.toString()); - sb.append(" ]"); - } else if ("array".equals(typeName)) { - sb.append(Strings.doubleQuote("array")); - sb.append(", \"javaType\": \"" + type + "\""); - } else { - sb.append(Strings.doubleQuote(typeName)); - sb.append(", \"javaType\": \"" + type + "\""); - } - - if (deprecated != null) { - sb.append(", \"deprecated\": "); - sb.append(Strings.doubleQuote(deprecated.toString())); - } - - if (!Strings.isNullOrEmpty(defaultValue)) { - sb.append(", \"defaultValue\": "); - String text = safeDefaultValue(defaultValue); - sb.append(Strings.doubleQuote(text)); - } - - if (!Strings.isNullOrEmpty(description)) { - sb.append(", \"description\": "); - String text = sanitizeDescription(description, false); - sb.append(Strings.doubleQuote(text)); - } - - sb.append(" }"); - return sb.toString(); - } - - /** - * Gets the JSon schema type. - * - * @param type the java type - * @return the json schema type, is never null, but returns <tt>object</tt> as the generic type - */ - public static String getType(String type, boolean enumType) { - if (enumType) { - return "enum"; - } else if (type == null) { - // return generic type for unknown type - return "object"; - } else if (type.equals(URI.class.getName()) || type.equals(URL.class.getName())) { - return "string"; - } else if (type.startsWith("java.lang.Class")) { - return "string"; - } else if (type.startsWith("java.util.List") || type.startsWith("java.util.Collection")) { - return "array"; - } - - String primitive = getPrimitiveType(type); - if (primitive != null) { - return primitive; - } - - return "object"; - } - - /** - * Gets the JSon schema primitive type. - * - * @param name the java type - * @return the json schema primitive type, or <tt>null</tt> if not a primitive - */ - public static String getPrimitiveType(String name) { - - // special for byte[] or Object[] as its common to use - if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) { - return "string"; - } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) { - return "array"; - } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) { - return "array"; - } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) { - return "array"; - // and these is common as well - } else if ("java.lang.String".equals(name) || "String".equals(name)) { - return "string"; - } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name)) { - return "boolean"; - } else if ("boolean".equals(name)) { - return "boolean"; - } else if ("java.lang.Integer".equals(name) || "Integer".equals(name)) { - return "integer"; - } else if ("int".equals(name)) { - return "integer"; - } else if ("java.lang.Long".equals(name) || "Long".equals(name)) { - return "integer"; - } else if ("long".equals(name)) { - return "integer"; - } else if ("java.lang.Short".equals(name) || "Short".equals(name)) { - return "integer"; - } else if ("short".equals(name)) { - return "integer"; - } else if ("java.lang.Byte".equals(name) || "Byte".equals(name)) { - return "integer"; - } else if ("byte".equals(name)) { - return "integer"; - } else if ("java.lang.Float".equals(name) || "Float".equals(name)) { - return "number"; - } else if ("float".equals(name)) { - return "number"; - } else if ("java.lang.Double".equals(name) || "Double".equals(name)) { - return "number"; - } else if ("double".equals(name)) { - return "number"; - } - - return null; - } - - /** - * Sanitizes the javadoc to removed invalid characters so it can be used as json description - * - * @param javadoc the javadoc - * @return the text that is valid as json - */ - public static String sanitizeDescription(String javadoc, boolean summary) { - if (Strings.isNullOrEmpty(javadoc)) { - return null; - } - - // lets just use what java accepts as identifiers - StringBuilder sb = new StringBuilder(); - - // split into lines - String[] lines = javadoc.split("\n"); - - boolean first = true; - for (String line : lines) { - line = line.trim(); - - // terminate if we reach @param, @return or @deprecated as we only want the javadoc summary - if (line.startsWith("@param") || line.startsWith("@return") || line.startsWith("@deprecated")) { - break; - } - - // skip lines that are javadoc references - if (line.startsWith("@")) { - continue; - } - - // remove all HTML tags - line = line.replaceAll("<.*?>", ""); - - // remove all inlined javadoc links, eg such as {@link org.apache.camel.spi.Registry} - line = line.replaceAll("\\{\\@\\w+\\s([\\w.]+)\\}", "$1"); - - // we are starting from a new line, so add a whitespace - if (!first) { - sb.append(' '); - } - - // create a new line - StringBuilder cb = new StringBuilder(); - for (char c : line.toCharArray()) { - if (Character.isJavaIdentifierPart(c) || VALID_CHARS.indexOf(c) != -1) { - cb.append(c); - } else if (Character.isWhitespace(c)) { - // always use space as whitespace, also for line feeds etc - cb.append(' '); - } - } - - // append data - String s = cb.toString().trim(); - sb.append(s); - - boolean empty = Strings.isNullOrEmpty(s); - boolean endWithDot = s.endsWith("."); - boolean haveText = sb.length() > 0; - - if (haveText && summary && (empty || endWithDot)) { - // if we only want a summary, then skip at first empty line we encounter, or if the sentence ends with a dot - break; - } - - first = false; - } - - // remove double whitespaces, and trim - String s = sb.toString(); - s = s.replaceAll("\\s+", " "); - return s.trim(); - } - - /** - * 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; - } - - /** - * The default value may need to be escaped to be safe for json - */ - private static String safeDefaultValue(String value) { - if ("\"".equals(value)) { - return "\\\""; - } else if ("\\".equals(value)) { - return "\\\\"; - } else { - return value; - } - } - -} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/Strings.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/Strings.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/Strings.java deleted file mode 100644 index 3e0747b..0000000 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/Strings.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * 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.tools.apt; - -/** - * Some String helper methods - */ -final class Strings { - - private Strings() { - //Helper class - } - - /** - * Returns true if the given text is null or empty string or has <tt>null</tt> as the value - */ - public static boolean isNullOrEmpty(String text) { - return text == null || text.length() == 0 || "null".equals(text); - } - - public static String safeNull(String text) { - if (isNullOrEmpty(text)) { - return ""; - } else { - return text; - } - } - - /** - * Returns the value or the defaultValue if it is null - */ - public static String getOrElse(String text, String defaultValue) { - return (text != null) ? text : defaultValue; - } - - /** - * Returns the string after the given token - * - * @param text the text - * @param after the token - * @return the text after the token, or <tt>null</tt> if text does not contain the token - */ - public static String after(String text, String after) { - if (!text.contains(after)) { - return null; - } - return text.substring(text.indexOf(after) + after.length()); - } - - /** - * Returns the canonical class name by removing any generic type information. - */ - public static String canonicalClassName(String className) { - // remove generics - int pos = className.indexOf('<'); - if (pos != -1) { - return className.substring(0, pos); - } else { - return className; - } - } - - /** - * Returns the text wrapped double quotes - */ - public static String doubleQuote(String text) { - return quote(text, "\""); - } - - /** - * Returns the text wrapped single quotes - */ - public static String singleQuote(String text) { - return quote(text, "'"); - } - - /** - * Wraps the text in the given quote text - * - * @param text the text to wrap in quotes - * @param quote the quote text added to the prefix and postfix of the text - * - * @return the text wrapped in the given quotes - */ - public static String quote(String text, String quote) { - return quote + text + quote; - } - -} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/CollectionStringBuffer.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/CollectionStringBuffer.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/CollectionStringBuffer.java new file mode 100644 index 0000000..ed89ad8 --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/CollectionStringBuffer.java @@ -0,0 +1,58 @@ +/** + * 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.tools.apt.helper; + +/** + * A little helper class for converting a collection of values to a (usually comma separated) string. + */ +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; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java new file mode 100644 index 0000000..b9c6eb6 --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/EndpointHelper.java @@ -0,0 +1,127 @@ +/** + * 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.tools.apt.helper; + +import java.util.Comparator; + +import org.apache.camel.tools.apt.model.EndpointOption; + +public final class EndpointHelper { + + private EndpointHelper() { + } + + /** + * Returns the group name from the given label. + * <p/> + * The group name is a single name deducted from the label. The label can contain multiple names separated by comma. + * The group is the best guess as a group of those labels, so similar labels can be combined into the same group. + * + * @param label the label + * @param consumerOnly whether the component is consumer only + * @param producerOnly whether the component is producer only + * @return the group name + */ + public static String labelAsGroupName(String label, boolean consumerOnly, boolean producerOnly) { + // if there is no label then use common as fallback + String answer = "common"; + if (consumerOnly) { + answer = "consumer"; + } else if (producerOnly) { + answer = "producer"; + } + + String value = label; + if (!Strings.isNullOrEmpty(value)) { + + // we want to put advanced into own group, so look for a label that has advanced as prefix x,advanced => x (advanced) + value = value.replaceFirst("(\\w),(advanced)", "$1 (advanced)"); + + String[] array = value.split(","); + // grab last label which is the most specific label we want to use for the tab + answer = array[array.length - 1]; + // if we are in consumer/producer only mode, then enrich the advanced label to indicate its advanced of those + if (answer.equals("advanced") && consumerOnly) { + answer = "consumer (advanced)"; + } else if (answer.equals("advanced") && producerOnly) { + answer = "producer (advanced)"; + } + } + + return answer; + } + + /** + * A comparator to sort the endpoint/component options according to group and label. + */ + public static EndpointOptionGroupAndLabelComparator createGroupAndLabelComparator() { + return new EndpointOptionGroupAndLabelComparator(); + } + + private static final class EndpointOptionGroupAndLabelComparator implements Comparator<EndpointOption> { + + @Override + public int compare(EndpointOption o1, EndpointOption o2) { + String name1 = o1.getName(); + String name2 = o2.getName(); + String label1 = o1.getLabel() != null ? o1.getLabel() : "common"; + String label2 = o2.getLabel() != null ? o2.getLabel() : "common"; + String group1 = o1.getGroup(); + String group2 = o2.getGroup(); + + // if same label or group then sort by name + if (label1.equalsIgnoreCase(label2) || group1.equalsIgnoreCase(group2)) { + return name1.compareToIgnoreCase(name2); + } + + int score1 = groupScore(group1); + int score2 = groupScore(group2); + + if (score1 < score2) { + return -1; + } else if (score2 < score1) { + return 1; + } else { + // compare by full label and name + int score = label1.compareToIgnoreCase(label2); + if (score == 0) { + score = name1.compareToIgnoreCase(name2); + } + return score; + } + } + } + + private static int groupScore(String group) { + if ("common".equals(group)) { + return 1; + } else if ("common (advanced)".equals(group)) { + return 2; + } else if ("consumer".equals(group)) { + return 3; + } else if ("consumer (advanced)".equals(group)) { + return 4; + } else if ("producer".equals(group)) { + return 5; + } else if ("producer (advanced)".equals(group)) { + return 6; + } else { + return 9; + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java new file mode 100644 index 0000000..32c1518 --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/IOHelper.java @@ -0,0 +1,82 @@ +/** + * 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.tools.apt.helper; + +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public final class IOHelper { + + private IOHelper() { + } + + /** + * 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, boolean skipCommentOrEmptyLines) throws IOException { + StringBuilder builder = new StringBuilder(); + InputStreamReader isr = new InputStreamReader(in); + try { + BufferedReader reader = new BufferedReader(isr); + while (true) { + String line = reader.readLine(); + if (line != null) { + + boolean empty = Strings.isNullOrEmpty(line); + boolean comment = line.trim().startsWith("#"); + if (skipCommentOrEmptyLines && (empty || comment)) { + continue; + } + + builder.append(line); + builder.append("\n"); + } else { + break; + } + } + return builder.toString(); + } finally { + close(isr, in); + } + } + + /** + * Closes the given resources if they are available. + * + * @param closeables the objects to close + */ + public static void close(Closeable... closeables) { + for (Closeable closeable : closeables) { + try { + closeable.close(); + } catch (IOException e) { + // ignore + } + } + } + + + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java new file mode 100644 index 0000000..73f8a3b --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/JsonSchemaHelper.java @@ -0,0 +1,367 @@ +/** + * 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.tools.apt.helper; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A helper class for <a href="http://json-schema.org/">JSON schema</a>. + */ +public final class JsonSchemaHelper { + + private static final String VALID_CHARS = ".-='/\\!&():;"; + private static final Pattern PATTERN = Pattern.compile("\"(.+?)\"|\\[(.+)\\]"); + private static final String QUOT = """; + + private JsonSchemaHelper() { + } + + public static String toJson(String name, String kind, Boolean required, String type, String defaultValue, String description, + Boolean deprecated, String group, String label, boolean enumType, Set<String> enums, boolean oneOfType, Set<String> oneOffTypes) { + String typeName = JsonSchemaHelper.getType(type, enumType); + + StringBuilder sb = new StringBuilder(); + sb.append(Strings.doubleQuote(name)); + sb.append(": { \"kind\": "); + sb.append(Strings.doubleQuote(kind)); + + // we want group early so its easier to spot + if (!Strings.isNullOrEmpty(group)) { + sb.append(", \"group\": "); + sb.append(Strings.doubleQuote(group)); + } + + // we want label early so its easier to spot + if (!Strings.isNullOrEmpty(label)) { + sb.append(", \"label\": "); + sb.append(Strings.doubleQuote(label)); + } + + if (required != null) { + sb.append(", \"required\": "); + sb.append(Strings.doubleQuote(required.toString())); + } + + sb.append(", \"type\": "); + if ("enum".equals(typeName)) { + sb.append(Strings.doubleQuote("string")); + sb.append(", \"javaType\": \"" + type + "\""); + CollectionStringBuffer enumValues = new CollectionStringBuffer(); + for (Object value : enums) { + enumValues.append(Strings.doubleQuote(value.toString())); + } + sb.append(", \"enum\": [ "); + sb.append(enumValues.toString()); + sb.append(" ]"); + } else if (oneOfType) { + sb.append(Strings.doubleQuote(typeName)); + sb.append(", \"javaType\": \"" + type + "\""); + CollectionStringBuffer oneOfValues = new CollectionStringBuffer(); + for (Object value : oneOffTypes) { + oneOfValues.append(Strings.doubleQuote(value.toString())); + } + sb.append(", \"oneOf\": [ "); + sb.append(oneOfValues.toString()); + sb.append(" ]"); + } else if ("array".equals(typeName)) { + sb.append(Strings.doubleQuote("array")); + sb.append(", \"javaType\": \"" + type + "\""); + } else { + sb.append(Strings.doubleQuote(typeName)); + sb.append(", \"javaType\": \"" + type + "\""); + } + + if (deprecated != null) { + sb.append(", \"deprecated\": "); + sb.append(Strings.doubleQuote(deprecated.toString())); + } + + if (!Strings.isNullOrEmpty(defaultValue)) { + sb.append(", \"defaultValue\": "); + String text = safeDefaultValue(defaultValue); + sb.append(Strings.doubleQuote(text)); + } + + if (!Strings.isNullOrEmpty(description)) { + sb.append(", \"description\": "); + String text = sanitizeDescription(description, false); + sb.append(Strings.doubleQuote(text)); + } + + sb.append(" }"); + return sb.toString(); + } + + /** + * Gets the JSon schema type. + * + * @param type the java type + * @return the json schema type, is never null, but returns <tt>object</tt> as the generic type + */ + public static String getType(String type, boolean enumType) { + if (enumType) { + return "enum"; + } else if (type == null) { + // return generic type for unknown type + return "object"; + } else if (type.equals(URI.class.getName()) || type.equals(URL.class.getName())) { + return "string"; + } else if (type.startsWith("java.lang.Class")) { + return "string"; + } else if (type.startsWith("java.util.List") || type.startsWith("java.util.Collection")) { + return "array"; + } + + String primitive = getPrimitiveType(type); + if (primitive != null) { + return primitive; + } + + return "object"; + } + + /** + * Gets the JSon schema primitive type. + * + * @param name the java type + * @return the json schema primitive type, or <tt>null</tt> if not a primitive + */ + public static String getPrimitiveType(String name) { + + // special for byte[] or Object[] as its common to use + if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) { + return "string"; + } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) { + return "array"; + } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) { + return "array"; + } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) { + return "array"; + // and these is common as well + } else if ("java.lang.String".equals(name) || "String".equals(name)) { + return "string"; + } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name)) { + return "boolean"; + } else if ("boolean".equals(name)) { + return "boolean"; + } else if ("java.lang.Integer".equals(name) || "Integer".equals(name)) { + return "integer"; + } else if ("int".equals(name)) { + return "integer"; + } else if ("java.lang.Long".equals(name) || "Long".equals(name)) { + return "integer"; + } else if ("long".equals(name)) { + return "integer"; + } else if ("java.lang.Short".equals(name) || "Short".equals(name)) { + return "integer"; + } else if ("short".equals(name)) { + return "integer"; + } else if ("java.lang.Byte".equals(name) || "Byte".equals(name)) { + return "integer"; + } else if ("byte".equals(name)) { + return "integer"; + } else if ("java.lang.Float".equals(name) || "Float".equals(name)) { + return "number"; + } else if ("float".equals(name)) { + return "number"; + } else if ("java.lang.Double".equals(name) || "Double".equals(name)) { + return "number"; + } else if ("double".equals(name)) { + return "number"; + } + + return null; + } + + /** + * Sanitizes the javadoc to removed invalid characters so it can be used as json description + * + * @param javadoc the javadoc + * @return the text that is valid as json + */ + public static String sanitizeDescription(String javadoc, boolean summary) { + if (Strings.isNullOrEmpty(javadoc)) { + return null; + } + + // lets just use what java accepts as identifiers + StringBuilder sb = new StringBuilder(); + + // split into lines + String[] lines = javadoc.split("\n"); + + boolean first = true; + for (String line : lines) { + line = line.trim(); + + // terminate if we reach @param, @return or @deprecated as we only want the javadoc summary + if (line.startsWith("@param") || line.startsWith("@return") || line.startsWith("@deprecated")) { + break; + } + + // skip lines that are javadoc references + if (line.startsWith("@")) { + continue; + } + + // remove all HTML tags + line = line.replaceAll("<.*?>", ""); + + // remove all inlined javadoc links, eg such as {@link org.apache.camel.spi.Registry} + line = line.replaceAll("\\{\\@\\w+\\s([\\w.]+)\\}", "$1"); + + // we are starting from a new line, so add a whitespace + if (!first) { + sb.append(' '); + } + + // create a new line + StringBuilder cb = new StringBuilder(); + for (char c : line.toCharArray()) { + if (Character.isJavaIdentifierPart(c) || VALID_CHARS.indexOf(c) != -1) { + cb.append(c); + } else if (Character.isWhitespace(c)) { + // always use space as whitespace, also for line feeds etc + cb.append(' '); + } + } + + // append data + String s = cb.toString().trim(); + sb.append(s); + + boolean empty = Strings.isNullOrEmpty(s); + boolean endWithDot = s.endsWith("."); + boolean haveText = sb.length() > 0; + + if (haveText && summary && (empty || endWithDot)) { + // if we only want a summary, then skip at first empty line we encounter, or if the sentence ends with a dot + break; + } + + first = false; + } + + // remove double whitespaces, and trim + String s = sb.toString(); + s = s.replaceAll("\\s+", " "); + return s.trim(); + } + + /** + * 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; + } + + /** + * The default value may need to be escaped to be safe for json + */ + private static String safeDefaultValue(String value) { + if ("\"".equals(value)) { + return "\\\""; + } else if ("\\".equals(value)) { + return "\\\\"; + } else { + return value; + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java new file mode 100644 index 0000000..30b826f --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/helper/Strings.java @@ -0,0 +1,103 @@ +/** + * 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.tools.apt.helper; + +/** + * Some String helper methods + */ +public final class Strings { + + private Strings() { + //Helper class + } + + /** + * Returns true if the given text is null or empty string or has <tt>null</tt> as the value + */ + public static boolean isNullOrEmpty(String text) { + return text == null || text.length() == 0 || "null".equals(text); + } + + public static String safeNull(String text) { + if (isNullOrEmpty(text)) { + return ""; + } else { + return text; + } + } + + /** + * Returns the value or the defaultValue if it is null + */ + public static String getOrElse(String text, String defaultValue) { + return (text != null) ? text : defaultValue; + } + + /** + * Returns the string after the given token + * + * @param text the text + * @param after the token + * @return the text after the token, or <tt>null</tt> if text does not contain the token + */ + public static String after(String text, String after) { + if (!text.contains(after)) { + return null; + } + return text.substring(text.indexOf(after) + after.length()); + } + + /** + * Returns the canonical class name by removing any generic type information. + */ + public static String canonicalClassName(String className) { + // remove generics + int pos = className.indexOf('<'); + if (pos != -1) { + return className.substring(0, pos); + } else { + return className; + } + } + + /** + * Returns the text wrapped double quotes + */ + public static String doubleQuote(String text) { + return quote(text, "\""); + } + + /** + * Returns the text wrapped single quotes + */ + public static String singleQuote(String text) { + return quote(text, "'"); + } + + /** + * Wraps the text in the given quote text + * + * @param text the text to wrap in quotes + * @param quote the quote text added to the prefix and postfix of the text + * + * @return the text wrapped in the given quotes + */ + public static String quote(String text, String quote) { + return quote + text + quote; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/c850a6e0/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentModel.java ---------------------------------------------------------------------- diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentModel.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentModel.java new file mode 100644 index 0000000..56810ec --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/model/ComponentModel.java @@ -0,0 +1,129 @@ +/** + * 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.tools.apt.model; + +public final class ComponentModel { + + private String scheme; + private String extendsScheme; + private String syntax; + private String javaType; + private String title; + private String description; + private String groupId; + private String artifactId; + private String versionId; + private String label; + private boolean consumerOnly; + private boolean producerOnly; + + public ComponentModel(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return scheme; + } + + public String getExtendsScheme() { + return extendsScheme; + } + + public void setExtendsScheme(String extendsScheme) { + this.extendsScheme = extendsScheme; + } + + public String getSyntax() { + return syntax; + } + + public void setSyntax(String syntax) { + this.syntax = syntax; + } + + public String getJavaType() { + return javaType; + } + + public void setJavaType(String javaType) { + this.javaType = javaType; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getGroupId() { + return groupId; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public void setArtifactId(String artifactId) { + this.artifactId = artifactId; + } + + public String getVersionId() { + return versionId; + } + + public void setVersionId(String versionId) { + this.versionId = versionId; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public boolean isConsumerOnly() { + return consumerOnly; + } + + public void setConsumerOnly(boolean consumerOnly) { + this.consumerOnly = consumerOnly; + } + + public boolean isProducerOnly() { + return producerOnly; + } + + public void setProducerOnly(boolean producerOnly) { + this.producerOnly = producerOnly; + } +}
