All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.fabric8.forge.camel.commands.project.CamelEditNodeXmlCommand Maven / Gradle / Ivy

/**
 * Copyright 2005-2015 Red Hat, Inc.
 * 

* Red Hat 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 io.fabric8.forge.camel.commands.project; import java.io.InputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import io.fabric8.forge.addon.utils.XmlLineNumberParser; import io.fabric8.forge.camel.commands.project.completer.CamelLanguagesCompleter; import io.fabric8.forge.camel.commands.project.completer.XmlEndpointsCompleter; import io.fabric8.forge.camel.commands.project.dto.NodeDto; import io.fabric8.forge.camel.commands.project.helper.CamelXmlHelper; import io.fabric8.forge.camel.commands.project.helper.PoorMansLogger; import io.fabric8.forge.camel.commands.project.model.CamelEndpointDetails; import io.fabric8.forge.camel.commands.project.model.InputOptionByGroup; import org.apache.camel.catalog.CamelCatalog; import org.apache.camel.catalog.JSonSchemaHelper; import org.apache.camel.model.ExpressionSubElementDefinition; import org.apache.camel.model.language.ExpressionDefinition; import org.apache.camel.util.CollectionStringBuffer; import org.apache.camel.util.IntrospectionSupport; import org.jboss.forge.addon.projects.Project; import org.jboss.forge.addon.projects.dependencies.DependencyInstaller; import org.jboss.forge.addon.resource.FileResource; import org.jboss.forge.addon.ui.context.UIBuilder; import org.jboss.forge.addon.ui.context.UIContext; import org.jboss.forge.addon.ui.context.UIExecutionContext; import org.jboss.forge.addon.ui.context.UINavigationContext; import org.jboss.forge.addon.ui.input.InputComponent; import org.jboss.forge.addon.ui.input.InputComponentFactory; import org.jboss.forge.addon.ui.input.UISelectOne; import org.jboss.forge.addon.ui.metadata.UICommandMetadata; import org.jboss.forge.addon.ui.metadata.WithAttributes; import org.jboss.forge.addon.ui.result.NavigationResult; import org.jboss.forge.addon.ui.result.Result; import org.jboss.forge.addon.ui.result.Results; import org.jboss.forge.addon.ui.result.navigation.NavigationResultBuilder; import org.jboss.forge.addon.ui.util.Categories; import org.jboss.forge.addon.ui.util.Metadata; import org.jboss.forge.addon.ui.wizard.UIWizard; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import static io.fabric8.forge.camel.commands.project.helper.CamelCommandsHelper.createUIInputsForCamelEIP; import static io.fabric8.forge.camel.commands.project.helper.CamelCommandsHelper.createUIInputsForCamelEndpoint; import static io.fabric8.forge.camel.commands.project.helper.CamelXmlHelper.loadCamelXmlFileAsDom; import static io.fabric8.forge.camel.commands.project.helper.CamelXmlHelper.xmlAsModel; /** * Edits an EIP to an existing XML route */ public class CamelEditNodeXmlCommand extends AbstractCamelProjectCommand implements UIWizard { private static final PoorMansLogger LOG = new PoorMansLogger(false); @Inject @WithAttributes(label = "XML File", required = true, description = "The XML file to use (either Spring or Blueprint)") private UISelectOne xml; @Inject @WithAttributes(label = "Node", required = true, description = "Node to edit") private UISelectOne node; private transient List nodes; private transient NodeDto preSelectedNode; @Inject private InputComponentFactory componentFactory; @Inject private DependencyInstaller dependencyInstaller; private XmlEndpointsCompleter xmlCompleter; @Override public UICommandMetadata getMetadata(UIContext context) { return Metadata.forCommand(CamelEditNodeXmlCommand.class).name( "Camel: Edit Node XML").category(Categories.create(CATEGORY)) .description("Edits a node in a Camel XML file"); } @Override public boolean isEnabled(UIContext context) { boolean enabled = super.isEnabled(context); // this command works both in Web UI and in GUI mode if (enabled) { // must have xml files with camel routes to be enabled Project project = getSelectedProject(context); String currentFile = getSelectedFile(context); String selected = configureXml(project, xml, currentFile); return selected != null; } return false; } @Override public void initializeUI(UIBuilder builder) throws Exception { UIContext context = builder.getUIContext(); Map attributeMap = context.getAttributeMap(); attributeMap.remove("navigationResult"); Project project = getSelectedProject(context); // include custom components discoverCustomCamelComponentsOnClasspathAndAddToCatalog(camelCatalog, project); String selectedFile = getSelectedFile(builder.getUIContext()); final String currentFile = asRelativeFile(builder.getUIContext(), selectedFile); final int cursorLineNumber = getCurrentCursorLine(builder.getUIContext()); LOG.info("Current file " + currentFile + " line number: " + cursorLineNumber); String selected = configureXml(project, xml, currentFile); nodes = configureXmlNodes(context, project, selected, xml, node); NodeDto candidate = null; FileResource file = getXmlResourceFile(project, currentFile); if (file != null) { InputStream resourceInputStream = file.getResourceInputStream(); Document root = loadCamelXmlFileAsDom(resourceInputStream); if (root != null) { for (NodeDto node : nodes) { String key = node.getKey(); Node selectedNode = CamelXmlHelper.findCamelNodeInDocument(root, key); LOG.info("Node " + key + " in XML " + selectedNode); if (selectedNode != null) { // skip root types like routes/camelContext boolean skip = "camelContext".equals(node.getPattern()) || "routes".equals(node.getPattern()) || "rests".equals(node.getPattern()); if (skip) { continue; } // we need to add after the parent node, so use line number information from the parent String lineNumber = (String) selectedNode.getUserData(XmlLineNumberParser.LINE_NUMBER); String lineNumberEnd = (String) selectedNode.getUserData(XmlLineNumberParser.LINE_NUMBER_END); if (lineNumber != null && lineNumberEnd != null) { LOG.info("Node " + key + " line " + lineNumber + "-" + lineNumberEnd); int start = Integer.parseInt(lineNumber); int end = Integer.parseInt(lineNumberEnd); if (start <= cursorLineNumber && end >= cursorLineNumber) { // its okay to select new candidate as a child is better than a parent if its within the range LOG.info("Selecting candidate " + node); candidate = node; } } } } } } if (candidate != null) { // lets pre-select the EIP from the cursor line so the wizard can move on preSelectedNode = candidate; } else { // show the UI where you can chose the xml and EIPs to select builder.add(xml).add(node); } } @Override public NavigationResult next(UINavigationContext context) throws Exception { Map attributeMap = context.getUIContext().getAttributeMap(); // always refresh these as the end user may have edited the instance name String xmlResourceName = xml.getValue(); attributeMap.put("xml", xmlResourceName); attributeMap.put("mode", "edit"); attributeMap.put("kind", "xml"); LOG.info("Edit selected index: " + node.getSelectedIndex()); NodeDto editNode = preSelectedNode; if (editNode == null && node != null) { int selectedIdx = node.getSelectedIndex(); if (selectedIdx != -1) { editNode = nodes.get(selectedIdx); } } String key = editNode != null ? editNode.getKey() : null; // must be same node to allow reusing existing navigation result String previous = getNodeKey(attributeMap.get("node")); if (previous != null && previous.equals(key)) { NavigationResult navigationResult = (NavigationResult) attributeMap.get("navigationResult"); if (navigationResult != null) { return navigationResult; } } LOG.info("Edit node " + editNode + " pattern " + editNode.getPattern()); attributeMap.put("node", key); String nodeName = editNode.getPattern(); attributeMap.put("nodeName", nodeName); attributeMap.put("pattern", editNode.getPattern()); // if its "from" or "to" then lets edit the node as an endpoint if (("from".equals(editNode.getPattern()) || "to".equals(editNode.getPattern()))) { return nextEditEndpoint(context, xmlResourceName, key, editNode); } else { return nextEditEip(context, xmlResourceName, key, editNode, nodeName); } } private NavigationResult nextEditEndpoint(UINavigationContext context, String xmlResourceName, String key, NodeDto editNode) throws Exception { Map attributeMap = context.getUIContext().getAttributeMap(); // find all endpoints xmlCompleter = createXmlEndpointsCompleter(context.getUIContext(), xmlResourceName::equals); String uri = editNode.getProperty("uri"); LOG.info("Endpoint uri " + uri); CamelEndpointDetails detail = xmlCompleter.getEndpointDetail(uri); LOG.info("Endpoint detail " + detail); if (detail == null) { return null; } attributeMap.put("componentName", detail.getEndpointComponentName()); attributeMap.put("instanceName", detail.getEndpointInstance()); attributeMap.put("endpointUri", detail.getEndpointUri()); attributeMap.put("lineNumber", detail.getLineNumber()); attributeMap.put("lineNumberEnd", detail.getLineNumberEnd()); attributeMap.put("mode", "edit"); attributeMap.put("xml", detail.getFileName()); attributeMap.put("kind", "xml"); // we need to figure out how many options there is so we can as many steps we need String camelComponentName = detail.getEndpointComponentName(); uri = detail.getEndpointUri(); String json = getCamelCatalog().componentJSonSchema(camelComponentName); if (json == null) { throw new IllegalArgumentException("Could not find catalog entry for component name: " + camelComponentName); } LOG.info("Component json: " + json); boolean consumerOnly = detail.isConsumerOnly(); boolean producerOnly = detail.isProducerOnly(); UIContext ui = context.getUIContext(); List groups = createUIInputsForCamelEndpoint(camelComponentName, uri, MAX_OPTIONS, consumerOnly, producerOnly, getCamelCatalog(), componentFactory, converterFactory, ui); // need all inputs in a list as well List allInputs = new ArrayList<>(); for (InputOptionByGroup group : groups) { allInputs.addAll(group.getInputs()); } LOG.info(allInputs.size() + " input fields in the UI wizard"); NavigationResultBuilder builder = Results.navigationBuilder(); int pages = groups.size(); for (int i = 0; i < pages; i++) { boolean last = i == pages - 1; InputOptionByGroup current = groups.get(i); ConfigureEndpointPropertiesStep step = new ConfigureEndpointPropertiesStep(projectFactory, dependencyInstaller, getCamelCatalog(), camelComponentName, current.getGroup(), allInputs, current.getInputs(), last, i, pages); builder.add(step); } NavigationResult navigationResult = builder.build(); attributeMap.put("navigationResult", navigationResult); return navigationResult; } private NavigationResult nextEditEip(UINavigationContext context, String xmlResourceName, String key, NodeDto editNode, String nodeName) throws Exception { Project project = getSelectedProject(context); Map attributeMap = context.getUIContext().getAttributeMap(); Element selectedElement = getSelectedCamelElementNode(project, xmlResourceName, key); if (selectedElement == null) { throw new IllegalArgumentException("Cannot find xml for node " + editNode); } String lineNumber = (String) selectedElement.getUserData(XmlLineNumberParser.LINE_NUMBER); String lineNumberEnd = (String) selectedElement.getUserData(XmlLineNumberParser.LINE_NUMBER_END); attributeMap.put("lineNumber", lineNumber); attributeMap.put("lineNumberEnd", lineNumberEnd); // if we edit a node then it may have children. We should then only edit until the first child starts if (editNode.getChildren() != null && !editNode.getChildren().isEmpty()) { NodeDto child = editNode.getChildren().get(0); Element childElement = getSelectedCamelElementNode(project, xmlResourceName, child.getKey()); String childLineNumber = (String) childElement.getUserData(XmlLineNumberParser.LINE_NUMBER); if (childLineNumber != null) { int num = Integer.valueOf(childLineNumber) - 1; attributeMap.put("lineNumberEnd", "" + num); } attributeMap.put("nodeChildren", "true"); } else { attributeMap.put("nodeChildren", "false"); } // we need to get all the options that are currently configured on the EIP so we have all the current values Map options = new LinkedHashMap<>(); try { ClassLoader cl = CamelCatalog.class.getClassLoader(); // xml -> pojo Object model = xmlAsModel(selectedElement, cl); LOG.info("Pojo model of node: " + model); // extra options from model Map temp = new LinkedHashMap<>(); IntrospectionSupport.getProperties(model, temp, null); for (Map.Entry entry : temp.entrySet()) { String k = entry.getKey(); Object v = entry.getValue(); // skip some we do not want like getOutputs if ("outputs".equals(k)) { continue; } // special for expressions if (v instanceof ExpressionSubElementDefinition) { ExpressionSubElementDefinition sub = (ExpressionSubElementDefinition) v; ExpressionDefinition exp = sub.getExpressionType(); expressionOptions(k, exp, options); } else if (v instanceof ExpressionDefinition) { ExpressionDefinition exp = (ExpressionDefinition) v; expressionOptions(k, exp, options); } else { // convert the value to a text based String text = v != null ? v.toString() : null; if (text != null) { options.put(k, text); } } } } catch (Exception e) { // ignore } LOG.info("Creating UIInputs with options: " + options); UIContext ui = context.getUIContext(); Set possibleLanguageNames = new CamelLanguagesCompleter(project, getCamelCatalog()).getLanguageNamesFromClasspath(); List groups = createUIInputsForCamelEIP(nodeName, MAX_OPTIONS, options, possibleLanguageNames, getCamelCatalog(), componentFactory, converterFactory, ui); // need all inputs in a list as well List allInputs = new ArrayList<>(); for (InputOptionByGroup group : groups) { allInputs.addAll(group.getInputs()); } NavigationResultBuilder builder = Results.navigationBuilder(); int pages = groups.size(); for (int i = 0; i < pages; i++) { boolean last = i == pages - 1; InputOptionByGroup current = groups.get(i); EditNodeXmlStep step = new EditNodeXmlStep(projectFactory, getCamelCatalog(), nodeName, current.getGroup(), allInputs, current.getInputs(), last, i, pages); builder.add(step); } NavigationResult navigationResult = builder.build(); attributeMap.put("navigationResult", navigationResult); return navigationResult; } private void expressionOptions(String k, ExpressionDefinition exp, Map options) { // special for aggregate as it has naming clash if ("completionSizeExpression".equals(k)) { k = "completionSize"; } else if ("completionTimeoutExpression".equals(k)) { k = "completionTimeout"; } String text = exp.getExpression(); String lan = exp.getLanguage(); options.put(k, lan); if (text != null) { options.put(k + "_value", text); } // when using a language as an expression it can contain additional options which we // cannot build a nice UI in forge as forge is not that dynamic. So instead we have an extra // input field where we allow users to edit the values using a Camel multivalue uri style with // key=value&key2=value2 ... CollectionStringBuffer csb = new CollectionStringBuffer("&"); String json = getCamelCatalog().languageJSonSchema(lan); if (json != null) { List> data = JSonSchemaHelper.parseJsonSchema("properties", json, true); if (data != null) { for (Map map : data) { String name = map.get("name"); // skip expression/id as we are not interested in those if (name != null && !"id".equals(name) && !"expression".equals(name)) { try { Object value = IntrospectionSupport.getProperty(exp, name); if (value != null) { text = value.toString(); csb.append(name + "=" + text); } } catch (Exception e) { // ignore } } } } if (!csb.isEmpty()) { String extra = csb.toString(); options.put(k + "_extra", extra); } } } private String getNodeKey(Object value) { if (value instanceof NodeDto) { NodeDto nodeDto = (NodeDto) value; return nodeDto.getKey(); } else if (value instanceof String) { return (String) value; } return null; } @Override public Result execute(UIExecutionContext context) throws Exception { return null; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy