org.apache.camel.idea.completion.extension.YamlPropertyPlaceholdersSmartCompletion.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.camel.idea.completion.extension.YamlPropertyPlaceholdersSmartCompletion.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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 org.apache.camel.idea.completion.extension;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.PlainPrefixMatcher;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import org.apache.camel.idea.service.CamelPreferenceService;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.Yaml;

/**
 * To support smart completion where properties are loaded from <tt>.yaml</tt> files.
 * <p/>
 * Smart completion for editing a Camel endpoint uri, to show a list of YAML properties can be added.
 * For example editing <tt>jms:queue?{{_CURSOR_HERE_</tt>. Which presents the user
 * with a list of possible properties.
 */
public class YamlPropertyPlaceholdersSmartCompletion implements CamelPropertyCompletion {

    private static final Logger LOG = Logger.getInstance(YamlPropertyPlaceholdersSmartCompletion.class);

    @NotNull
    @SuppressWarnings("unchecked")
    private Map<String, Object> getProperties(VirtualFile virtualFile) {
        Map<String, Object> result = new HashMap<>();
        Yaml yaml = new Yaml();
        try {
            // Parse the YAML file and return the output as a series of Maps and Lists
            result = (Map<String, Object>) yaml.load(virtualFile.getInputStream());
        } catch (Exception e) {
            LOG.warn("Error loading yaml file: " + virtualFile, e);
        }
        return result;
    }

    @Override
    public boolean isValidExtension(String filename) {
        final CamelPreferenceService preferenceService = ServiceManager.getService(CamelPreferenceService.class);
        final boolean present = preferenceService.getExcludePropertyFiles().stream()
                .filter(s -> !s.isEmpty() && FilenameUtils.wildcardMatch(filename, s)).findFirst().isPresent();
        return (!present) && (filename.endsWith(".yaml") || filename.endsWith(".yml"));
    }

    @Override
    public void buildResultSet(CompletionResultSet resultSet, VirtualFile virtualFile) {
        getProperties(virtualFile).forEach((key, value) -> {
            final String keyStr = key;
            if (!isIgnored(key)) {
                if (value instanceof List) {
                    buildResultSetForList(resultSet, virtualFile, keyStr, (List) value);
                } else if (value instanceof LinkedHashMap) {
                    buildResultSetForLinkedHashMap(resultSet, virtualFile, keyStr,
                            Collections.singletonList(value));
                } else {
                    buildResultSet(resultSet, virtualFile, keyStr, String.valueOf(value));
                }
            }
        });
    }

    /**
     * Flat the {@link LinkedHashMap} to string property names and build the {@link CompletionResultSet}
     */
    @SuppressWarnings("unchecked")
    private void buildResultSetForLinkedHashMap(CompletionResultSet resultSet, VirtualFile virtualFile,
            String keyStr, List<?> propertyList) {
        propertyList.stream().filter(l -> l instanceof LinkedHashMap).map(LinkedHashMap.class::cast)
                .flatMap(lhm -> lhm.entrySet().stream()).forEach(e -> {
                    Map.Entry<String, Object> entry = (Map.Entry<String, Object>) e;
                    String flatKeyStr = keyStr + "." + String.valueOf(entry.getKey());
                    if (entry.getValue() instanceof List) {
                        buildResultSetForList(resultSet, virtualFile, flatKeyStr, (List<?>) entry.getValue());
                    } else if (entry.getValue() instanceof LinkedHashMap) {
                        buildResultSetForLinkedHashMap(resultSet, virtualFile, flatKeyStr,
                                Collections.singletonList(entry.getValue()));
                    } else {
                        buildResultSet(resultSet, virtualFile, flatKeyStr, String.valueOf(entry.getValue()));
                    }
                }

        );
    }

    /**
     * Flat the List to string array and build the {@link CompletionResultSet}
     */
    private void buildResultSetForList(CompletionResultSet resultSet, VirtualFile virtualFile, String keyStr,
            List<?> propertyList) {
        final AtomicInteger count = new AtomicInteger(0);
        propertyList.forEach(e -> {
            if (e instanceof String) {
                String flatKeyStr = String.format("%s[%s]", keyStr, count.getAndIncrement());
                buildResultSet(resultSet, virtualFile, flatKeyStr, String.valueOf(e));
            } else if (e instanceof List) {
                buildResultSetForList(resultSet, virtualFile, keyStr, (List<?>) e);
            } else if (e instanceof LinkedHashMap) {
                buildResultSetForLinkedHashMap(resultSet, virtualFile, keyStr, propertyList);
            }
        });
    }

    private void buildResultSet(CompletionResultSet resultSet, VirtualFile virtualFile, String keyStr,
            String value) {
        if (!isIgnored(keyStr)) {
            LookupElementBuilder builder = LookupElementBuilder.create(keyStr + "}}").appendTailText(value, true)
                    .withTypeText("[" + virtualFile.getPresentableName() + "]", true)
                    .withPresentableText(keyStr + " = ");
            resultSet.withPrefixMatcher(new PlainPrefixMatcher("")).addElement(builder);
        }
    }
}