James Strachan wrote:
Awesome! :)

Did you try out the xtext stuff to generate a nice context
highlighting editor as well?

At the moment I use *Type classes but I'm working on injecting routes
directly into camel context now.

Creating the *Type classes sounds good btw - the classes in
org.apache.camel.model; then we can just add the RoutesType to the
CamelContext and share the same code to take the AST and turn it into
the actual running routes. Is that kinda what you meant?


No I haven't look at xtext yet. The next task on my plate is When it's done I'll start hacking eclipse.

Type classes. Well, my idea was to avoid their usage and inject concrete route objects into the camel context directly. Just for sake of avoiding extra dependencies. But after some more code reading I discovered that a lot of business is done in Type classes. Wrapping routes into exception handlers, hooking up interceptors, etc. So I decided I will use Type classes. I could experiment with implementing this logic in parser itself, but why would I do something that already is implemented? BTW, it is not rhetorical question so if there is a reason, let me know :)

Overall it turned out to be much simpler task then I anticipated. Kudos to antlrworks. This tool changed my opinion about LL parsers (top-to-down parser). I am ready to trade LR parser for what this tool gives to you. Ability to debug your *grammar* even before you compile it with the application saves tons of time and is just fun to watch and play with. And when it shows a visual graph with conflicting choices in the grammar... man, I was just speechless when I discovered it.

Questions:
Here's what I'm considering as I'm doing it. First of all some kind of code reusage support. What if you have the same route definition in several places? Do we want to support some kind of macro? If we do, then the next thing users will ask is "I have a macro, but in each application I need to set a parameter in it, for example queue name". As I'm trying to keep domain of this DSL small and avoid yet another interpreter. So I think it'd be beneficial to integrate this DSL with scripting languages which we already have in camel. Another thing is that we need external calls in order to implement conditions. I'd rather delegate expressions evaluation and keep DSL a routing only language.

For example dsl:

route from {
        // must return list of strings or null
        // TODO: where getMySourceList is declared???
        juel:getMySourceList('InputQueue', 'Integration')
} to {
        'mock:a1'
        if(javascript('headers.header["a"] == "b"')) {
                'a2'
        } else {
                multicast {
                        'a3'
                        'a4'
                }
        }
}


Comments are more than welcome,
Vadim.

P.S. Here is the current parser. There is a decision conflict around "else" and I'm working on it.
=====================================================================
grammar Camel;
options { output = AST; ASTLabelType = CommonTree;}

tokens {
        ROUTES; PROCESS;
}

@header { package org.mycompany.test; }
@lexer::header { package org.mycompany.test; }

routes :
        route+ -> ^(ROUTES route*)
        ;

route :
        ROUTE from (to)?
        ;
        
from :
        FROM endpoints
        ;

to :
        TO endpoints
        ;

endpoints :     
        endpoint
        | '{' endpoint+ '}'
        ;


endpoint:
        SINGLE_Q_STRING
| IF '(' function ')' endpoints (ELSE endpoints )? // TODO: make sure that "sliding else" works correctly
        ;

function:
        lang ':' LITERAL params?
        ;
        
params  :       
        '(' (SINGLE_Q_STRING (',' SINGLE_Q_STRING)* )* ')'
        ;

/*process :
        BEAN SINGLE_Q_STRING -> ^(BEAN SINGLE_Q_STRING)
        | MULTICAST '{' process* '}' -> ^(MULTICAST process*)
        //| PIPELINE '{' process_list '}'
        | SPLIT SINGLE_Q_STRING
        //| AGGREGATE expression
        | AGGREGATE
        | resequence
        ;

resequence :
        RESEQUENCE BATCH
        //| BATCH RESEQUENCE expression
        | BATCH RESEQUENCE NUMBER NUMBER
        //| BATCH RESEQUENCE NUMBER NUMBER '(' expression_list ')'
        //| STREAM RESEQUENCE resequence_options
        //| STREAM RESEQUENCE resequence_options '(' expression ')'
        ;
*/
        
lang    :       
        'el'
        |'xpath'
        |'ognl'
        |'beanshell'
        |'javascript'
        |'groovy'
        |'python'
        |'php'
        |'ruby'
        ;

ROUTE   :       'route';
FROM    :       'from';
TO      :       'to';
BEAN    :       'bean';
MULTICAST:      'multicast';
PIPELINE:       'pipeline';
SPLIT   :       'split';
AGGREGATE:      'aggregate';
RESEQUENCE:     'resequence';
BATCH   :       'batch';
STREAM  :       'stream';

IF      :       'if';
ELSE    :       'else';

NUMBER  :       '0'..'9'+;
SINGLE_Q_STRING : '\'' ~('\'')* '\'' {setText(getText().substring(1, getText().length()-1));} ;
LITERAL :       ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*;

WS  : (' '|'\r'|'\n'|'\t')+ {$channel = HIDDEN;} ;
COMMENT
    :   '/*' .* '*/' {$channel=HIDDEN;}
    ;
LINE_COMMENT
    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    ;

Reply via email to