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

io.syndesis.dv.lsp.completion.providers.MetadataItemProvider Maven / Gradle / Ivy

Go to download

Tool that allows creating, editing and managing dynamic VDBs for the Teiid OpenShift Deployment.

The newest version!
/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed 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.syndesis.dv.lsp.completion.providers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.teiid.query.parser.SQLParserConstants;
import org.teiid.query.parser.Token;

import io.syndesis.dv.lsp.TeiidDdlWorkspaceService;
import io.syndesis.dv.lsp.completion.providers.items.MetadataCompletionItem;
import io.syndesis.dv.lsp.parser.DdlAnalyzerConstants.Context;
import io.syndesis.dv.lsp.parser.DdlAnalyzerConstants.MetadataType;
import io.syndesis.dv.lsp.parser.statement.AbstractStatementObject;
import io.syndesis.dv.lsp.parser.statement.CreateViewStatement;
import io.syndesis.dv.lsp.parser.statement.FromClause;
import io.syndesis.dv.lsp.parser.statement.TableSymbol;
import io.syndesis.dv.lsp.parser.statement.TokenContext;
import io.syndesis.dv.server.endpoint.MetadataService;
import io.syndesis.dv.server.endpoint.RestSourceColumn;
import io.syndesis.dv.server.endpoint.RestSourceSchema;
import io.syndesis.dv.server.endpoint.RestSourceTable;
import io.syndesis.dv.server.endpoint.RestViewSourceInfo;

@SuppressWarnings("PMD.GodClass")
public class MetadataItemProvider extends CompletionItemBuilder {
    private static final Logger LOGGER = LoggerFactory.getLogger(MetadataItemProvider.class);

    private static final boolean DO_PRINT_TO_CONSOLE = false;
    CreateViewStatement statement;
    MetadataService metadataService;
    TeiidDdlWorkspaceService workspaceService;

    public MetadataItemProvider(CreateViewStatement statement, MetadataService metadataService,
            TeiidDdlWorkspaceService workspaceService) {
        super();
        this.statement = statement;
        this.metadataService = metadataService;
        this.workspaceService = workspaceService;
    }

    public List getCompletionItems(TokenContext context) {
        String virtualizationName = context.getVirtualizationId();
        return getCompletionItems(context, virtualizationName);
    }

    public List getAllMetadataCompletionItems(String virtualizationName, String viewName) {
        RestViewSourceInfo schemaInfo = getRuntimeMetadata(virtualizationName);

        if (schemaInfo != null) {
            return createItems(schemaInfo, virtualizationName, viewName);
        }

        return Collections.emptyList();
    }

    public List getCompletionItems(TokenContext context, String virtualizationName) {
        List allMetadataItems = this.getAllMetadataCompletionItems(virtualizationName,
                this.statement.getViewName());

        List returnItems = new ArrayList();

        AbstractStatementObject targetObject = context.getTargetObject();

        if (targetObject instanceof TableSymbol && context.getToken().kind == SQLParserConstants.COMMA) {
            // Add all items that are of types:
            // SchemaName.TableName
            // TableName
            List allowableTypes = new ArrayList();
            allowableTypes.add(MetadataType.TABLE);
            allowableTypes.add(MetadataType.SCHEMA_TABLE);
            List filteredItems = filterCompletionItems(allMetadataItems, allowableTypes, false);
            returnItems.addAll(filteredItems);
        } else {
            switch (context.getContext()) {
                case SELECT_CLAUSE:
                case SELECT_COLUMN:
                case FUNCTION: {
                    processSelectClause(allMetadataItems, returnItems);
                }
                    break;
                case FROM_CLAUSE:
                case TABLE_SYMBOL: {
                    processFromClause(context, allMetadataItems, returnItems);
                }
                    break;
                case WHERE_CLAUSE_TABLE_ALIAS:
                case WHERE_CLAUSE: {
                    processWhereClause(context, allMetadataItems, returnItems);
                }
                    break;
                case QUERY_EXPRESSION: {
                    returnItems.addAll(filterCompletionItems(allMetadataItems, null, false));
                }
                    break;
                case TABLE_ALIAS: {
                    processForTableAlias(context, allMetadataItems, returnItems);
                }
                    break;
                default:
                    break;
            }
        }

        logDebug("  RETURNING [ " + returnItems.size() + " ] METADATA ITEMS for CONTEXT = " + context.contextToString());
        if (DO_PRINT_TO_CONSOLE) {
            for (CompletionItem item : returnItems) {
                logDebug(" >>  ITEM = " + item.getLabel());
            }
        }
        return returnItems;
    }

