Java tutorial
/** * 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; } }