From 89d000858b0fbbe6746ac718d401602c22d618d6 Mon Sep 17 00:00:00 2001 From: Adriano Machado Date: Thu, 16 Mar 2023 15:09:44 -0400 Subject: [PATCH 1/4] Fix for REST param definition --- src/xml2dsl/xml2dsl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xml2dsl/xml2dsl.py b/src/xml2dsl/xml2dsl.py index cf2218a..1c9fc19 100755 --- a/src/xml2dsl/xml2dsl.py +++ b/src/xml2dsl/xml2dsl.py @@ -623,7 +623,6 @@ def post_def(self, node): def param_def(self, node): param = '.param()' - param += '.endParam()' if 'name' in node.attrib: param += f'.name("{node.attrib["name"]}")' @@ -643,6 +642,8 @@ def param_def(self, node): if 'dataType' in node.attrib: param += f'.dataType("{node.attrib["dataType"]}")' + param += '.endParam()' + return self.indent(param) # param().name("id").type(path).description("The id of the user to get").dataType("int").endParam() From bdf0efaa040941d89d4cd867bfb491b50c266b96 Mon Sep 17 00:00:00 2001 From: Adriano Machado Date: Thu, 6 Apr 2023 16:02:13 -0400 Subject: [PATCH 2/4] Blueprint support --- src/xml2dsl/xml2dsl.py | 122 +++++++++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/src/xml2dsl/xml2dsl.py b/src/xml2dsl/xml2dsl.py index 1c9fc19..1328852 100755 --- a/src/xml2dsl/xml2dsl.py +++ b/src/xml2dsl/xml2dsl.py @@ -9,7 +9,9 @@ __version__ = importlib.metadata.version('camel-xml2dsl') ns = { "camel": "http://camel.apache.org/schema/spring", - "beans": "http://www.springframework.org/schema/beans" + "camelBlueprint": "http://camel.apache.org/schema/blueprint", + "beans": "http://www.springframework.org/schema/beans", + "blueprint": "http://www.osgi.org/xmlns/blueprint/v1.0.0" } console = Console() @@ -32,6 +34,7 @@ class Converter: import org.apache.camel.ExchangePattern; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.dataformat.JaxbDataFormat; import org.apache.camel.model.dataformat.JsonDataFormat; import org.apache.camel.model.dataformat.JsonLibrary; import org.apache.camel.model.rest.RestBindingMode; @@ -88,7 +91,7 @@ def xml_to_dsl(self): bean_definitions.append(bean) # Multiline groovy transforms - for idx, node in enumerate(root.findall('.//camel:groovy', ns)): + for idx, node in enumerate(self.find_any_descendent(root, 'groovy')): code_hash, text = self.preformat_groovy_transformation(node) transformed = Converter.GROOVY_TEMPLATE \ .replace('>>> index <<<', str(idx)) \ @@ -100,7 +103,7 @@ def xml_to_dsl(self): } # Camel Contexts - for idx, camelContext in enumerate(root.findall('camel:camelContext', ns)): + for idx, camelContext in enumerate(self.find_camel_nodes(root, 'camelContext')): if 'id' in camelContext.attrib: console.log("processing camel context", camelContext.attrib['id']) @@ -124,8 +127,8 @@ def xml_to_dsl(self): def get_namespaces(node): console.log("namespaces:", node.nsmap) - def analyze_node(self, node): - dslText = "" + def analyze_node(self, node, suffix=''): + dslText = '' for child in node: node_name = child.tag.partition('}')[2] @@ -133,13 +136,26 @@ def analyze_node(self, node): if node_name == 'propertyPlaceholder': continue - process_function_name = node_name + "_def" + if suffix == 'dataformat': + process_function_name = f'{node_name}_dataformat_def' if suffix == 'dataformat' else f'{node_name}_def' + suffix = '' + else: + process_function_name = f'{node_name}_def' + console.log("processing node", node_name, child.tag, child.sourceline) next_node = getattr(self, process_function_name, None) if next_node is None: console.log("unknown node", process_function_name, child.sourceline) sys.exit(1) - dslText += getattr(self, process_function_name)(child) + + if suffix: + dslText += getattr(self, process_function_name)(child, suffix) + else: + dslText += getattr(self, process_function_name)(child) + + if node_name == 'from': + suffix = '' + return dslText def analyze_element(self, node): @@ -148,16 +164,26 @@ def analyze_element(self, node): return getattr(self, node_name)(node) def route_def(self, node): - route_def = self.analyze_node(node) + description_node = self.find_camel_node(node, 'description') + description = '' + if description_node is not None: + self.indentation += 1 + description = self.description_def(description_node) + self.indentation -= 1 + node.remove(description_node) + + route_def = self.analyze_node(node, description) route_def += self.indent('.end();\n') self.indentation -= 1 return route_def def dataFormats_def(self, node): - dataformats = self.analyze_node(node) + dataformats = '' + for child in node: + dataformats += self.analyze_node(child, 'dataformat') return dataformats - def json_def(self, node): + def json_dataformat_def(self, node): name = node.attrib['id'] library = f'JsonLibrary.{node.attrib["library"]}' if 'library' in node.attrib else '' @@ -173,6 +199,20 @@ def json_def(self, node): return json_dataformat + '\n' + def jaxb_dataformat_def(self, node): + name = node.attrib['id'] + jaxb_dataformat = '' + + jaxb_dataformat += self.indent(f'JaxbDataFormat {name} = new JaxbDataFormat();') + + if 'contextPath' in node.attrib: + jaxb_dataformat += self.indent(f'{name}.setContextPath("{node.attrib["contextPath"]}");') + + if 'encoding' in node.attrib: + jaxb_dataformat += self.indent(f'{name}.encoding("{node.attrib["encoding"]}");') + + return jaxb_dataformat + '\n' + def endpoint_def(self, node): endpoint_id = node.attrib['id'] uri = node.attrib['uri'] @@ -221,7 +261,7 @@ def redeliveryPolicyProfile_def(self, node): def onException_def(self, node): exceptions = [] - for exception in node.findall("camel:exception", ns): + for exception in self.find_camel_nodes(node, 'exception'): exceptions.append(exception.text + ".class") node.remove(exception) exceptions = ','.join(exceptions) @@ -229,17 +269,18 @@ def onException_def(self, node): indented = False - handled = node.find("camel:handled", ns) + handled = self.find_camel_nodes(node, 'handled') if handled is not None: if not indented: self.indentation += 1 indented = True - onException_def += self.indent('.handled(' + handled[0].text + ')') + handled_expression = self.analyze_node(handled[0]) + onException_def += self.indent(f'.handled({handled_expression})') - node.remove(handled) + node.remove(handled[0]) - redeliveryPolicy = node.find('camel:redeliveryPolicy', ns) + redeliveryPolicy = self.find_camel_node(node, 'redeliveryPolicy') if redeliveryPolicy is not None: if not indented: self.indentation += 1 @@ -271,12 +312,14 @@ def onException_def(self, node): def description_def(self, node): return self.indent(f'.description("{node.text}")') - def from_def(self, node): + def from_def(self, node, description=''): routeFrom = self.deprecatedProcessor(node.attrib['uri']) routeId = node.getparent().attrib['id'] if 'id' in node.getparent().keys() else routeFrom from_def = self.indent(f'from("{routeFrom}")') self.indentation += 1 from_def += self.indent(f'.routeId("{routeId}")') + if description: + from_def += description from_def += self.analyze_node(node) return from_def @@ -442,7 +485,7 @@ def doTry_def(self, node): def doCatch_def(self, node): exceptions = [] - for exception in node.findall("camel:exception", ns): + for exception in self.find_camel_nodes(node, 'exception'): exceptions.append(exception.text + ".class") node.remove(exception) exceptions = ', '.join(exceptions) @@ -673,6 +716,39 @@ def generic_rest_def(self, node, verb): return rest_call + def filter_def(self, node): + filter_def = self.indent(f'.filter(){self.handle_id(node)} // (source line: {str(node.sourceline)})') + self.indentation += 1 + filter_def += self.analyze_node(node) + self.indentation -= 1 + + filter_def += self.indent(f'.end() // end filter (source line: {str(node.sourceline)})') + + return filter_def + + def routeContextRef_def(self, node): + return self.indent(f'// TODO: import routeContextRef routes for \"{node.attrib["ref"]}\"') + + @staticmethod + def find_camel_node(node, node_name): + found = node.find(f'camel:{node_name}', ns) + if found: + return found[0] + + found = node.findall(f'camelBlueprint:{node_name}', ns) + if found: + return found[0] + + return None + + @staticmethod + def find_camel_nodes(node, node_name): + return node.findall(f'camel:{node_name}', ns) + node.findall(f'camelBlueprint:{node_name}', ns) + + @staticmethod + def find_any_descendent(node, node_name): + return node.findall(f'.//camel:{node_name}', ns) + node.findall(f'.//camelBlueprint:{node_name}', ns) + # Text deprecated processor for camel deprecated endpoints and features @staticmethod def deprecatedProcessor(text): @@ -682,6 +758,9 @@ def deprecatedProcessor(text): text = re.sub('"', "'", text) # replace all occurrences from " to ' text = re.sub('\n', "", text) # remove all endlines + if text == '${body}': + return text + # convert all property references for match in re.finditer(r"\$(\{[\w\.\_]+\})", text): if 'exchangeProperty' not in match.group(0) and 'headers' not in match.group(0): @@ -698,11 +777,18 @@ def componentOptions(text): return text def set_expression(self, node, set_method, parameter=None): + description_node = self.find_camel_node(node, 'description') + description = '' + if description_node is not None: + description = self.description_def(description_node) + description = description[description.index('.'):] + node.remove(description_node) + predicate = self.analyze_element(node[0]) groovy_predicate = f'.{predicate}' if predicate.startswith("groovy") else '' predicate = '' if groovy_predicate else predicate parameter = f'"{parameter.strip()}", ' if parameter else '' - return self.indent(f'.{set_method}({parameter}{predicate.strip()}){groovy_predicate}') + return self.indent(f'.{set_method}({parameter}{predicate.strip()}){description}{groovy_predicate}') def process_multiline_groovy(self, text): parts = re.split('\r?\n', text) From 5d02e2813e6f01a1b1923df35d4ad77defbd66e1 Mon Sep 17 00:00:00 2001 From: Adriano Machado Date: Tue, 1 Aug 2023 14:23:43 -0400 Subject: [PATCH 3/4] Fix filter definition --- src/xml2dsl/xml2dsl.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/xml2dsl/xml2dsl.py b/src/xml2dsl/xml2dsl.py index 1328852..56f7ef1 100755 --- a/src/xml2dsl/xml2dsl.py +++ b/src/xml2dsl/xml2dsl.py @@ -3,6 +3,7 @@ from rich import console from rich.console import Console import importlib.metadata +import os import re import sys @@ -65,8 +66,7 @@ def xml_to_dsl(self): description="Transforms xml routes to dsl routes " + __version__) p.add_argument('--xml', metavar='xml', type=str, help='xml camel context file', required=True, env_var='XML_CTX_INPUT') - p.add_argument('--beans', metavar='beans', type=str, - help='use beans instead processors', required=False, env_var='USE_BEANS') + args = p.parse_args() with open(args.xml, "r") as xml_file: parser = etree.XMLParser(remove_comments=True) @@ -107,14 +107,21 @@ def xml_to_dsl(self): if 'id' in camelContext.attrib: console.log("processing camel context", camelContext.attrib['id']) - class_name = camelContext.attrib['id'] if 'id' in camelContext.attrib else f'camelContext{str(idx)}' - class_name = class_name.capitalize() - self.get_namespaces(camelContext) self.dsl_route += self.analyze_node(camelContext) + # Blueprint Route Contexts + for idx, routeContext in enumerate(self.find_camel_nodes(root, 'routeContext')): + if 'id' in routeContext.attrib: + console.log("processing route context", camelContext.attrib['id']) + + self.get_namespaces(routeContext) + self.dsl_route += self.analyze_node(routeContext) + groovy_transformations = '\n\n'.join([v['transformation'] for k, v in self.groovy_transformations.items()]) + class_name = os.path.splitext(os.path.basename(args.xml))[0].capitalize() + dsl_route = Converter.CLASS_TEMPLATE \ .replace(">>> groovy transformations <<<", groovy_transformations) \ .replace(">>> beans <<<", ''.join(bean_definitions)) \ @@ -717,13 +724,12 @@ def generic_rest_def(self, node, verb): return rest_call def filter_def(self, node): - filter_def = self.indent(f'.filter(){self.handle_id(node)} // (source line: {str(node.sourceline)})') + filter_def = self.indent('.filter(' + self.analyze_element(node[0]) + ')' + self.handle_id(node)) + node.remove(node[0]) self.indentation += 1 filter_def += self.analyze_node(node) self.indentation -= 1 - - filter_def += self.indent(f'.end() // end filter (source line: {str(node.sourceline)})') - + filter_def += self.indent(f'.end() // (source line: {str(node.sourceline)})') return filter_def def routeContextRef_def(self, node): From 39dd6622134a5d6df98a0dec61f782b2009037f3 Mon Sep 17 00:00:00 2001 From: Adriano Machado Date: Tue, 8 Aug 2023 13:10:46 -0400 Subject: [PATCH 4/4] Fix routeContext id --- src/xml2dsl/xml2dsl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xml2dsl/xml2dsl.py b/src/xml2dsl/xml2dsl.py index 56f7ef1..60be5d6 100755 --- a/src/xml2dsl/xml2dsl.py +++ b/src/xml2dsl/xml2dsl.py @@ -113,7 +113,7 @@ def xml_to_dsl(self): # Blueprint Route Contexts for idx, routeContext in enumerate(self.find_camel_nodes(root, 'routeContext')): if 'id' in routeContext.attrib: - console.log("processing route context", camelContext.attrib['id']) + console.log("processing route context", routeContext.attrib['id']) self.get_namespaces(routeContext) self.dsl_route += self.analyze_node(routeContext)