io.crate.analyze.CreateAnalyzerStatementAnalyzer.java Source code

Java tutorial

Introduction

Here is the source code for io.crate.analyze.CreateAnalyzerStatementAnalyzer.java

Source

/*
 * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  Crate 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.
 *
 * However, if you have executed another commercial license agreement
 * with Crate these terms will supersede the license and you may use the
 * software solely pursuant to the terms of the relevant commercial agreement.
 */

package io.crate.analyze;

import com.google.common.base.Optional;
import io.crate.analyze.expressions.ExpressionToStringVisitor;
import io.crate.metadata.FulltextAnalyzerResolver;
import io.crate.sql.tree.*;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;

import java.util.Locale;
import java.util.Map;

import static io.crate.analyze.CreateAnalyzerAnalyzedStatement.getSettingsKey;

class CreateAnalyzerStatementAnalyzer
        extends DefaultTraversalVisitor<CreateAnalyzerAnalyzedStatement, CreateAnalyzerStatementAnalyzer.Context> {

    private final FulltextAnalyzerResolver fulltextAnalyzerResolver;

    CreateAnalyzerStatementAnalyzer(FulltextAnalyzerResolver fulltextAnalyzerResolver) {
        this.fulltextAnalyzerResolver = fulltextAnalyzerResolver;
    }

    public CreateAnalyzerAnalyzedStatement analyze(Node node, Analysis analysis) {
        return super.process(node, new Context(analysis));
    }

    static class Context {

        Analysis analysis;
        CreateAnalyzerAnalyzedStatement statement;

        public Context(Analysis analysis) {
            this.analysis = analysis;
        }
    }

    @Override
    public CreateAnalyzerAnalyzedStatement visitCreateAnalyzer(CreateAnalyzer node, Context context) {
        context.statement = new CreateAnalyzerAnalyzedStatement(fulltextAnalyzerResolver);
        context.statement.ident(node.ident());

        if (node.isExtending()) {
            context.statement.extendedAnalyzer(node.extendedAnalyzer().get());
        }

        for (AnalyzerElement element : node.elements()) {
            process(element, context);
        }

        return context.statement;
    }

    @Override
    public CreateAnalyzerAnalyzedStatement visitTokenizer(Tokenizer tokenizer, Context context) {
        String name = tokenizer.ident();
        Optional<io.crate.sql.tree.GenericProperties> properties = tokenizer.properties();

        if (!properties.isPresent()) {
            // use a builtin tokenizer without parameters

            // validate
            if (!context.statement.analyzerService().hasBuiltInTokenizer(name)) {
                throw new IllegalArgumentException(
                        String.format(Locale.ENGLISH, "Non-existing tokenizer '%s'", name));
            }
            // build
            context.statement.tokenDefinition(name, Settings.EMPTY);
        } else {
            // validate
            if (!context.statement.analyzerService().hasBuiltInTokenizer(name)) {
                // type mandatory
                String evaluatedType = extractType(properties.get(), context.analysis.parameterContext());
                if (!context.statement.analyzerService().hasBuiltInTokenizer(evaluatedType)) {
                    // only builtin tokenizers can be extended, for now
                    throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                            "Non-existing built-in tokenizer type '%s'", evaluatedType));
                }
            } else {
                throw new IllegalArgumentException(
                        String.format(Locale.ENGLISH, "tokenizer name '%s' is reserved", name));
            }
            // build
            // transform name as tokenizer is not publicly available
            name = String.format(Locale.ENGLISH, "%s_%s", context.statement.ident(), name);

            Settings.Builder builder = Settings.builder();
            for (Map.Entry<String, Expression> tokenizerProperty : properties.get().properties().entrySet()) {
                GenericPropertiesConverter.genericPropertyToSetting(builder,
                        getSettingsKey("index.analysis.tokenizer.%s.%s", name, tokenizerProperty.getKey()),
                        tokenizerProperty.getValue(), context.analysis.parameterContext());
            }
            context.statement.tokenDefinition(name, builder.build());
        }

        return null;
    }

    @Override
    public CreateAnalyzerAnalyzedStatement visitGenericProperty(GenericProperty property, Context context) {
        GenericPropertiesConverter.genericPropertyToSetting(context.statement.genericAnalyzerSettingsBuilder(),
                getSettingsKey("index.analysis.analyzer.%s.%s", context.statement.ident(), property.key()),
                property.value(), context.analysis.parameterContext());
        return null;
    }

    @Override
    public CreateAnalyzerAnalyzedStatement visitTokenFilters(TokenFilters tokenFilters, Context context) {
        for (NamedProperties tokenFilterNode : tokenFilters.tokenFilters()) {

            String name = tokenFilterNode.ident();
            Optional<GenericProperties> properties = tokenFilterNode.properties();

            // use a builtin token-filter without parameters
            if (!properties.isPresent()) {
                // validate
                if (!context.statement.analyzerService().hasBuiltInTokenFilter(name)) {
                    throw new IllegalArgumentException(
                            String.format(Locale.ENGLISH, "Non-existing built-in token-filter '%s'", name));
                }
                // build
                context.statement.addTokenFilter(name, Settings.EMPTY);
            } else {
                // validate
                GenericProperties filterProperties = properties.get();
                if (!context.statement.analyzerService().hasBuiltInTokenFilter(name)) {
                    // type mandatory when name is not a builtin filter
                    String evaluatedType = extractType(filterProperties, context.analysis.parameterContext());
                    if (!context.statement.analyzerService().hasBuiltInTokenFilter(evaluatedType)) {
                        // only builtin token-filters can be extended, for now
                        throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                                "Non-existing built-in token-filter type '%s'", evaluatedType));
                    }
                } else {
                    if (filterProperties.get("type") != null) {
                        throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                                "token-filter name '%s' is reserved, 'type' property forbidden here", name));
                    }
                    filterProperties.add(new GenericProperty("type", new StringLiteral(name)));
                }

                // build
                // transform name as token-filter is not publicly available
                name = String.format(Locale.ENGLISH, "%s_%s", context.statement.ident(), name);
                Settings.Builder builder = Settings.builder();
                for (Map.Entry<String, Expression> tokenFilterProperty : filterProperties.properties().entrySet()) {
                    GenericPropertiesConverter.genericPropertyToSetting(builder,
                            getSettingsKey("index.analysis.filter.%s.%s", name, tokenFilterProperty.getKey()),
                            tokenFilterProperty.getValue(), context.analysis.parameterContext());
                }
                context.statement.addTokenFilter(name, builder.build());
            }
        }
        return null;
    }

    @Override
    public CreateAnalyzerAnalyzedStatement visitCharFilters(CharFilters charFilters, Context context) {
        for (NamedProperties charFilterNode : charFilters.charFilters()) {

            String name = charFilterNode.ident();
            Optional<GenericProperties> properties = charFilterNode.properties();

            // use a builtin char-filter without parameters
            if (!properties.isPresent()) {
                // validate
                if (!context.statement.analyzerService().hasBuiltInCharFilter(name)) {
                    throw new IllegalArgumentException(
                            String.format(Locale.ENGLISH, "Non-existing built-in char-filter '%s'", name));
                }
                validateCharFilterProperties(name, properties.orNull());
                // build
                context.statement.addCharFilter(name, Settings.EMPTY);
            } else {
                String type = extractType(properties.get(), context.analysis.parameterContext());
                if (!context.statement.analyzerService().hasBuiltInCharFilter(type)) {
                    // only builtin char-filters can be extended, for now
                    throw new IllegalArgumentException(String.format(Locale.ENGLISH,
                            "Non-existing built-in char-filter" + " type '%s'", type));
                }
                validateCharFilterProperties(type, properties.get());

                // build
                // transform name as char-filter is not publicly available
                name = String.format(Locale.ENGLISH, "%s_%s", context.statement.ident(), name);
                Settings.Builder builder = Settings.builder();
                for (Map.Entry<String, Expression> charFilterProperty : properties.get().properties().entrySet()) {
                    GenericPropertiesConverter.genericPropertyToSetting(builder,
                            getSettingsKey("index.analysis.char_filter.%s.%s", name, charFilterProperty.getKey()),
                            charFilterProperty.getValue(), context.analysis.parameterContext());
                }
                context.statement.addCharFilter(name, builder.build());
            }
        }
        return null;
    }

    /**
     * Validate and process `type` property
     */
    private String extractType(GenericProperties properties, ParameterContext parameterContext) {
        Expression expression = properties.get("type");
        if (expression == null) {
            throw new IllegalArgumentException("'type' property missing");
        }
        if (expression instanceof ArrayLiteral) {
            throw new IllegalArgumentException("'type' property is invalid");
        }

        return ExpressionToStringVisitor.convert(expression, parameterContext.parameters());
    }

    private static void validateCharFilterProperties(String type, @Nullable GenericProperties properties) {
        if (properties == null && !type.equals("html_strip")) {
            throw new IllegalArgumentException(
                    String.format(Locale.ENGLISH, "CHAR_FILTER of type '%s' needs additional parameters", type));
        }
    }

}