http://git-wip-us.apache.org/repos/asf/camel/blob/8a18e284/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
----------------------------------------------------------------------
diff --git 
a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
new file mode 100644
index 0000000..be2783f
--- /dev/null
+++ 
b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessor.java
@@ -0,0 +1,1127 @@
+/**
+ * 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.PrintWriter;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+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.AnnotationProcessorHelper.findJavaDoc;
+import static 
org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElement;
+import static 
org.apache.camel.tools.apt.AnnotationProcessorHelper.findTypeElementChildren;
+import static 
org.apache.camel.tools.apt.AnnotationProcessorHelper.hasSuperClass;
+import static org.apache.camel.tools.apt.AnnotationProcessorHelper.processFile;
+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
+ */
+public class CoreEipAnnotationProcessor {
+
+    // special when using expression/predicates in the model
+    private static final String ONE_OF_TYPE_NAME = 
"org.apache.camel.model.ExpressionSubElementDefinition";
+    private static final String[] ONE_OF_LANGUAGES = new String[]{
+        "org.apache.camel.model.language.ExpressionDefinition",
+        "org.apache.camel.model.language.NamespaceAwareExpression"
+    };
+    // special for inputs (these classes have sub classes, so we use this to 
find all classes)
+    private static final String[] ONE_OF_INPUTS = new String[]{
+        "org.apache.camel.model.ProcessorDefinition",
+        "org.apache.camel.model.VerbDefinition"
+    };
+    // special for outputs (these classes have sub classes, so we use this to 
find all classes)
+    private static final String[] ONE_OF_OUTPUTS = new String[]{
+        "org.apache.camel.model.ProcessorDefinition",
+        "org.apache.camel.model.NoOutputDefinition",
+        "org.apache.camel.model.OutputDefinition",
+        "org.apache.camel.model.ExpressionNode",
+        "org.apache.camel.model.NoOutputExpressionNode",
+        "org.apache.camel.model.SendDefinition",
+        "org.apache.camel.model.InterceptDefinition",
+        "org.apache.camel.model.WhenDefinition",
+        "org.apache.camel.model.ToDynamicDefinition"
+    };
+    // special for verbs (these classes have sub classes, so we use this to 
find all classes)
+    private static final String[] ONE_OF_VERBS = new String[]{
+        "org.apache.camel.model.rest.VerbDefinition"
+    };
+
+    private boolean skipUnwanted = true;
+
+    protected void processModelClass(final ProcessingEnvironment 
processingEnv, final RoundEnvironment roundEnv, final TypeElement classElement) 
{
+        final String javaTypeName = 
canonicalClassName(classElement.getQualifiedName().toString());
+        String packageName = javaTypeName.substring(0, 
javaTypeName.lastIndexOf("."));
+
+        // skip abstract classes
+        if (classElement.getModifiers().contains(Modifier.ABSTRACT)) {
+            return;
+        }
+
+        // skip unwanted classes which are "abstract" holders
+        if (skipUnwanted) {
+            if 
(classElement.getQualifiedName().toString().equals(ONE_OF_TYPE_NAME)) {
+                return;
+            }
+        }
+
+        final XmlRootElement rootElement = 
classElement.getAnnotation(XmlRootElement.class);
+        if (rootElement == null) {
+            return;
+        }
+
+        String aName = rootElement.name();
+        if (isNullOrEmpty(aName) || "##default".equals(aName)) {
+            XmlType typeElement = classElement.getAnnotation(XmlType.class);
+            aName = typeElement.name();
+        }
+        final String name = aName;
+
+        // lets use the xsd name as the file name
+        String fileName;
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            fileName = classElement.getSimpleName().toString() + ".json";
+        } else {
+            fileName = name + ".json";
+        }
+
+        // write json schema
+        Func1<PrintWriter, Void> handler = new Func1<PrintWriter, Void>() {
+            @Override
+            public Void call(PrintWriter writer) {
+                writeJSonSchemeDocumentation(processingEnv, writer, roundEnv, 
classElement, rootElement, javaTypeName, name);
+                return null;
+            }
+        };
+        processFile(processingEnv, packageName, fileName, handler);
+    }
+
+    protected void writeJSonSchemeDocumentation(ProcessingEnvironment 
processingEnv, PrintWriter writer, RoundEnvironment roundEnv,
+                                                TypeElement classElement, 
XmlRootElement rootElement,
+                                                String javaTypeName, String 
modelName) {
+        // gather eip information
+        EipModel eipModel = findEipModelProperties(processingEnv, roundEnv, 
classElement, javaTypeName, modelName);
+
+        // get endpoint information which is divided into paths and options 
(though there should really only be one path)
+        Set<EipOption> eipOptions = new TreeSet<EipOption>(new 
EipOptionComparator(eipModel));
+        findClassProperties(processingEnv, writer, roundEnv, eipOptions, 
classElement, classElement, "", modelName);
+
+        // after we have found all the options then figure out if the model 
accepts input/output
+        eipModel.setInput(hasInput(processingEnv, roundEnv, classElement));
+        eipModel.setOutput(hasOutput(eipModel, eipOptions));
+
+        String json = createParameterJsonSchema(eipModel, eipOptions);
+        writer.println(json);
+    }
+
+    public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> 
options) {
+        StringBuilder buffer = new StringBuilder("{");
+        // eip model
+        buffer.append("\n \"model\": {");
+        buffer.append("\n    \"kind\": \"").append("model").append("\",");
+        buffer.append("\n    \"name\": 
\"").append(eipModel.getName()).append("\",");
+        if (eipModel.getTitle() != null) {
+            buffer.append("\n    \"title\": 
\"").append(eipModel.getTitle()).append("\",");
+        } else {
+            // fallback and use name as title
+            buffer.append("\n    \"title\": 
\"").append(asTitle(eipModel.getName())).append("\",");
+        }
+        buffer.append("\n    \"description\": 
\"").append(safeNull(eipModel.getDescription())).append("\",");
+        buffer.append("\n    \"javaType\": 
\"").append(eipModel.getJavaType()).append("\",");
+        buffer.append("\n    \"label\": 
\"").append(safeNull(eipModel.getLabel())).append("\",");
+        buffer.append("\n    \"input\": 
\"").append(eipModel.getInput()).append("\",");
+        buffer.append("\n    \"output\": 
\"").append(eipModel.getOutput()).append("\"");
+        buffer.append("\n  },");
+
+        buffer.append("\n  \"properties\": {");
+        boolean first = true;
+        for (EipOption entry : options) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(",");
+            }
+            buffer.append("\n    ");
+            // as its json we need to sanitize the docs
+            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(), false, null, null, 
entry.isEnumType(), entry.getEnums(), entry.isOneOf(), entry.getOneOfTypes(), 
null, null, false));
+        }
+        buffer.append("\n  }");
+
+        buffer.append("\n}\n");
+        return buffer.toString();
+    }
+
+    protected EipModel findEipModelProperties(ProcessingEnvironment 
processingEnv, RoundEnvironment roundEnv, TypeElement classElement, String 
javaTypeName, String name) {
+        EipModel model = new EipModel();
+        model.setJavaType(javaTypeName);
+        model.setName(name);
+
+        Metadata metadata = classElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.label())) {
+                model.setLabel(metadata.label());
+            }
+            if (!Strings.isNullOrEmpty(metadata.title())) {
+                model.setTitle(metadata.title());
+            }
+        }
+
+        // favor to use class javadoc of component as description
+        if (model.getJavaType() != null) {
+            Elements elementUtils = processingEnv.getElementUtils();
+            TypeElement typeElement = findTypeElement(processingEnv, roundEnv, 
model.getJavaType());
+            if (typeElement != null) {
+                String doc = elementUtils.getDocComment(typeElement);
+                if (doc != null) {
+                    // need to sanitize the description first (we only want a 
summary)
+                    doc = sanitizeDescription(doc, true);
+                    // the javadoc may actually be empty, so only change the 
doc if we got something
+                    if (!Strings.isNullOrEmpty(doc)) {
+                        model.setDescription(doc);
+                    }
+                }
+            }
+        }
+
+        return model;
+    }
+
+    protected void findClassProperties(ProcessingEnvironment processingEnv, 
PrintWriter writer, RoundEnvironment roundEnv, Set<EipOption> eipOptions,
+                                       TypeElement originalClassType, 
TypeElement classElement, String prefix, String modelName) {
+        while (true) {
+            List<VariableElement> fieldElements = 
ElementFilter.fieldsIn(classElement.getEnclosedElements());
+            for (VariableElement fieldElement : fieldElements) {
+
+                String fieldName = fieldElement.getSimpleName().toString();
+
+                XmlAttribute attribute = 
fieldElement.getAnnotation(XmlAttribute.class);
+                if (attribute != null) {
+                    boolean skip = processAttribute(processingEnv, roundEnv, 
originalClassType, classElement, fieldElement, fieldName, attribute, 
eipOptions, prefix, modelName);
+                    if (skip) {
+                        continue;
+                    }
+                }
+
+                XmlValue value = fieldElement.getAnnotation(XmlValue.class);
+                if (value != null) {
+                    processValue(processingEnv, roundEnv, originalClassType, 
classElement, fieldElement, fieldName, value, eipOptions, prefix, modelName);
+                }
+
+                XmlElements elements = 
fieldElement.getAnnotation(XmlElements.class);
+                if (elements != null) {
+                    processElements(processingEnv, roundEnv, classElement, 
elements, fieldElement, eipOptions, prefix);
+                }
+
+                XmlElement element = 
fieldElement.getAnnotation(XmlElement.class);
+                if (element != null) {
+                    processElement(processingEnv, roundEnv, classElement, 
element, fieldElement, eipOptions, prefix);
+                }
+
+                // special for eips which has outputs or requires an 
expressions
+                XmlElementRef elementRef = 
fieldElement.getAnnotation(XmlElementRef.class);
+                if (elementRef != null) {
+
+                    // special for routes
+                    processRoutes(roundEnv, originalClassType, elementRef, 
fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for outputs
+                    processOutputs(processingEnv, roundEnv, originalClassType, 
elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for when clauses (choice eip)
+                    processRefWhenClauses(processingEnv, roundEnv, 
originalClassType, elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for rests (rest-dsl)
+                    processRests(roundEnv, originalClassType, elementRef, 
fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for verbs (rest-dsl)
+                    processVerbs(processingEnv, roundEnv, originalClassType, 
elementRef, fieldElement, fieldName, eipOptions, prefix);
+
+                    // special for expression
+                    processRefExpression(processingEnv, roundEnv, 
originalClassType, classElement, elementRef, fieldElement, fieldName, 
eipOptions, prefix);
+
+                }
+            }
+
+            // special when we process these nodes as they do not use JAXB 
annotations on fields, but on methods
+            if 
("OptionalIdentifiedDefinition".equals(classElement.getSimpleName().toString()))
 {
+                processIdentified(processingEnv, roundEnv, originalClassType, 
classElement, eipOptions, prefix);
+            } else if 
("RouteDefinition".equals(classElement.getSimpleName().toString())) {
+                processRoute(processingEnv, roundEnv, originalClassType, 
classElement, eipOptions, prefix);
+            }
+
+            // check super classes which may also have fields
+            TypeElement baseTypeElement = null;
+            TypeMirror superclass = classElement.getSuperclass();
+            if (superclass != null) {
+                String superClassName = 
canonicalClassName(superclass.toString());
+                baseTypeElement = findTypeElement(processingEnv, roundEnv, 
superClassName);
+            }
+            if (baseTypeElement != null) {
+                classElement = baseTypeElement;
+            } else {
+                break;
+            }
+        }
+    }
+
+    private boolean processAttribute(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement 
classElement, VariableElement fieldElement,
+                                     String fieldName, XmlAttribute attribute, 
Set<EipOption> eipOptions, String prefix, String modelName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String name = attribute.name();
+        if (isNullOrEmpty(name) || "##default".equals(name)) {
+            name = fieldName;
+        }
+
+        // lets skip some unwanted attributes
+        if (skipUnwanted) {
+            // we want to skip inheritErrorHandler which is only applicable 
for the load-balancer
+            boolean loadBalancer = 
"LoadBalanceDefinition".equals(originalClassType.getSimpleName().toString());
+            if (!loadBalancer && "inheritErrorHandler".equals(name)) {
+                return true;
+            }
+        }
+
+        name = prefix + name;
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+        TypeElement fieldTypeElement = findTypeElement(processingEnv, 
roundEnv, fieldTypeName);
+
+        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, 
name, classElement, true);
+        boolean required = attribute.required();
+        // metadata may overrule element required
+        required = findRequired(fieldElement, required);
+
+        // gather enums
+        Set<String> enums = new TreeSet<String>();
+        boolean isEnum = fieldTypeElement != null && 
fieldTypeElement.getKind() == ElementKind.ENUM;
+        if (isEnum) {
+            TypeElement enumClass = findTypeElement(processingEnv, roundEnv, 
fieldTypeElement.asType().toString());
+            // find all the enum constants which has the possible enum value 
that can be used
+            List<VariableElement> fields = 
ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+            for (VariableElement var : fields) {
+                if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                    String val = var.toString();
+                    enums.add(val);
+                }
+            }
+        }
+
+        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != 
null;
+
+        EipOption ep = new EipOption(name, "attribute", fieldTypeName, 
required, defaultValue, docComment, deprecated, isEnum, enums, false, null);
+        eipOptions.add(ep);
+
+        return false;
+    }
+
+    private void processValue(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType,
+                              TypeElement classElement, VariableElement 
fieldElement, String fieldName, XmlValue value,
+        Set<EipOption> eipOptions, String prefix, String modelName) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // XmlValue has no name attribute
+        String name = fieldName;
+
+        if ("method".equals(modelName) || "tokenize".equals(modelName) || 
"xtokenize".equals(modelName)) {
+            // skip expression attribute on these three languages as they are 
solely configured using attributes
+            if ("expression".equals(name)) {
+                return;
+            }
+        }
+
+        name = prefix + name;
+        TypeMirror fieldType = fieldElement.asType();
+        String fieldTypeName = fieldType.toString();
+
+        String defaultValue = findDefaultValue(fieldElement, fieldTypeName);
+        String docComment = findJavaDoc(elementUtils, fieldElement, fieldName, 
name, classElement, true);
+        boolean required = true;
+        // metadata may overrule element required
+        required = findRequired(fieldElement, required);
+
+        boolean deprecated = fieldElement.getAnnotation(Deprecated.class) != 
null;
+
+        EipOption ep = new EipOption(name, "value", fieldTypeName, required, 
defaultValue, docComment, deprecated, false, null, false, null);
+        eipOptions.add(ep);
+    }
+
+    private void processElement(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement classElement, XmlElement element, 
VariableElement fieldElement,
+                                Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (element != null) {
+
+            String kind = "element";
+            String name = element.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+            TypeElement fieldTypeElement = findTypeElement(processingEnv, 
roundEnv, fieldTypeName);
+
+            String defaultValue = findDefaultValue(fieldElement, 
fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, 
fieldName, name, classElement, true);
+            boolean required = element.required();
+            // metadata may overrule element required
+            required = findRequired(fieldElement, required);
+
+            // gather enums
+            Set<String> enums = new LinkedHashSet<String>();
+            boolean isEnum = fieldTypeElement != null && 
fieldTypeElement.getKind() == ElementKind.ENUM;
+            if (isEnum) {
+                TypeElement enumClass = findTypeElement(processingEnv, 
roundEnv, fieldTypeElement.asType().toString());
+                // find all the enum constants which has the possible enum 
value that can be used
+                List<VariableElement> fields = 
ElementFilter.fieldsIn(enumClass.getEnclosedElements());
+                for (VariableElement var : fields) {
+                    if (var.getKind() == ElementKind.ENUM_CONSTANT) {
+                        String val = var.toString();
+                        enums.add(val);
+                    }
+                }
+            }
+
+            // gather oneOf expression/predicates which uses language
+            Set<String> oneOfTypes = new TreeSet<String>();
+            boolean isOneOf = ONE_OF_TYPE_NAME.equals(fieldTypeName);
+            if (isOneOf) {
+                // okay its actually an language expression, so favor using 
that in the eip option
+                kind = "expression";
+                for (String language : ONE_OF_LANGUAGES) {
+                    fieldTypeName = language;
+                    TypeElement languages = findTypeElement(processingEnv, 
roundEnv, language);
+                    String superClassName = 
canonicalClassName(languages.toString());
+                    // find all classes that has that superClassName
+                    Set<TypeElement> children = new 
LinkedHashSet<TypeElement>();
+                    findTypeElementChildren(processingEnv, roundEnv, children, 
superClassName);
+                    for (TypeElement child : children) {
+                        XmlRootElement rootElement = 
child.getAnnotation(XmlRootElement.class);
+                        if (rootElement != null) {
+                            String childName = rootElement.name();
+                            if (childName != null) {
+                                oneOfTypes.add(childName);
+                            }
+                        }
+                    }
+                }
+            }
+            // special for otherwise as we want to indicate that the element is
+            if ("otherwise".equals(name)) {
+                isOneOf = true;
+                oneOfTypes.add("otherwise");
+            }
+
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) 
!= null;
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, 
defaultValue, docComment, deprecated, isEnum, enums, isOneOf, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private void processElements(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement classElement, XmlElements elements, 
VariableElement fieldElement,
+                                 Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        String fieldName;
+        fieldName = fieldElement.getSimpleName().toString();
+        if (elements != null) {
+            String kind = "element";
+            String name = fieldName;
+            name = prefix + name;
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            String defaultValue = findDefaultValue(fieldElement, 
fieldTypeName);
+            String docComment = findJavaDoc(elementUtils, fieldElement, 
fieldName, name, classElement, true);
+
+            boolean required = true;
+            required = findRequired(fieldElement, required);
+
+            // gather oneOf of the elements
+            Set<String> oneOfTypes = new TreeSet<String>();
+            for (XmlElement element : elements.value()) {
+                String child = element.name();
+                oneOfTypes.add(child);
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, required, 
defaultValue, docComment, false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    private void processRoute(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement 
classElement,
+                              Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // group
+        String docComment = findJavaDoc(elementUtils, null, "group", null, 
classElement, true);
+        EipOption ep = new EipOption("group", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // group
+        docComment = findJavaDoc(elementUtils, null, "streamCache", null, 
classElement, true);
+        ep = new EipOption("streamCache", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "trace", null, 
classElement, true);
+        ep = new EipOption("trace", "attribute", "java.lang.String", false, 
"", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "messageHistory", null, 
classElement, true);
+        ep = new EipOption("messageHistory", "attribute", "java.lang.String", 
false, "true", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // trace
+        docComment = findJavaDoc(elementUtils, null, "handleFault", null, 
classElement, true);
+        ep = new EipOption("handleFault", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // delayer
+        docComment = findJavaDoc(elementUtils, null, "delayer", null, 
classElement, true);
+        ep = new EipOption("delayer", "attribute", "java.lang.String", false, 
"", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // autoStartup
+        docComment = findJavaDoc(elementUtils, null, "autoStartup", null, 
classElement, true);
+        ep = new EipOption("autoStartup", "attribute", "java.lang.String", 
false, "true", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // startupOrder
+        docComment = findJavaDoc(elementUtils, null, "startupOrder", null, 
classElement, true);
+        ep = new EipOption("startupOrder", "attribute", "java.lang.Integer", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // errorHandlerRef
+        docComment = findJavaDoc(elementUtils, null, "errorHandlerRef", null, 
classElement, true);
+        ep = new EipOption("errorHandlerRef", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // routePolicyRef
+        docComment = findJavaDoc(elementUtils, null, "routePolicyRef", null, 
classElement, true);
+        ep = new EipOption("routePolicyRef", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // shutdownRoute
+        Set<String> enums = new LinkedHashSet<String>();
+        enums.add("Default");
+        enums.add("Defer");
+        docComment = findJavaDoc(elementUtils, null, "shutdownRoute", 
"Default", classElement, true);
+        ep = new EipOption("shutdownRoute", "attribute", 
"org.apache.camel.ShutdownRoute", false, "", docComment, false, true, enums, 
false, null);
+        eipOptions.add(ep);
+
+        // shutdownRunningTask
+        enums = new LinkedHashSet<String>();
+        enums.add("CompleteCurrentTaskOnly");
+        enums.add("CompleteAllTasks");
+        docComment = findJavaDoc(elementUtils, null, "shutdownRunningTask", 
"CompleteCurrentTaskOnly", classElement, true);
+        ep = new EipOption("shutdownRunningTask", "attribute", 
"org.apache.camel.ShutdownRunningTask", false, "", docComment, false, true, 
enums, false, null);
+        eipOptions.add(ep);
+
+        // inputs
+        Set<String> oneOfTypes = new TreeSet<String>();
+        oneOfTypes.add("from");
+        docComment = findJavaDoc(elementUtils, null, "inputs", null, 
classElement, true);
+        ep = new EipOption("inputs", "element", 
"java.util.List<org.apache.camel.model.FromDefinition>", true, "", docComment, 
false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+
+        // outputs
+        // gather oneOf which extends any of the output base classes
+        oneOfTypes = new TreeSet<String>();
+        // find all classes that has that superClassName
+        Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+        for (String superclass : ONE_OF_OUTPUTS) {
+            findTypeElementChildren(processingEnv, roundEnv, children, 
superclass);
+        }
+        for (TypeElement child : children) {
+            XmlRootElement rootElement = 
child.getAnnotation(XmlRootElement.class);
+            if (rootElement != null) {
+                String childName = rootElement.name();
+                if (childName != null) {
+                    oneOfTypes.add(childName);
+                }
+            }
+        }
+
+        // remove some types which are not intended as an output in eips
+        oneOfTypes.remove("route");
+
+        docComment = findJavaDoc(elementUtils, null, "outputs", null, 
classElement, true);
+        ep = new EipOption("outputs", "element", 
"java.util.List<org.apache.camel.model.ProcessorDefinition<?>>", true, "", 
docComment, false, false, null, true, oneOfTypes);
+        eipOptions.add(ep);
+    }
+
+    /**
+     * Special for process the OptionalIdentifiedDefinition
+     */
+    private void processIdentified(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement 
classElement,
+                                   Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        // id
+        String docComment = findJavaDoc(elementUtils, null, "id", null, 
classElement, true);
+        EipOption ep = new EipOption("id", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+        eipOptions.add(ep);
+
+        // description
+        docComment = findJavaDoc(elementUtils, null, "description", null, 
classElement, true);
+        ep = new EipOption("description", "element", 
"org.apache.camel.model.DescriptionDefinition", false, "", docComment, false, 
false, null, false, null);
+        eipOptions.add(ep);
+
+        // lets skip custom id as it has no value for end users to configure
+        if (!skipUnwanted) {
+            // custom id
+            docComment = findJavaDoc(elementUtils, null, "customId", null, 
classElement, true);
+            ep = new EipOption("customId", "attribute", "java.lang.String", 
false, "", docComment, false, false, null, false, null);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef routes field
+     */
+    private void processRoutes(RoundEnvironment roundEnv, TypeElement 
originalClassType, XmlElementRef elementRef,
+                               VariableElement fieldElement, String fieldName, 
Set<EipOption> eipOptions, String prefix) {
+        if ("routes".equals(fieldName)) {
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            Set<String> oneOfTypes = new TreeSet<String>();
+            oneOfTypes.add("route");
+
+            EipOption ep = new EipOption("routes", "element", fieldTypeName, 
false, "", "Contains the Camel routes", false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef rests field
+     */
+    private void processRests(RoundEnvironment roundEnv, TypeElement 
originalClassType, XmlElementRef elementRef,
+                               VariableElement fieldElement, String fieldName, 
Set<EipOption> eipOptions, String prefix) {
+        if ("rests".equals(fieldName)) {
+
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            Set<String> oneOfTypes = new TreeSet<String>();
+            oneOfTypes.add("rest");
+
+            EipOption ep = new EipOption("rests", "element", fieldTypeName, 
false, "", "Contains the rest services defined using the rest-dsl", false, 
false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef outputs field
+     */
+    private void processOutputs(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef 
elementRef,
+                                VariableElement fieldElement, String 
fieldName, Set<EipOption> eipOptions, String prefix) {
+        if ("outputs".equals(fieldName) && supportOutputs(originalClassType)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // gather oneOf which extends any of the output base classes
+            Set<String> oneOfTypes = new TreeSet<String>();
+            // find all classes that has that superClassName
+            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+            for (String superclass : ONE_OF_OUTPUTS) {
+                findTypeElementChildren(processingEnv, roundEnv, children, 
superclass);
+            }
+            for (TypeElement child : children) {
+                XmlRootElement rootElement = 
child.getAnnotation(XmlRootElement.class);
+                if (rootElement != null) {
+                    String childName = rootElement.name();
+                    if (childName != null) {
+                        oneOfTypes.add(childName);
+                    }
+                }
+            }
+
+            // remove some types which are not intended as an output in eips
+            oneOfTypes.remove("route");
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", 
"", false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef verbs field (rest-dsl)
+     */
+    private void processVerbs(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef 
elementRef,
+                              VariableElement fieldElement, String fieldName, 
Set<EipOption> eipOptions, String prefix) {
+
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("verbs".equals(fieldName) && supportOutputs(originalClassType)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            String docComment = findJavaDoc(elementUtils, fieldElement, 
fieldName, name, originalClassType, true);
+
+            // gather oneOf which extends any of the output base classes
+            Set<String> oneOfTypes = new TreeSet<String>();
+            // find all classes that has that superClassName
+            Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+            for (String superclass : ONE_OF_VERBS) {
+                findTypeElementChildren(processingEnv, roundEnv, children, 
superclass);
+            }
+            for (TypeElement child : children) {
+                XmlRootElement rootElement = 
child.getAnnotation(XmlRootElement.class);
+                if (rootElement != null) {
+                    String childName = rootElement.name();
+                    if (childName != null) {
+                        oneOfTypes.add(childName);
+                    }
+                }
+            }
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", 
docComment, false, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef expression field
+     */
+    private void processRefExpression(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, TypeElement 
classElement,
+                                      XmlElementRef elementRef, 
VariableElement fieldElement,
+                                      String fieldName, Set<EipOption> 
eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("expression".equals(fieldName)) {
+            String kind = "expression";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // find javadoc from original class as it will override the 
setExpression method where we can provide the javadoc for the given EIP
+            String docComment = findJavaDoc(elementUtils, fieldElement, 
fieldName, name, originalClassType, true);
+
+            // gather oneOf expression/predicates which uses language
+            Set<String> oneOfTypes = new TreeSet<String>();
+            for (String language : ONE_OF_LANGUAGES) {
+                TypeElement languages = findTypeElement(processingEnv, 
roundEnv, language);
+                String superClassName = 
canonicalClassName(languages.toString());
+                // find all classes that has that superClassName
+                Set<TypeElement> children = new LinkedHashSet<TypeElement>();
+                findTypeElementChildren(processingEnv, roundEnv, children, 
superClassName);
+                for (TypeElement child : children) {
+                    XmlRootElement rootElement = 
child.getAnnotation(XmlRootElement.class);
+                    if (rootElement != null) {
+                        String childName = rootElement.name();
+                        if (childName != null) {
+                            oneOfTypes.add(childName);
+                        }
+                    }
+                }
+            }
+
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) 
!= null;
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, true, "", 
docComment, deprecated, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Special for processing an @XmlElementRef when field
+     */
+    private void processRefWhenClauses(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement originalClassType, XmlElementRef 
elementRef,
+                                       VariableElement fieldElement, String 
fieldName, Set<EipOption> eipOptions, String prefix) {
+        Elements elementUtils = processingEnv.getElementUtils();
+
+        if ("whenClauses".equals(fieldName)) {
+            String kind = "element";
+            String name = elementRef.name();
+            if (isNullOrEmpty(name) || "##default".equals(name)) {
+                name = fieldName;
+            }
+            name = prefix + name;
+            TypeMirror fieldType = fieldElement.asType();
+            String fieldTypeName = fieldType.toString();
+
+            // find javadoc from original class as it will override the 
setExpression method where we can provide the javadoc for the given EIP
+            String docComment = findJavaDoc(elementUtils, fieldElement, 
fieldName, name, originalClassType, true);
+            boolean deprecated = fieldElement.getAnnotation(Deprecated.class) 
!= null;
+
+            // indicate that this element is one of when
+            Set<String> oneOfTypes = new HashSet<String>();
+            oneOfTypes.add("when");
+
+            EipOption ep = new EipOption(name, kind, fieldTypeName, false, "", 
docComment, deprecated, false, null, true, oneOfTypes);
+            eipOptions.add(ep);
+        }
+    }
+
+    /**
+     * Whether the class supports outputs.
+     * <p/>
+     * There are some classes which does not support outputs, even though they 
have a outputs element.
+     */
+    private boolean supportOutputs(TypeElement classElement) {
+        String superclass = 
canonicalClassName(classElement.getSuperclass().toString());
+        return 
!"org.apache.camel.model.NoOutputExpressionNode".equals(superclass);
+    }
+
+    private String findDefaultValue(VariableElement fieldElement, String 
fieldTypeName) {
+        String defaultValue = null;
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.defaultValue())) {
+                defaultValue = metadata.defaultValue();
+            }
+        }
+        if (defaultValue == null) {
+            // if its a boolean type, then we use false as the default
+            if ("boolean".equals(fieldTypeName) || 
"java.lang.Boolean".equals(fieldTypeName)) {
+                defaultValue = "false";
+            }
+        }
+
+        return defaultValue;
+    }
+
+    private boolean findRequired(VariableElement fieldElement, boolean 
defaultValue) {
+        Metadata metadata = fieldElement.getAnnotation(Metadata.class);
+        if (metadata != null) {
+            if (!Strings.isNullOrEmpty(metadata.required())) {
+                defaultValue = "true".equals(metadata.required());
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Capitializes the name as a title
+     *
+     * @param name  the name
+     * @return as a title
+     */
+    private static String asTitle(String name) {
+        StringBuilder sb = new StringBuilder();
+        for (char c : name.toCharArray()) {
+            boolean upper = Character.isUpperCase(c);
+            boolean first = sb.length() == 0;
+            if (first) {
+                sb.append(Character.toUpperCase(c));
+            } else if (upper) {
+                sb.append(' ');
+                sb.append(c);
+            } else {
+                sb.append(Character.toLowerCase(c));
+            }
+        }
+        return sb.toString().trim();
+    }
+
+    private boolean hasInput(ProcessingEnvironment processingEnv, 
RoundEnvironment roundEnv, TypeElement classElement) {
+        for (String name : ONE_OF_INPUTS) {
+            if (hasSuperClass(processingEnv, roundEnv, classElement, name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasOutput(EipModel model, Set<EipOption> options) {
+        // if we are route/rest then we accept output
+        if ("route".equals(model.getName()) || "rest".equals(model.getName())) 
{
+            return true;
+        }
+
+        for (EipOption option : options) {
+            if ("outputs".equals(option.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static final class EipModel {
+
+        private String name;
+        private String title;
+        private String javaType;
+        private String label;
+        private String description;
+        private boolean input;
+        private boolean output;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+
+        public String getJavaType() {
+            return javaType;
+        }
+
+        public void setJavaType(String javaType) {
+            this.javaType = javaType;
+        }
+
+        public String getLabel() {
+            return label;
+        }
+
+        public void setLabel(String label) {
+            this.label = label;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        public boolean isInput() {
+            return input;
+        }
+
+        public void setInput(boolean input) {
+            this.input = input;
+        }
+
+        public String getInput() {
+            return input ? "true" : "false";
+        }
+
+        public boolean isOutput() {
+            return output;
+        }
+
+        public void setOutput(boolean output) {
+            this.output = output;
+        }
+
+        public String getOutput() {
+            return output ? "true" : "false";
+        }
+
+    }
+
+    private static final class EipOption {
+
+        private String name;
+        private String kind;
+        private String type;
+        private boolean required;
+        private String defaultValue;
+        private String documentation;
+        private boolean deprecated;
+        private boolean enumType;
+        private Set<String> enums;
+        private boolean oneOf;
+        private Set<String> oneOfTypes;
+
+        private EipOption(String name, String kind, String type, boolean 
required, String defaultValue, String documentation, boolean deprecated,
+                          boolean enumType, Set<String> enums, boolean oneOf, 
Set<String> oneOfTypes) {
+            this.name = name;
+            this.kind = kind;
+            this.type = type;
+            this.required = required;
+            this.defaultValue = defaultValue;
+            this.documentation = documentation;
+            this.deprecated = deprecated;
+            this.enumType = enumType;
+            this.enums = enums;
+            this.oneOf = oneOf;
+            this.oneOfTypes = oneOfTypes;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getKind() {
+            return kind;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public boolean isRequired() {
+            return required;
+        }
+
+        public String getDefaultValue() {
+            return defaultValue;
+        }
+
+        public String getDocumentation() {
+            return documentation;
+        }
+
+        public boolean isDeprecated() {
+            return deprecated;
+        }
+
+        public boolean isEnumType() {
+            return enumType;
+        }
+
+        public Set<String> getEnums() {
+            return enums;
+        }
+
+        public boolean isOneOf() {
+            return oneOf;
+        }
+
+        public Set<String> getOneOfTypes() {
+            return oneOfTypes;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            EipOption that = (EipOption) o;
+
+            if (!name.equals(that.name)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+    }
+
+    private static final class EipOptionComparator implements 
Comparator<EipOption> {
+
+        private final EipModel model;
+
+        private EipOptionComparator(EipModel model) {
+            this.model = model;
+        }
+
+        @Override
+        public int compare(EipOption o1, EipOption o2) {
+            int weigth = weigth(o1);
+            int weigth2 = weigth(o2);
+
+            if (weigth == weigth2) {
+                // keep the current order
+                return 1;
+            } else {
+                // sort according to weight
+                return weigth2 - weigth;
+            }
+        }
+
+        private int weigth(EipOption o) {
+            String name = o.getName();
+
+            // these should be first
+            if ("expression".equals(name)) {
+                return 10;
+            }
+
+            // these should be last
+            if ("description".equals(name)) {
+                return -10;
+            } else if ("id".equals(name)) {
+                return -9;
+            } else if ("pattern".equals(name) && "to".equals(model.getName())) 
{
+                // and pattern only for the to model
+                return -8;
+            }
+            return 0;
+        }
+    }
+
+}

Reply via email to