Repository: camel
Updated Branches:
  refs/heads/parser2 [created] 32e0a7162


Camel java dsl parser prototype


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d8844048
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d8844048
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d8844048

Branch: refs/heads/parser2
Commit: d8844048b8f7def0b5eb25286de3802446de3a14
Parents: 3c14611
Author: Claus Ibsen <[email protected]>
Authored: Fri Dec 23 22:10:09 2016 +0100
Committer: Claus Ibsen <[email protected]>
Committed: Sat Oct 7 16:33:25 2017 +0200

----------------------------------------------------------------------
 tooling/camel-route-parser/pom.xml              |   7 +
 .../parser/AdvancedRouteBuilderParser.java      |  56 +++
 .../apache/camel/parser/graph/RenderRoute.java  |  66 ++++
 .../helper/AdvancedCamelJavaParserHelper.java   | 392 +++++++++++++++++++
 .../camel/parser/model/CamelNodeDetails.java    |  86 ++++
 .../parser/java/MyJavaDslRouteBuilder.java      |  38 ++
 .../camel/parser/java/RoasterJavaDslTest.java   |  44 +++
 7 files changed, 689 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/camel-route-parser/pom.xml 
b/tooling/camel-route-parser/pom.xml
index 5d3aa77..4d67bd3 100644
--- a/tooling/camel-route-parser/pom.xml
+++ b/tooling/camel-route-parser/pom.xml
@@ -42,6 +42,13 @@
       <scope>provided</scope>
     </dependency>
 
+    <!-- the catalog has details the parser needs to parse the Camel Java DSL 
-->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-catalog</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
     <!-- only test scopes for camel as we have no runtime dependency on camel 
-->
     <dependency>
       <groupId>org.apache.camel</groupId>

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/AdvancedRouteBuilderParser.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/AdvancedRouteBuilderParser.java
 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/AdvancedRouteBuilderParser.java