    private void processFromClause(TokenContext context, List allMetadataItems,
            List returnItems) {
        AbstractStatementObject targetObject = context.getTargetObject();
        Token targetToken = context.getToken();
        if (targetObject instanceof FromClause) {
            // Add all items that are of types:
            // SchemaName.TableName
            // TableName
            List allowableTypes = new ArrayList();
            allowableTypes.add(MetadataType.TABLE);
            allowableTypes.add(MetadataType.SCHEMA_TABLE);
            List filteredItems = filterCompletionItems(allMetadataItems, allowableTypes, false);
            returnItems.addAll(filteredItems);
        } else if (targetObject instanceof TableSymbol) {
            // TableSymbol to = (TableSymbol)targetObject;
            if (targetToken.kind == SQLParserConstants.ID || targetToken.kind == SQLParserConstants.STRINGVAL) {
                String[] values = { "AS" };
                returnItems.addAll(generateCompletionItems(values));
            } else if (targetToken.kind == SQLParserConstants.COMMA) {
                List allowableTypes = new ArrayList();
                allowableTypes.add(MetadataType.TABLE);
                allowableTypes.add(MetadataType.SCHEMA_TABLE);
                List filteredItems = filterCompletionItems(allMetadataItems, allowableTypes, false);
                returnItems.addAll(filteredItems);
            }
        }
    }

    private void processSelectClause(List allMetadataItems, List returnItems) {
        List allowableTypes = new ArrayList();
        allowableTypes.add(MetadataType.COLUMN);
        allowableTypes.add(MetadataType.TABLE_COLUMN);
        List filteredItems = filterCompletionItems(allMetadataItems, allowableTypes, true);
        returnItems.addAll(filteredItems);
    }

    public List getOnlyColumnMetadataItems(String virtualizationName) {
        List allowableTypes = new ArrayList();
        allowableTypes.add(MetadataType.COLUMN);
        return filterCompletionItems(
                this.getAllMetadataCompletionItems(virtualizationName, this.statement.getViewName()), allowableTypes,
                true);
    }

    private void processWhereClause(TokenContext context, List allMetadataItems,
            List returnItems) {
        if (context.getContext() == Context.WHERE_CLAUSE_TABLE_ALIAS) {
            String aliasTableName = context.getToken().image;
            logDebug("  MIP >>>  CONTEXT = TABLE_ALIAS   name = " + aliasTableName);
            List filteredItems = filterCompletionItemsForTableAlias(allMetadataItems, aliasTableName);
            returnItems.addAll(filteredItems);
        } else {
            List allowableTypes = new ArrayList();
            allowableTypes.add(MetadataType.COLUMN);
            allowableTypes.add(MetadataType.TABLE_COLUMN);
            returnItems.addAll(filterCompletionItems(allMetadataItems, allowableTypes, true));
        }
    }

    private void processForTableAlias(TokenContext context, List allMetadataItems,
            List returnItems) {
        // We've identified that the focused token is a '.' PERIOD character proceeded
        // by a defined table alias
        String aliasTableName = context.getToken().image;
        logDebug("  MIP >>>  CONTEXT = TABLE_ALIAS   name = " + aliasTableName);
        List filteredItems = filterCompletionItemsForTableAlias(allMetadataItems, aliasTableName);
        returnItems.addAll(filteredItems);
    }

