io.fabric8.forge.camel.commands.project.AbstractCamelProjectCommand.java Source code

Java tutorial

Introduction

Here is the source code for io.fabric8.forge.camel.commands.project.AbstractCamelProjectCommand.java

Source

/**
 * Copyright 2005-2015 Red Hat, Inc.
 * <p/>
 * 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
 * <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 io.fabric8.forge.camel.commands.project;

import java.io.File;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import javax.inject.Inject;

import io.fabric8.forge.addon.utils.CamelProjectHelper;
import io.fabric8.forge.camel.commands.project.completer.CurrentLineCompleter;
import io.fabric8.forge.camel.commands.project.completer.RouteBuilderCompleter;
import io.fabric8.forge.camel.commands.project.completer.RouteBuilderEndpointsCompleter;
import io.fabric8.forge.camel.commands.project.completer.SpringBootConfigurationFileCompleter;
import io.fabric8.forge.camel.commands.project.completer.XmlEndpointsCompleter;
import io.fabric8.forge.camel.commands.project.completer.XmlFileCompleter;
import io.fabric8.forge.camel.commands.project.dto.ComponentDto;
import io.fabric8.forge.camel.commands.project.dto.ContextDto;
import io.fabric8.forge.camel.commands.project.dto.NodeDto;
import io.fabric8.forge.camel.commands.project.dto.NodeDtos;
import io.fabric8.forge.camel.commands.project.helper.CamelCommandsHelper;
import io.fabric8.forge.camel.commands.project.helper.CamelXmlHelper;
import io.fabric8.forge.camel.commands.project.helper.PoorMansLogger;
import io.fabric8.utils.Strings;
import org.apache.camel.catalog.CamelCatalog;
import org.jboss.forge.addon.convert.Converter;
import org.jboss.forge.addon.convert.ConverterFactory;
import org.jboss.forge.addon.dependencies.Coordinate;
import org.jboss.forge.addon.dependencies.Dependency;
import org.jboss.forge.addon.dependencies.builder.CoordinateBuilder;
import org.jboss.forge.addon.maven.projects.facets.MavenDependencyFacet;
import org.jboss.forge.addon.parser.java.facets.JavaSourceFacet;
import org.jboss.forge.addon.projects.Project;
import org.jboss.forge.addon.projects.ProjectFactory;
import org.jboss.forge.addon.projects.Projects;
import org.jboss.forge.addon.projects.facets.ResourcesFacet;
import org.jboss.forge.addon.projects.facets.WebResourcesFacet;
import org.jboss.forge.addon.projects.ui.AbstractProjectCommand;
import org.jboss.forge.addon.resource.FileResource;
import org.jboss.forge.addon.ui.context.UIContext;
import org.jboss.forge.addon.ui.context.UIExecutionContext;
import org.jboss.forge.addon.ui.context.UIRegion;
import org.jboss.forge.addon.ui.input.UISelectOne;
import org.jboss.forge.addon.ui.input.ValueChangeListener;
import org.jboss.forge.addon.ui.input.events.ValueChangeEvent;
import org.jboss.forge.addon.ui.metadata.UICommandMetadata;
import org.jboss.forge.addon.ui.util.Categories;
import org.jboss.forge.addon.ui.util.Metadata;
import org.w3c.dom.Element;

import static io.fabric8.forge.addon.utils.VersionHelper.loadText;
import static io.fabric8.forge.camel.commands.project.helper.CollectionHelper.first;

public abstract class AbstractCamelProjectCommand extends AbstractProjectCommand {

    private static final PoorMansLogger LOG = new PoorMansLogger(false);

    public static String CATEGORY = "Camel";
    public static int MAX_OPTIONS = 20;

    @Inject
    protected ProjectFactory projectFactory;

    @Inject
    protected ConverterFactory converterFactory;

    @Inject
    protected CamelCatalog camelCatalog;

    @Override
    protected boolean isProjectRequired() {
        return true;
    }

    @Override
    public UICommandMetadata getMetadata(UIContext context) {
        return Metadata.forCommand(CamelDeleteNodeXmlCommand.class).name("Camel: Delete Node XML")
                .category(Categories.create(CATEGORY)).description("Deletes a node from a Camel XML file");
    }

    @Override
    public boolean isEnabled(UIContext context) {
        boolean enabled = super.isEnabled(context);
        if (!enabled) {
            return false;
        }
        if (requiresCamelSetup()) {
            // requires camel is already setup
            Project project = getSelectedProjectOrNull(context);
            if (project != null) {
                return findCamelCoreDependency(project) != null;
            }
        }
        return false;
    }

    protected Project getSelectedProjectOrNull(UIContext context) {
        return Projects.getSelectedProject(this.getProjectFactory(), context);
    }

    protected boolean isRunningInGui(UIContext context) {
        return context.getProvider().isGUI();
    }

    protected boolean requiresCamelSetup() {
        return true;
    }

    protected List<NodeDto> configureXmlNodes(final UIContext context, final Project project, final String selected,
            final UISelectOne<String> xml, final UISelectOne<String> node) throws Exception {

        // because the UISelectOne must be unique we need to use a running number
        int index = 1;

        List<NodeDto> nodes;

        String xmlResourceName = xml.getValue();
        if (Strings.isNullOrBlank(xmlResourceName)) {
            xmlResourceName = selected;
        }
        if (Strings.isNotBlank(xmlResourceName)) {
            List<ContextDto> camelContexts = CamelXmlHelper.loadCamelContext(camelCatalog, context, project,
                    xmlResourceName);
            nodes = NodeDtos.toNodeList(camelContexts);
            // if there is one CamelContext then pre-select the first node (which is the route)
            if (camelContexts.size() == 1 && nodes.size() > 1) {
                node.setDefaultValue("1 " + nodes.get(1).getLabel());
            }
        } else {
            nodes = Collections.EMPTY_LIST;
        }

        final List<NodeDto> answer = nodes;

        List<String> choices = new ArrayList<>();
        for (NodeDto dto : nodes) {
            choices.add(index + " " + dto.getLabel());
            index++;
        }
        node.setValueChoices(choices);
        // to convert from key to label (with number)
        // this converter is needed for the web console as it uses the key to select which node to edit
        // and we need to be able to convert from the key to the correct node in the list
        node.setValueConverter(s -> {
            for (int i = 0; i < answer.size(); i++) {
                NodeDto dto = answer.get(i);
                if (dto.getKey().equals(s)) {
                    int number = i + 1;
                    return number + " " + dto.getLabel();
                }
            }
            return s;
        });

        return answer;
    }

    @Override
    protected ProjectFactory getProjectFactory() {
        return projectFactory;
    }

    protected ConverterFactory getConverterFactory() {
        return converterFactory;
    }

    protected CamelCatalog getCamelCatalog() {
        return camelCatalog;
    }

    protected PrintStream getOutput(UIExecutionContext context) {
        return context.getUIContext().getProvider().getOutput().out();
    }

    protected boolean isCamelProject(Project project) {
        // is there any camel dependency?
        return !findCamelArtifacts(project).isEmpty();
    }

    protected boolean isSpringBootProject(Project project) {
        return CamelProjectHelper.hasDependency(project, "org.springframework.boot");
    }

    protected Dependency findCamelCoreDependency(Project project) {
        return CamelProjectHelper.findCamelCoreDependency(project);
    }

    protected Set<Dependency> findCamelArtifacts(Project project) {
        return CamelProjectHelper.findCamelArtifacts(project);
    }

    protected Coordinate createCoordinate(String groupId, String artifactId, String version) {
        CoordinateBuilder builder = CoordinateBuilder.create().setGroupId(groupId).setArtifactId(artifactId);
        if (version != null) {
            builder = builder.setVersion(version);
        }

        return builder;
    }

    protected Coordinate createCamelCoordinate(String artifactId, String version) {
        return createCoordinate("org.apache.camel", artifactId, version);
    }

    protected RouteBuilderCompleter createRouteBuilderCompleter(Project project) {
        JavaSourceFacet facet = project.getFacet(JavaSourceFacet.class);
        return new RouteBuilderCompleter(facet);
    }

    protected RouteBuilderEndpointsCompleter createRouteBuilderEndpointsCompleter(UIContext context,
            Function<String, Boolean> filter) {
        Project project = getSelectedProject(context);
        return createRouteBuilderEndpointsCompleter(project, filter);
    }

    protected RouteBuilderEndpointsCompleter createRouteBuilderEndpointsCompleter(Project project,
            Function<String, Boolean> filter) {
        JavaSourceFacet facet = project.getFacet(JavaSourceFacet.class);
        return new RouteBuilderEndpointsCompleter(facet, filter);
    }

    protected XmlEndpointsCompleter createXmlEndpointsCompleter(UIContext context,
            Function<String, Boolean> filter) {
        Project project = getSelectedProject(context);
        return createXmlEndpointsCompleter(project, filter);
    }

    protected XmlEndpointsCompleter createXmlEndpointsCompleter(Project project, Function<String, Boolean> filter) {
        ResourcesFacet resourcesFacet = null;
        WebResourcesFacet webResourcesFacet = null;
        if (project.hasFacet(ResourcesFacet.class)) {
            resourcesFacet = project.getFacet(ResourcesFacet.class);
        }
        if (project.hasFacet(WebResourcesFacet.class)) {
            webResourcesFacet = project.getFacet(WebResourcesFacet.class);
        }

        return new XmlEndpointsCompleter(resourcesFacet, webResourcesFacet, filter);
    }

    protected XmlFileCompleter createXmlFileCompleter(Project project, Function<String, Boolean> filter) {
        ResourcesFacet resourcesFacet = null;
        WebResourcesFacet webResourcesFacet = null;
        if (project.hasFacet(ResourcesFacet.class)) {
            resourcesFacet = project.getFacet(ResourcesFacet.class);
        }
        if (project.hasFacet(WebResourcesFacet.class)) {
            webResourcesFacet = project.getFacet(WebResourcesFacet.class);
        }

        return new XmlFileCompleter(resourcesFacet, webResourcesFacet, filter);
    }

    protected XmlFileCompleter createXmlFileCompleter(UIContext context, Function<String, Boolean> filter) {
        Project project = getSelectedProject(context);
        return createXmlFileCompleter(project, filter);
    }

    protected SpringBootConfigurationFileCompleter createSpringBootConfigurationFileCompleter(UIContext context,
            Function<String, Boolean> filter) {
        Project project = getSelectedProject(context);
        ResourcesFacet resourcesFacet = null;
        if (project.hasFacet(ResourcesFacet.class)) {
            resourcesFacet = project.getFacet(ResourcesFacet.class);
        }
        return new SpringBootConfigurationFileCompleter(resourcesFacet, filter);
    }

    protected CurrentLineCompleter createCurrentLineCompleter(int lineNumber, String file, UIContext context)
            throws Exception {
        Project project = getSelectedProject(context);

        JavaSourceFacet sourceFacet = null;
        ResourcesFacet resourcesFacet = null;
        WebResourcesFacet webResourcesFacet = null;
        if (project.hasFacet(JavaSourceFacet.class)) {
            sourceFacet = project.getFacet(JavaSourceFacet.class);
        }
        if (project.hasFacet(ResourcesFacet.class)) {
            resourcesFacet = project.getFacet(ResourcesFacet.class);
        }
        if (project.hasFacet(WebResourcesFacet.class)) {
            webResourcesFacet = project.getFacet(WebResourcesFacet.class);
        }

        String relativeFile = asRelativeFile(context, file);
        return new CurrentLineCompleter(lineNumber, relativeFile, sourceFacet, resourcesFacet, webResourcesFacet);
    }

    protected FileResource getXmlResourceFile(Project project, String xmlResourceName) {
        if (xmlResourceName == null) {
            return null;
        }

        ResourcesFacet facet = null;
        WebResourcesFacet webResourcesFacet = null;
        if (project.hasFacet(ResourcesFacet.class)) {
            facet = project.getFacet(ResourcesFacet.class);
        }
        if (project.hasFacet(WebResourcesFacet.class)) {
            webResourcesFacet = project.getFacet(WebResourcesFacet.class);
        }

        FileResource file = facet != null ? facet.getResource(xmlResourceName) : null;
        if (file == null || !file.exists()) {
            file = webResourcesFacet != null ? webResourcesFacet.getWebResource(xmlResourceName) : null;
        }
        return file;
    }

    protected String configureXml(Project project, UISelectOne<String> xml, String currentFile) {
        XmlFileCompleter xmlFileCompleter = createXmlFileCompleter(project, null);
        Set<String> files = xmlFileCompleter.getFiles();

        // use value choices instead of completer as that works better in web console
        final String first = first(files);
        String answer = first;

        xml.setValueChoices(files);
        if (files.size() == 1) {
            // lets default the value if there's only one choice
            xml.setDefaultValue(first);
        } else if (currentFile != null) {
            // lets default to the current file
            for (String name : files) {
                if (currentFile.endsWith(name)) {
                    xml.setDefaultValue(name);
                    answer = name;
                    break;
                }
            }
        }
        return answer;
    }

    protected String configureRouteBuilder(Project project, UISelectOne<String> routeBuilders, String currentFile) {
        RouteBuilderCompleter completer = createRouteBuilderCompleter(project);
        Set<String> builders = completer.getRouteBuilders();

        // use value choices instead of completer as that works better in web console
        final String first = first(builders);
        String answer = first;

        routeBuilders.setValueChoices(builders);
        if (builders.size() == 1) {
            // lets default the value if there's only one choice
            routeBuilders.setDefaultValue(first);
        } else if (currentFile != null) {
            // lets default to the current file
            if (currentFile.endsWith(".java")) {
                currentFile = currentFile.substring(0, currentFile.length() - 5);
            }
            for (String name : builders) {
                if (currentFile.endsWith(name)) {
                    routeBuilders.setDefaultValue(name);
                    answer = name;
                    break;
                }
            }
        }
        return answer;
    }

    protected void configureComponentName(Project project, final UISelectOne<ComponentDto> componentName,
            boolean consumerOnly, boolean producerOnly) throws Exception {

        // filter the list of components based on consumer and producer only
        Iterable<ComponentDto> it = CamelCommandsHelper.createComponentDtoValues(project, getCamelCatalog(), null,
                false, consumerOnly, producerOnly, false).call();
        final Map<String, ComponentDto> components = new LinkedHashMap<>();
        for (ComponentDto dto : it) {
            components.put(dto.getScheme(), dto);
        }

        componentName.setValueChoices(components.values());
        // include converter from string->dto
        componentName.setValueConverter(new Converter<String, ComponentDto>() {
            @Override
            public ComponentDto convert(String text) {
                return components.get(text);
            }
        });
        // show note about the chosen component
        componentName.addValueChangeListener(new ValueChangeListener() {
            @Override
            public void valueChanged(ValueChangeEvent event) {
                ComponentDto component = (ComponentDto) event.getNewValue();
                if (component != null) {
                    String description = component.getDescription();
                    componentName.setNote(description != null ? description : "");
                } else {
                    componentName.setNote("");
                }
            }
        });
    }

    protected Element getSelectedCamelElementNode(Project project, String xmlResourceName, String key)
            throws Exception {
        FileResource file = getXmlResourceFile(project, xmlResourceName);
        if (file != null) {
            InputStream resourceInputStream = file.getResourceInputStream();
            return CamelXmlHelper.getSelectedCamelElementNode(key, resourceInputStream);
        } else {
            return null;
        }
    }

    protected String getSelectedFile(UIContext context) {
        String currentFile = null;
        // get selected file
        Optional<UIRegion<Object>> region = context.getSelection().getRegion();
        if (region.isPresent()) {
            Object resource = region.get().getResource();
            currentFile = resource.toString();
        }
        return currentFile;
    }

    protected boolean isSelectedFileJava(UIContext context) {
        Optional<UIRegion<Object>> region = context.getSelection().getRegion();
        if (region.isPresent()) {
            Object resource = region.get().getResource();
            if (resource instanceof FileResource) {
                return ((FileResource) resource).getFullyQualifiedName().endsWith(".java");
            }
        }
        return false;
    }

    protected boolean isSelectedFileXml(UIContext context) {
        Optional<UIRegion<Object>> region = context.getSelection().getRegion();
        if (region.isPresent()) {
            Object resource = region.get().getResource();
            if (resource instanceof FileResource) {
                return ((FileResource) resource).getFullyQualifiedName().endsWith(".xml");
            }
        }
        return false;
    }

    protected int getCurrentCursorLine(UIContext context) {
        int answer = -1;
        Optional<UIRegion<Object>> region = context.getSelection().getRegion();
        if (region.isPresent()) {
            answer = region.get().getStartLine();
        }
        return answer;
    }

    protected int getCurrentCursorPosition(UIContext context) {
        int answer = -1;
        Optional<UIRegion<Object>> region = context.getSelection().getRegion();
        if (region.isPresent()) {
            answer = region.get().getStartPosition();
        }
        return answer;
    }

    protected String asRelativeFile(UIContext context, String currentFile) {
        Project project = getSelectedProject(context);

        JavaSourceFacet javaSourceFacet = null;
        ResourcesFacet resourcesFacet = null;
        WebResourcesFacet webResourcesFacet = null;
        if (project.hasFacet(JavaSourceFacet.class)) {
            javaSourceFacet = project.getFacet(JavaSourceFacet.class);
        }
        if (project.hasFacet(ResourcesFacet.class)) {
            resourcesFacet = project.getFacet(ResourcesFacet.class);
        }
        if (project.hasFacet(WebResourcesFacet.class)) {
            webResourcesFacet = project.getFacet(WebResourcesFacet.class);
        }
        return asRelativeFile(currentFile, javaSourceFacet, resourcesFacet, webResourcesFacet);
    }

    public static String asRelativeFile(String currentFile, JavaSourceFacet javaSourceFacet,
            ResourcesFacet resourcesFacet, WebResourcesFacet webResourcesFacet) {
        boolean javaFile = currentFile != null && currentFile.endsWith(".java");

        // if its not a java file, then we need to have the relative path name
        String target = null;
        if (javaFile && javaSourceFacet != null) {
            // we only want the relative dir name from the source directory, eg src/main/java
            String baseDir = javaSourceFacet.getSourceDirectory().getFullyQualifiedName();
            String fqn = currentFile;
            if (fqn != null && fqn.startsWith(baseDir) && fqn.length() > baseDir.length()) {
                target = fqn.substring(baseDir.length() + 1);
            }
            // could be in test directory
            if (target == null) {
                // we only want the relative dir name from the source directory, eg src/test/java
                baseDir = javaSourceFacet.getTestSourceDirectory().getFullyQualifiedName();
                fqn = currentFile;
                if (fqn != null && fqn.startsWith(baseDir) && fqn.length() > baseDir.length()) {
                    target = fqn.substring(baseDir.length() + 1);
                }
            }
        } else if (resourcesFacet != null || webResourcesFacet != null) {
            if (resourcesFacet != null) {
                // we only want the relative dir name from the resource directory, eg src/main/resources
                String baseDir = resourcesFacet.getResourceDirectory().getFullyQualifiedName();
                String fqn = currentFile;
                if (fqn != null && fqn.startsWith(baseDir) && fqn.length() > baseDir.length()) {
                    target = fqn.substring(baseDir.length() + 1);
                }
            }
            if (target == null && webResourcesFacet != null) {
                // we only want the relative dir name from the web resource directory, eg WEB-INF/foo.xml
                String baseDir = webResourcesFacet.getWebRootDirectory().getFullyQualifiedName();
                String fqn = currentFile;
                if (fqn != null && fqn.startsWith(baseDir) && fqn.length() > baseDir.length()) {
                    target = fqn.substring(baseDir.length() + 1);
                }
            }
        }

        return target != null ? target : currentFile;
    }

    protected Set<String> discoverCustomCamelComponentsOnClasspathAndAddToCatalog(CamelCatalog camelCatalog,
            Project project) {
        Set<String> answer = new LinkedHashSet<>();

        // find the dependency again because forge don't associate artifact on the returned dependency when installed
        MavenDependencyFacet facet = project.getFacet(MavenDependencyFacet.class);
        List<Dependency> list = facet.getEffectiveDependencies();

        for (Dependency dep : list) {
            Properties properties = loadComponentProperties(dep);
            if (properties != null) {
                String components = (String) properties.get("components");
                if (components != null) {
                    String[] part = components.split("\\s");
                    for (String scheme : part) {
                        if (!camelCatalog.findComponentNames().contains(scheme)) {
                            // find the class name
                            String javaType = extractComponentJavaType(dep, scheme);
                            if (javaType != null) {
                                String json = loadComponentJSonSchema(dep, scheme);
                                if (json != null) {
                                    camelCatalog.addComponent(scheme, javaType, json);
                                    answer.add(scheme);
                                }
                            }
                        }
                    }
                }
            }
        }

        return answer;
    }

    public static Properties loadComponentProperties(Dependency dependency) {
        Properties answer = new Properties();

        try {
            // is it a JAR file
            File file = dependency.getArtifact().getUnderlyingResourceObject();
            if (file != null && file.getName().toLowerCase().endsWith(".jar")) {
                URL url = new URL("file:" + file.getAbsolutePath());
                URLClassLoader child = new URLClassLoader(new URL[] { url });

                InputStream is = child
                        .getResourceAsStream("META-INF/services/org/apache/camel/component.properties");
                if (is != null) {
                    answer.load(is);
                }
            }
        } catch (Throwable e) {
            // ignore
        }

        return answer;
    }

    public static String loadComponentJSonSchema(Dependency dependency, String scheme) {
        String answer = null;

        String path = null;
        String javaType = extractComponentJavaType(dependency, scheme);
        if (javaType != null) {
            int pos = javaType.lastIndexOf(".");
            path = javaType.substring(0, pos);
            path = path.replace('.', '/');
            path = path + "/" + scheme + ".json";
        }

        if (path != null) {
            try {
                // is it a JAR file
                File file = dependency.getArtifact().getUnderlyingResourceObject();
                if (file != null && file.getName().toLowerCase().endsWith(".jar")) {
                    URL url = new URL("file:" + file.getAbsolutePath());
                    URLClassLoader child = new URLClassLoader(new URL[] { url });

                    InputStream is = child.getResourceAsStream(path);
                    if (is != null) {
                        answer = loadText(is);
                    }
                }
            } catch (Throwable e) {
                // ignore
            }
        }

        return answer;
    }

    public static String extractComponentJavaType(Dependency dependency, String scheme) {
        try {
            // is it a JAR file
            File file = dependency.getArtifact().getUnderlyingResourceObject();
            if (file != null && file.getName().toLowerCase().endsWith(".jar")) {
                URL url = new URL("file:" + file.getAbsolutePath());
                URLClassLoader child = new URLClassLoader(new URL[] { url });

                InputStream is = child
                        .getResourceAsStream("META-INF/services/org/apache/camel/component/" + scheme);
                if (is != null) {
                    Properties props = new Properties();
                    props.load(is);
                    return (String) props.get("class");
                }
            }
        } catch (Throwable e) {
            // ignore
        }

        return null;
    }

}