new file mode 100644
index 0000000..e3fb6d7
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/AdvancedRouteBuilderParser.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.parser.helper.AdvancedCamelJavaParserHelper;
+import org.apache.camel.parser.helper.CamelJavaParserHelper;
+import org.apache.camel.parser.model.CamelNodeDetails;
+import org.jboss.forge.roaster.model.source.JavaClassSource;
+import org.jboss.forge.roaster.model.source.MethodSource;
+
+/**
+ * TODO: Merge this to {@link RouteBuilderParser}
+ */
+public class AdvancedRouteBuilderParser {
+
+    // TODO: list of details, on per route
+    public static CamelNodeDetails parseRouteBuilder(JavaClassSource clazz, 
boolean includeInlinedRouteBuilders) {
+        AdvancedCamelJavaParserHelper parser = new 
AdvancedCamelJavaParserHelper();
+
+        List<MethodSource<JavaClassSource>> methods = new ArrayList<>();
+        MethodSource<JavaClassSource> method = 
CamelJavaParserHelper.findConfigureMethod(clazz);
+        if (method != null) {
+            methods.add(method);
+        }
+        if (includeInlinedRouteBuilders) {
+            List<MethodSource<JavaClassSource>> inlinedMethods = 
CamelJavaParserHelper.findInlinedConfigureMethods(clazz);
+            if (!inlinedMethods.isEmpty()) {
+                methods.addAll(inlinedMethods);
+            }
+        }
+
+        for (MethodSource<JavaClassSource> configureMethod : methods) {
+            CamelNodeDetails details = parser.parseCamelRoute(clazz, 
configureMethod);
+            return details;
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
new file mode 100644
index 0000000..2b1cd1c
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
@@ -0,0 +1,66 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.parser.graph;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+
+import org.apache.camel.parser.model.CamelNodeDetails;
+
+public class RenderRoute {
+
+    public static void main(String[] args) {
+        RenderRoute render = new RenderRoute();
+        render(null);
+    }
+
+    public static void render(CamelNodeDetails root) {
+        // TODO:
+        try {
+            int width = 200, height = 200;
+
+            // TYPE_INT_ARGB specifies the image format: 8-bit RGBA packed
+            // into integer pixels
+//            BufferedImage bi = new BufferedImage(width, height, 
BufferedImage.TYPE_INT_ARGB);
+            BufferedImage bi = new BufferedImage(width, height, 
BufferedImage.TYPE_INT_ARGB);
+
+            Graphics2D ig2 = bi.createGraphics();
+
+            ig2.drawRect(10, 10, 80, 40);
+            ig2.drawLine(45, 50, 45, 80);
+            ig2.drawRect(10, 80, 80, 40);
+
+            Font font = new Font("Arial", Font.BOLD, 20);
+            ig2.setFont(font);
+            String message = "Apache Camel";
+            FontMetrics fontMetrics = ig2.getFontMetrics();
+            int stringWidth = fontMetrics.stringWidth(message);
+            int stringHeight = fontMetrics.getAscent();
+            ig2.setPaint(Color.black);
+            ig2.drawString(message, (width - stringWidth) / 2, height / 2 + 
stringHeight / 4);
+
+            ImageIO.write(bi, "PNG", new File("target/route.png"));
+
+        } catch (IOException ie) {
+            ie.printStackTrace();
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/helper/AdvancedCamelJavaParserHelper.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/helper/AdvancedCamelJavaParserHelper.java
 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/helper/AdvancedCamelJavaParserHelper.java
new file mode 100644
index 0000000..1a5fa0b
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/helper/AdvancedCamelJavaParserHelper.java
@@ -0,0 +1,392 @@
+/**
+ * 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.parser.helper;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.catalog.JSonSchemaHelper;
+import org.apache.camel.parser.RouteBuilderParser;
+import org.apache.camel.parser.model.CamelNodeDetails;
+import org.apache.camel.parser.roaster.StatementFieldSource;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ASTNode;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Block;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.BooleanLiteral;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Expression;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ExpressionStatement;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.FieldDeclaration;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.InfixExpression;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.MemberValuePair;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.MethodDeclaration;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.MethodInvocation;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.NormalAnnotation;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.NumberLiteral;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ParenthesizedExpression;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.QualifiedName;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SimpleName;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.SingleMemberAnnotation;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.StringLiteral;
+import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Type;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import 
org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.jboss.forge.roaster.model.Annotation;
+import org.jboss.forge.roaster.model.source.FieldSource;
+import org.jboss.forge.roaster.model.source.JavaClassSource;
+import org.jboss.forge.roaster.model.source.MethodSource;
+
+/**
+ * A Camel Java parser that only depends on the Roaster API.
+ * <p/>
+ * This implementation is lower level details. For a higher level parser see 
{@link RouteBuilderParser}.
+ */
+public final class AdvancedCamelJavaParserHelper {
+
+    private CamelCatalog camelCatalog = new DefaultCamelCatalog(true);
+
+    public CamelNodeDetails parseCamelRoute(JavaClassSource clazz, 
MethodSource<JavaClassSource> method) {
+
+        // find any from which is the start of the route
+
+        CamelNodeDetails route = new CamelNodeDetails(null, "route");
+
+        if (method != null) {
+            MethodDeclaration md = (MethodDeclaration) method.getInternal();
+            Block block = md.getBody();
+            if (block != null) {
+                for (Object statement : md.getBody().statements()) {
+                    // must be a method call expression
+                    if (statement instanceof ExpressionStatement) {
+                        ExpressionStatement es = (ExpressionStatement) 
statement;
+                        Expression exp = es.getExpression();
+
+                        parseExpression(clazz, block, exp, route);
+                    }
+                }
+            }
+        }
+
+        // now parse the route node and build a tree structure of the EIPs
+        String root = route.getOutputs().get(0).getName();
+
+        CamelNodeDetails answer = new CamelNodeDetails(null, root);
+        CamelNodeDetails parent = answer;
+
+        // TODO: use camel catalog to know about these types and when to do 
what
+
+        for (int i = 1; i < route.getOutputs().size(); i++) {
+            CamelNodeDetails node = route.getOutputs().get(i);
+            String name = node.getName();
+
+            // special for some EIPs
+            if ("choice".equals(name)) {
+                CamelNodeDetails output = new CamelNodeDetails(parent, name);
+                parent.addOutput(output);
+                parent = output;
+            } else if ("when".equals(name)) {
+                parent = grandParent(parent, "choice");
+                CamelNodeDetails output = new CamelNodeDetails(parent, name);
+                parent.addOutput(output);
+                parent = output;
+            } else if ("otherwise".equals(name)) {
+                parent = grandParent(parent, "choice");
+                CamelNodeDetails output = new CamelNodeDetails(parent, name);
+                parent.addOutput(output);
+                parent = output;
+            } else if ("end".equals(name) || "endChoice".equals(name) || 
"endDoTry".equals(name)) {
+                // special for ending otherwise, as we end it automatic in 
Java DSL so do a double end then
+                if ("otherwise".equals(parent.getName())) {
+                    parent = parent.getParent();
+                }
+                // parent should be grand parent
+                parent = parent.getParent();
+            } else {
+                boolean hasOutput = hasOutput(name);
+                if (hasOutput) {
+                    // has output so add as new child node
+                    CamelNodeDetails output = new CamelNodeDetails(parent, 
name);
+                    parent.addOutput(output);
+                    parent = output;
+                } else {
+                    // add straight to itself
+                    CamelNodeDetails output = new CamelNodeDetails(parent, 
name);
+                    parent.addOutput(output);
+                }
+            }
+        }
+
+        return answer;
+    }
+
+    private boolean hasOutput(String name) {
+        String json = camelCatalog.modelJSonSchema(name);
+        List<Map<String, String>> rows = 
JSonSchemaHelper.parseJsonSchema("model", json, false);
+        return isModelOutput(rows);
+    }
+
+    private static boolean isModelOutput(List<Map<String, String>> rows) {
+        for (Map<String, String> row : rows) {
+            if (row.containsKey("output")) {
+                return "true".equals(row.get("output"));
+            }
+        }
+        return false;
+    }
+
+    private static CamelNodeDetails grandParent(CamelNodeDetails node, String 
parentName) {
+        if (node == null) {
+            return null;
+        }
+        if (parentName.equals(node.getName())) {
+            return node;
+        } else {
+            return grandParent(node.getParent(), parentName);
+        }
+    }
+
+    private void parseExpression(JavaClassSource clazz, Block block, 
Expression exp, CamelNodeDetails node) {
+        if (exp == null) {
+            return;
+        }
+        if (exp instanceof MethodInvocation) {
+            MethodInvocation mi = (MethodInvocation) exp;
+            node = doParseCamelModels(clazz, block, mi, node);
+            // if the method was called on another method, then recursive
+            exp = mi.getExpression();
+            parseExpression(clazz, block, exp, node);
+        }
+    }
+
+    private CamelNodeDetails doParseCamelModels(JavaClassSource clazz, Block 
block, MethodInvocation mi, CamelNodeDetails node) {
+        String name = mi.getName().getIdentifier();
+
+        // special for Java DSL having some endXXX
+        boolean isEnd = "end".equals(name) || "endChoice".equals(name) || 
"endDoTry".equals(name);
+
+        // only include if its a known Camel model
+        if (isEnd || camelCatalog.findModelNames().contains(name)) {
+            CamelNodeDetails newNode = new CamelNodeDetails(node, name);
+            node.addPreliminaryOutput(newNode);
+            return node;
+        }
+
+        return node;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static FieldSource<JavaClassSource> getField(JavaClassSource 
clazz, Block block, SimpleName ref) {
+        String fieldName = ref.getIdentifier();
+        if (fieldName != null) {
+            // find field in class
+            FieldSource field = clazz != null ? clazz.getField(fieldName) : 
null;
+            if (field == null) {
+                field = findFieldInBlock(clazz, block, fieldName);
+            }
+            return field;
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static FieldSource<JavaClassSource> 
findFieldInBlock(JavaClassSource clazz, Block block, String fieldName) {
+        for (Object statement : block.statements()) {
+            // try local statements first in the block
+            if (statement instanceof VariableDeclarationStatement) {
+                final Type type = ((VariableDeclarationStatement) 
statement).getType();
+                for (Object obj : ((VariableDeclarationStatement) 
statement).fragments()) {
+                    if (obj instanceof VariableDeclarationFragment) {
+                        VariableDeclarationFragment fragment = 
(VariableDeclarationFragment) obj;
+                        SimpleName name = fragment.getName();
+                        if (name != null && 
fieldName.equals(name.getIdentifier())) {
+                            return new StatementFieldSource(clazz, fragment, 
type);
+                        }
+                    }
+                }
+            }
+
+            // okay the field may be burried inside an anonymous inner class 
as a field declaration
+            // outside the configure method, so lets go back to the parent and 
see what we can find
+            ASTNode node = block.getParent();
+            if (node instanceof MethodDeclaration) {
+                node = node.getParent();
+            }
+            if (node instanceof AnonymousClassDeclaration) {
+                List declarations = ((AnonymousClassDeclaration) 
node).bodyDeclarations();
+                for (Object dec : declarations) {
+                    if (dec instanceof FieldDeclaration) {
+                        FieldDeclaration fd = (FieldDeclaration) dec;
+                        final Type type = fd.getType();
+                        for (Object obj : fd.fragments()) {
+                            if (obj instanceof VariableDeclarationFragment) {
+                                VariableDeclarationFragment fragment = 
(VariableDeclarationFragment) obj;
+                                SimpleName name = fragment.getName();
+                                if (name != null && 
fieldName.equals(name.getIdentifier())) {
+                                    return new StatementFieldSource(clazz, 
fragment, type);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static String getLiteralValue(JavaClassSource clazz, Block block, 
Expression expression) {
+        // unwrap parenthesis
+        if (expression instanceof ParenthesizedExpression) {
+            expression = ((ParenthesizedExpression) 
expression).getExpression();
+        }
+
+        if (expression instanceof StringLiteral) {
+            return ((StringLiteral) expression).getLiteralValue();
+        } else if (expression instanceof BooleanLiteral) {
+            return "" + ((BooleanLiteral) expression).booleanValue();
+        } else if (expression instanceof NumberLiteral) {
+            return ((NumberLiteral) expression).getToken();
+        }
+
+        // if it a method invocation then add a dummy value assuming the 
method invocation will return a valid response
+        if (expression instanceof MethodInvocation) {
+            String name = ((MethodInvocation) 
expression).getName().getIdentifier();
+            return "{{" + name + "}}";
+        }
+
+        // if its a qualified name (usually a constant field in another class)
+        // then add a dummy value as we cannot find the field value in other 
classes and maybe even outside the
+        // source code we have access to
+        if (expression instanceof QualifiedName) {
+            QualifiedName qn = (QualifiedName) expression;
+            String name = qn.getFullyQualifiedName();
+            return "{{" + name + "}}";
+        }
+
+        if (expression instanceof SimpleName) {
+            FieldSource<JavaClassSource> field = getField(clazz, block, 
(SimpleName) expression);
+            if (field != null) {
+                // is the field annotated with a Camel endpoint
+                if (field.getAnnotations() != null) {
+                    for (Annotation ann : field.getAnnotations()) {
+                        boolean valid = 
"org.apache.camel.EndpointInject".equals(ann.getQualifiedName()) || 
"org.apache.camel.cdi.Uri".equals(ann.getQualifiedName());
+                        if (valid) {
+                            Expression exp = (Expression) ann.getInternal();
+                            if (exp instanceof SingleMemberAnnotation) {
+                                exp = ((SingleMemberAnnotation) 
exp).getValue();
+                            } else if (exp instanceof NormalAnnotation) {
+                                List values = ((NormalAnnotation) 
exp).values();
+                                for (Object value : values) {
+                                    MemberValuePair pair = (MemberValuePair) 
value;
+                                    if 
("uri".equals(pair.getName().toString())) {
+                                        exp = pair.getValue();
+                                        break;
+                                    }
+                                }
+                            }
+                            if (exp != null) {
+                                return getLiteralValue(clazz, block, exp);
+                            }
+                        }
+                    }
+                }
+                // is the field an org.apache.camel.Endpoint type?
+                if ("Endpoint".equals(field.getType().getSimpleName())) {
+                    // then grab the uri from the first argument
+                    VariableDeclarationFragment vdf = 
(VariableDeclarationFragment) field.getInternal();
+                    expression = vdf.getInitializer();
+                    if (expression instanceof MethodInvocation) {
+                        MethodInvocation mi = (MethodInvocation) expression;
+                        List args = mi.arguments();
+                        if (args != null && args.size() > 0) {
+                            // the first argument has the endpoint uri
+                            expression = (Expression) args.get(0);
+                            return getLiteralValue(clazz, block, expression);
+                        }
+                    }
+                } else {
+                    // no annotations so try its initializer
+                    VariableDeclarationFragment vdf = 
(VariableDeclarationFragment) field.getInternal();
+                    expression = vdf.getInitializer();
+                    if (expression == null) {
+                        // its a field which has no initializer, then add a 
dummy value assuming the field will be initialized at runtime
+                        return "{{" + field.getName() + "}}";
+                    } else {
+                        return getLiteralValue(clazz, block, expression);
+                    }
+                }
+            } else {
+                // we could not find the field in this class/method, so its 
maybe from some other super class, so insert a dummy value
+                final String fieldName = ((SimpleName) 
expression).getIdentifier();
+                return "{{" + fieldName + "}}";
+            }
+        } else if (expression instanceof InfixExpression) {
+            String answer = null;
+            // is it a string that is concat together?
+            InfixExpression ie = (InfixExpression) expression;
+            if (InfixExpression.Operator.PLUS.equals(ie.getOperator())) {
+
+                String val1 = getLiteralValue(clazz, block, 
ie.getLeftOperand());
+                String val2 = getLiteralValue(clazz, block, 
ie.getRightOperand());
+
+                // if numeric then we plus the values, otherwise we string 
concat
+                boolean numeric = isNumericOperator(clazz, block, 
ie.getLeftOperand()) && isNumericOperator(clazz, block, ie.getRightOperand());
+                if (numeric) {
+                    Long num1 = val1 != null ? Long.valueOf(val1) : 0;
+                    Long num2 = val2 != null ? Long.valueOf(val2) : 0;
+                    answer = "" + (num1 + num2);
+                } else {
+                    answer = (val1 != null ? val1 : "") + (val2 != null ? val2 
: "");
+                }
+
+                if (!answer.isEmpty()) {
+                    // include extended when we concat on 2 or more lines
+                    List extended = ie.extendedOperands();
+                    if (extended != null) {
+                        for (Object ext : extended) {
+                            String val3 = getLiteralValue(clazz, block, 
(Expression) ext);
+                            if (numeric) {
+                                Long num3 = val3 != null ? Long.valueOf(val3) 
: 0;
+                                Long num = Long.valueOf(answer);
+                                answer = "" + (num + num3);
+                            } else {
+                                answer += val3 != null ? val3 : "";
+                            }
+                        }
+                    }
+                }
+            }
+            return answer;
+        }
+
+        return null;
+    }
+
+    private static boolean isNumericOperator(JavaClassSource clazz, Block 
block, Expression expression) {
+        if (expression instanceof NumberLiteral) {
+            return true;
+        } else if (expression instanceof SimpleName) {
+            FieldSource field = getField(clazz, block, (SimpleName) 
expression);
+            if (field != null) {
+                return field.getType().isType("int") || 
field.getType().isType("long")
+                        || field.getType().isType("Integer") || 
field.getType().isType("Long");
+            }
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/model/CamelNodeDetails.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/model/CamelNodeDetails.java
 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/model/CamelNodeDetails.java
new file mode 100644
index 0000000..76c3bba
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/model/CamelNodeDetails.java
@@ -0,0 +1,86 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.parser.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CamelNodeDetails {
+
+    private final String name;
+    private List<CamelNodeDetails> outputs;
+    private CamelNodeDetails parent;
+
+    public CamelNodeDetails(CamelNodeDetails parent, String name) {
+        this.parent = parent;
+        this.name = name;
+    }
+
+    public void addPreliminaryOutput(CamelNodeDetails output) {
+        if (outputs == null) {
+            outputs = new ArrayList<>();
+        }
+        // the parser walks the EIPs backwards so add from the top
+        outputs.add(0, output);
+    }
+
+    public void addOutput(CamelNodeDetails output) {
+        if (outputs == null) {
+            outputs = new ArrayList<>();
+        }
+        outputs.add(output);
+    }
+
+    public CamelNodeDetails getParent() {
+        return parent;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<CamelNodeDetails> getOutputs() {
+        return outputs;
+    }
+
+    public String toString() {
+        return name;
+    }
+
+    public String dump(int level) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(padString(level));
+        sb.append(name);
+        if (outputs != null) {
+            level++;
+            for (CamelNodeDetails child : outputs) {
+                String text = child.dump(level);
+                sb.append("\n");
+                sb.append(text);
+            }
+        }
+        return sb.toString();
+    }
+
+    private static String padString(int level) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < level; i++) {
+            sb.append("  ");
+        }
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJavaDslRouteBuilder.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJavaDslRouteBuilder.java
 
b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJavaDslRouteBuilder.java
new file mode 100644
index 0000000..91ff71f
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/MyJavaDslRouteBuilder.java
@@ -0,0 +1,38 @@
+/**
+ * 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.parser.java;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyJavaDslRouteBuilder extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("timer:foo").routeId("bar")
+            .log("I was here")
+            .setHeader("foo", constant("123"))
+            .choice()
+                .when(header("foo"))
+                    .toD("log:a")
+                .when(header("bar"))
+                    .toD("log:b")
+                .otherwise()
+                    .wireTap("mock:tap")
+            .end()
+            .to("log:b");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/d8844048/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTest.java
----------------------------------------------------------------------
diff --git 
a/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTest.java
 
b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTest.java
new file mode 100644
index 0000000..841c608
--- /dev/null
+++ 
b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTest.java
@@ -0,0 +1,44 @@
+/**
+ * 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.parser.java;
+
+import java.io.File;
+
+import org.apache.camel.parser.AdvancedRouteBuilderParser;
+import org.apache.camel.parser.model.CamelNodeDetails;
+import org.jboss.forge.roaster.Roaster;
+import org.jboss.forge.roaster.model.source.JavaClassSource;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoasterJavaDslTest {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(RoasterJavaDslTest.class);
+
+    @Test
+    public void parse() throws Exception {
+        JavaClassSource clazz = (JavaClassSource) Roaster.parse(new 
File("src/test/java/org/apache/camel/parser/java/MyJavaDslRouteBuilder.java"));
+
+        CamelNodeDetails details = 
AdvancedRouteBuilderParser.parseRouteBuilder(clazz, true);
+        String tree = details.dump(0);
+        LOG.info("\n" + tree);
+
+        System.out.println(tree);
+    }
+
+}

Reply via email to