    private static String getFQName(RestSourceSchema schema, RestSourceTable table, RestSourceColumn column) {
        return new StringBuilder().append(schema.getName()).append('.').append(table.getName()).append('.')
                .append(column.getName()).toString();
    }

    private static String getFQName(RestSourceSchema schema, RestSourceTable table) {
        return new StringBuilder().append(schema.getName()).append('.').append(table.getName()).toString();
    }

    private static String getFQName(RestSourceTable table, RestSourceColumn column) {
        return new StringBuilder().append(table.getName()).append('.').append(column.getName()).toString();
    }

    public static List createItems(RestViewSourceInfo schemaInfo, String virtualizationName,
            String viewName) {
        List items = new ArrayList();

        logDebug("  MetadataItemProvider.createItems() for >>  virtualizationName = " + virtualizationName
                + "  viewName = " + viewName);

        if (schemaInfo == null) {
            logDebug("No metadata items returned. SCHEMA INFO == NULL");
            return items;
        }

        Set allLabels = new HashSet();

        for (RestSourceSchema nextSchema : schemaInfo.getSchemas()) {

            CompletionItem schemaItem = new CompletionItem(nextSchema.getName());
            schemaItem.setKind(CompletionItemKind.Text);
            schemaItem.setSortText(SORT_WEIGHT_1080);
            MetadataCompletionItem metadataCompetionItem = new MetadataCompletionItem(schemaItem, MetadataType.SCHEMA,
                    nextSchema.getName(), null, null);
            addItem(items, allLabels, metadataCompetionItem);

            for (RestSourceTable nextTable : nextSchema.getTables()) {

                // We don't want to return items for the targeted View Definition
                // 1) Check the nextTable name == viewName
                // 2) Check the virtualizationName with the
                // 3) If they both match, then call break; to skip generation

                boolean doNextTable = true;

                if (virtualizationName != null && virtualizationName.equalsIgnoreCase(nextSchema.getName())) {
                    doNextTable = !nextTable.getName().equalsIgnoreCase(viewName);
                }

                if (doNextTable) {
                    CompletionItem tableItem = new CompletionItem(nextTable.getName());
                    tableItem.setKind(CompletionItemKind.Text);
                    metadataCompetionItem = new MetadataCompletionItem(tableItem, MetadataType.TABLE,
                            nextSchema.getName(), nextTable.getName(), null);
                    setSortText(metadataCompetionItem);
                    addItem(items, allLabels, metadataCompetionItem);

                    CompletionItem schemaTableItem = new CompletionItem(getFQName(nextSchema, nextTable));
                    schemaTableItem.setKind(CompletionItemKind.Text);
                    schemaTableItem.setSortText(SORT_WEIGHT_1080);
                    metadataCompetionItem = new MetadataCompletionItem(schemaTableItem, MetadataType.SCHEMA_TABLE,
                            nextSchema.getName(), nextTable.getName(), null);
                    setSortText(metadataCompetionItem);
                    addItem(items, allLabels, metadataCompetionItem);

                    for (RestSourceColumn nextColumn : nextTable.getColumns()) {
                        CompletionItem columnItem = new CompletionItem(nextColumn.getName());
                        columnItem.setKind(CompletionItemKind.Text);
                        columnItem.setSortText(SORT_WEIGHT_1050);
                        metadataCompetionItem = new MetadataCompletionItem(columnItem, MetadataType.COLUMN,
                                nextSchema.getName(), nextTable.getName(), nextColumn.getName());
                        setSortText(metadataCompetionItem);
                        addItem(items, allLabels, metadataCompetionItem);

                        CompletionItem tableColumnItem = new CompletionItem(getFQName(nextTable, nextColumn));
                        tableColumnItem.setKind(CompletionItemKind.Text);
                        tableColumnItem.setSortText(SORT_WEIGHT_1080);
                        metadataCompetionItem = new MetadataCompletionItem(tableColumnItem, MetadataType.TABLE_COLUMN,
                                nextSchema.getName(), nextTable.getName(), nextColumn.getName());
                        setSortText(metadataCompetionItem);
                        addItem(items, allLabels, metadataCompetionItem);

                        CompletionItem schemaTableColumnItem = new CompletionItem(
                                getFQName(nextSchema, nextTable, nextColumn));
                        schemaTableColumnItem.setKind(CompletionItemKind.Text);
                        schemaTableColumnItem.setSortText(SORT_WEIGHT_1100);
                        metadataCompetionItem = new MetadataCompletionItem(schemaTableColumnItem,
                                MetadataType.SCHEMA_TABLE_COLUMN, nextSchema.getName(), nextTable.getName(),
                                nextColumn.getName());
                        setSortText(metadataCompetionItem);
                        addItem(items, allLabels, metadataCompetionItem);
                    }
                }
            }
        }
        logDebug("  RETURNING [ " + items.size() + " ] MetadataCompletionItems from createItems() ");
        return items;
    }

