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

org.elasticsearch.script.Script Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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.elasticsearch.script;

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
import org.elasticsearch.common.logging.support.LoggerMessageFormat;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService.ScriptType;

import java.io.IOException;
import java.util.Map;

/**
 * Script holds all the parameters necessary to compile or find in cache and then execute a script.
 */
public class Script implements ToXContent, Streamable {

    public static final ScriptType DEFAULT_TYPE = ScriptType.INLINE;
    private static final ScriptParser PARSER = new ScriptParser();

    private String script;
    private @Nullable ScriptType type;
    private @Nullable String lang;
    private @Nullable Map params;

    /**
     * For Serialization
     */
    Script() {
    }

    /**
     * Constructor for simple inline script. The script will have no lang or
     * params set.
     *
     * @param script
     *            The inline script to execute.
     */
    public Script(String script) {
        this(script, null);
    }

    /**
     * For sub-classes to use to override the default language
     */
    protected Script(String script, String lang) {
        this(script, ScriptType.INLINE, lang, null);
    }

    /**
     * Constructor for Script.
     * 
     * @param script
     *            The cache key of the script to be compiled/executed. For
     *            inline scripts this is the actual script source code. For
     *            indexed scripts this is the id used in the request. For on
     *            file scripts this is the file name.
     * @param type
     *            The type of script -- dynamic, indexed, or file.
     * @param lang
     *            The language of the script to be compiled/executed.
     * @param params
     *            The map of parameters the script will be executed with.
     */
    public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map params) {
        if (script == null) {
            throw new IllegalArgumentException("The parameter script (String) must not be null in Script.");
        }
        if (type == null) {
            throw new IllegalArgumentException("The parameter type (ScriptType) must not be null in Script.");
        }
        this.script = script;
        this.type = type;
        this.lang = lang;
        this.params = (Map)params;
    }

    /**
     * Method for getting the script.
     * @return The cache key of the script to be compiled/executed.  For dynamic scripts this is the actual
     *         script source code.  For indexed scripts this is the id used in the request.  For on disk scripts
     *         this is the file name.
     */
    public String getScript() {
        return script;
    }

    /**
     * Method for getting the type.
     * 
     * @return The type of script -- inline, indexed, or file.
     */
    public ScriptType getType() {
        return type == null ? DEFAULT_TYPE : type;
    }

    /**
     * Method for getting language.
     * 
     * @return The language of the script to be compiled/executed.
     */
    public String getLang() {
        return lang;
    }

    /**
     * Method for getting the parameters.
     * 
     * @return The map of parameters the script will be executed with.
     */
    public Map getParams() {
        return params;
    }

    @Override
    public final void readFrom(StreamInput in) throws IOException {
        script = in.readString();
        if (in.readBoolean()) {
            type = ScriptType.readFrom(in);
        }
        lang = in.readOptionalString();
        if (in.readBoolean()) {
            params = in.readMap();
        }
        doReadFrom(in);
    }

    protected void doReadFrom(StreamInput in) throws IOException {
        // For sub-classes to Override
    }

    @Override
    public final void writeTo(StreamOutput out) throws IOException {
        out.writeString(script);
        boolean hasType = type != null;
        out.writeBoolean(hasType);
        if (hasType) {
            ScriptType.writeTo(type, out);
        }
        out.writeOptionalString(lang);
        boolean hasParams = params != null;
        out.writeBoolean(hasParams);
        if (hasParams) {
            out.writeMap(params);
        }
        doWriteTo(out);
    }

    protected void doWriteTo(StreamOutput out) throws IOException {
        // For sub-classes to Override
    }

    @Override
    public final XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException {
        if (type == null) {
            return builder.value(script);
        }

        builder.startObject();
        scriptFieldToXContent(script, type, builder, builderParams);
        if (lang != null) {
            builder.field(ScriptField.LANG.getPreferredName(), lang);
        }
        if (params != null) {
            builder.field(ScriptField.PARAMS.getPreferredName(), params);
        }
        builder.endObject();
        return builder;
    }

    protected XContentBuilder scriptFieldToXContent(String script, ScriptType type, XContentBuilder builder, Params builderParams)
            throws IOException {
        builder.field(type.getParseField().getPreferredName(), script);
        return builder;
    }

    public static Script readScript(StreamInput in) throws IOException {
        Script script = new Script();
        script.readFrom(in);
        return script;
    }

    public static Script parse(Map config, boolean removeMatchedEntries, ParseFieldMatcher parseFieldMatcher) {
        return PARSER.parse(config, removeMatchedEntries, parseFieldMatcher);
    }

    public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
        return PARSER.parse(parser, parseFieldMatcher);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((lang == null) ? 0 : lang.hashCode());
        result = prime * result + ((params == null) ? 0 : params.hashCode());
        result = prime * result + ((script == null) ? 0 : script.hashCode());
        result = prime * result + ((type == null) ? 0 : type.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Script other = (Script) obj;
        if (lang == null) {
            if (other.lang != null)
                return false;
        } else if (!lang.equals(other.lang))
            return false;
        if (params == null) {
            if (other.params != null)
                return false;
        } else if (!params.equals(other.params))
            return false;
        if (script == null) {
            if (other.script != null)
                return false;
        } else if (!script.equals(other.script))
            return false;
        if (type != other.type)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "[script: " + script + ", type: " + type.getParseField().getPreferredName() + ", lang: " + lang + ", params: " + params
                + "]";
    }

    private static class ScriptParser extends AbstractScriptParser