    private static void setSortText(MetadataCompletionItem metaItem) {
        if (metaItem.getMetadataType() == MetadataType.COLUMN) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1050);
        } else if (metaItem.getMetadataType() == MetadataType.TABLE) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1060);
        } else if (metaItem.getMetadataType() == MetadataType.SCHEMA) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1090);
        } else if (metaItem.getMetadataType() == MetadataType.TABLE_COLUMN) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1070);
        } else if (metaItem.getMetadataType() == MetadataType.SCHEMA_TABLE) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1080);
        } else if (metaItem.getMetadataType() == MetadataType.SCHEMA_TABLE_COLUMN) {
            metaItem.getCompletionItem().setSortText(SORT_WEIGHT_1100);
        }
    }

    private static void addItem(List items, Set allLabels,
            MetadataCompletionItem newItem) {
        if (!allLabels.contains(newItem.getCompletionItem().getLabel())) {
            allLabels.add(newItem.getCompletionItem().getLabel());
            items.add(newItem);
            logDebug("  addItem() : \n" + newItem);
        } else {
            // Note that we can only return 1 item with each label/string
            // However different tables might have same column names
            // So if duplicate label, tag the item as cached duplicate
            // This can be used to check items later for aliased tables
            if (newItem.getMetadataType() == MetadataType.COLUMN) {
                newItem.setCachedDuplicate(true);
                items.add(newItem);
                logDebug("  addItem()  Cached Duplicate: \n" + newItem);
            }
        }
    }

    /**
     * This method filters the metadata items based on: 1) allowable types 2)
     * statement context based on position and relevant token(s) within the
     * statement 3)
     *
     * @param metadataItems
     * @param allowableTypes
     * @param checkSchemaScope - filter columns that aren't referenced in the
     *                         FromClause
     * @return
     */
    private List filterCompletionItems(List metadataItems,
            List allowableTypes, boolean checkSchemaScope) {
        List filteredItems = new ArrayList();

        for (MetadataCompletionItem nextMI : metadataItems) {
            // if (!nextMI.isCachedDuplicate()) {
                if ((allowableTypes == null || allowableTypes.contains(nextMI.getMetadataType()))) {
                    if (checkSchemaScope && isSchemaTableInScope(nextMI)) {
                        filteredItems.add(nextMI.getCompletionItem());
                    } else if (!checkSchemaScope) {
                        filteredItems.add(nextMI.getCompletionItem());
                    }
                }
            // }
        }
        logDebug("  RETURNING [ " + filteredItems.size() + " ] METADATA ITEMS from filterCompletionItems() ");
        return filteredItems;
    }

    /**
     * This method filters the metadata items based on: 1) allowable types 2)
     * statement context based on position and relevant token(s) within the
     * statement 3)
     *
     * @param metadataItems
     * @param allowableTypes
     * @param checkSchemaScope - filter columns that aren't referenced in the
     *                         FromClause
     * @return
     */
    public List filterCompletionItemsForTableAlias(List metadataItems,
            String aliasTableName) {
        List filteredItems = new ArrayList();
        logDebug("  ==== START ===== filterCompletionItemsForTableAlias() ==========");
        logDebug("    >>>  TABLE_ALIAS   name = " + aliasTableName);
        // Find metadata table FQN from TableSymbol
        for (TableSymbol nextTS : this.statement.getQueryExpression().getFromClause().getTableSymbols()) {
            logDebug("   >>> TableSymbol schemaName = " + nextTS.getSchemaName() + " tableName = "
                    + nextTS.getTableName());
            if (nextTS.isAliased() && nextTS.getAlias().equalsIgnoreCase(aliasTableName)) {
                String schemaName = nextTS.getSchemaName();
                String tableName = nextTS.getTableName();
                logDebug("   >>> CHECKING FOR COLUMN ITEMS for schemaName = " + schemaName + "  and tableName = "
                        + tableName);
                for (MetadataCompletionItem nextMI : metadataItems) {
                    if (isColumnMetadataForAliasedTable(nextMI, schemaName, tableName)) {
                        filteredItems.add(nextMI.getCompletionItem());
                    }
                }
            }
        }
        logDebug("  ====  END  RETURNING [ " + filteredItems.size() + " ]  ITEMS ============================");
        return filteredItems;
    }

    public boolean isColumnMetadataForAliasedTable(MetadataCompletionItem metadataItem, String sName, String tName) {
        // Only return COLUMN types for SchemaName.TableName or TableName

        if (metadataItem.getMetadataType() == MetadataType.COLUMN) {
            logDebug("   >>> Checking columns for aliased table: " + sName + "." + tName);
            // Schema
            if (sName != null && metadataItem.getSchemaName() != null
                    && metadataItem.getSchemaName().equalsIgnoreCase(sName)) {
                logDebug("   ######## COLUMN MATCHES:  " + metadataItem.getColumnName());
                return metadataItem.getTableName() != null && metadataItem.getTableName().equalsIgnoreCase(tName);
            }
        }

        return false;
    }

    private boolean isSchemaTableInScope(MetadataCompletionItem item) {
        if (item.getTableName() == null) {
            return false;
        }

        FromClause fromClause = statement.getQueryExpression().getFromClause();

        boolean result = false;
        for (TableSymbol tableSymbol : fromClause.getTableSymbols()) {
            if (item.getSchemaName() != null && tableSymbol.getSchemaName() != null) {
                result = tableSymbol.getSchemaName().equalsIgnoreCase(item.getSchemaName())
                        && tableSymbol.getTableName().equalsIgnoreCase(item.getTableName());
            } else if (tableSymbol.getTableName() != null) {
                result = tableSymbol.getTableName().equalsIgnoreCase(item.getTableName());
            }

            if (result) {
                break;
            }
        }
        return result;
    }

    private RestViewSourceInfo getRuntimeMetadata(String virtualizationName) {
        if (virtualizationName != null && this.metadataService != null) {
            try {
                return this.metadataService.getRuntimeMetadata(virtualizationName);
            } catch (Exception e) {
                LOGGER.error("MetadataItemProvider.getRuntimeMetadata() ERROR accessing runtime metadata", e);
            }
        } else {
            LOGGER.error("MetadataItemProvider.getRuntimeMetadata() virtualizationName == NULL");
        }

        return null;
    }

    @SuppressWarnings("PMD.SystemPrintln")
    private static void logDebug(String msg) {
        if (DO_PRINT_TO_CONSOLE) {
            LOGGER.info(msg);
        } else if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(msg);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy