com.yahoo.yqlplus.engine.internal.source.ExportModuleAdapter.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.yqlplus.engine.internal.source.ExportModuleAdapter.java

Source

/*
 * Copyright (c) 2016 Yahoo Inc.
 * Licensed under the terms of the Apache version 2.0 license.
 * See LICENSE file for terms.
 */

package com.yahoo.yqlplus.engine.internal.source;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.GambitCreator;
import com.yahoo.yqlplus.engine.internal.bytecode.types.gambit.ObjectBuilder;
import com.yahoo.yqlplus.engine.internal.plan.ContextPlanner;
import com.yahoo.yqlplus.engine.internal.plan.DynamicExpressionEvaluator;
import com.yahoo.yqlplus.engine.internal.plan.ModuleType;
import com.yahoo.yqlplus.engine.internal.plan.ast.OperatorStep;
import com.yahoo.yqlplus.engine.internal.plan.ast.OperatorValue;
import com.yahoo.yqlplus.engine.internal.plan.ast.PhysicalExprOperator;
import com.yahoo.yqlplus.engine.internal.plan.ast.PhysicalOperator;
import com.yahoo.yqlplus.engine.internal.plan.streams.StreamValue;
import com.yahoo.yqlplus.engine.internal.plan.types.TypeWidget;
import com.yahoo.yqlplus.language.logical.ExpressionOperator;
import com.yahoo.yqlplus.language.operator.OperatorNode;
import com.yahoo.yqlplus.language.parser.Location;
import com.yahoo.yqlplus.language.parser.ProgramCompileException;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ExportModuleAdapter implements ModuleType {
    private final TypeWidget type;
    private final String moduleName;
    private final Multimap<String, ObjectBuilder.MethodBuilder> methods;
    private final Map<String, ObjectBuilder.MethodBuilder> fields;

    private OperatorNode<PhysicalExprOperator> module;

    public ExportModuleAdapter(TypeWidget type, String moduleName,
            Multimap<String, ObjectBuilder.MethodBuilder> methods,
            Map<String, ObjectBuilder.MethodBuilder> fields) {
        this.type = type;
        this.moduleName = moduleName;
        this.methods = methods;
        this.fields = fields;
    }

    @Override
    public OperatorNode<PhysicalExprOperator> call(Location location, ContextPlanner context, String name,
            List<OperatorNode<ExpressionOperator>> arguments) {
        return callInRowContext(location, context, name, arguments, null);
    }

    @Override
    public OperatorNode<PhysicalExprOperator> callInRowContext(Location location, ContextPlanner context,
            String name, List<OperatorNode<ExpressionOperator>> arguments, OperatorNode<PhysicalExprOperator> row) {
        Collection<ObjectBuilder.MethodBuilder> targets = methods.get(name);
        if (targets.isEmpty()) {
            throw new ProgramCompileException(location, "Method '%s' not found on module %s", name, moduleName);
        }
        @SuppressWarnings("ConstantConditions")
        GambitCreator.Invocable firstInvocable = Iterables.getFirst(targets, null).invoker();
        TypeWidget outputType = firstInvocable.getReturnType();
        DynamicExpressionEvaluator eval = row == null ? new DynamicExpressionEvaluator(context)
                : new DynamicExpressionEvaluator(context, row);
        List<OperatorNode<PhysicalExprOperator>> callArgs = Lists.newArrayList();
        callArgs.add(getModule(location, context));
        callArgs.add(context.getContextExpr());
        if (targets.size() > 1) {
            callArgs.addAll(eval.applyAll(arguments));
            for (ObjectBuilder.MethodBuilder candidate : targets) {
                outputType = context.getValueTypeAdapter().unifyTypes(outputType,
                        candidate.invoker().getReturnType());
            }
            return OperatorNode.create(location, PhysicalExprOperator.CALL, outputType, name, callArgs);
        } else {
            Iterator<TypeWidget> args = firstInvocable.getArgumentTypes().iterator();
            args.next();
            args.next();
            // consume the module & context
            Iterator<OperatorNode<ExpressionOperator>> e = arguments.iterator();
            while (args.hasNext()) {
                if (!e.hasNext()) {
                    throw new ProgramCompileException(location,
                            "Argument length mismatch in call to %s (expects %d arguments)", name,
                            firstInvocable.getArgumentTypes().size());
                }
                callArgs.add(OperatorNode.create(location, PhysicalExprOperator.CAST, args.next(),
                        eval.apply(e.next())));
            }
            if (e.hasNext()) {
                throw new ProgramCompileException(location,
                        "Argument length mismatch in call to %s (expects %d arguments)", name,
                        firstInvocable.getArgumentTypes().size());
            }
            return OperatorNode.create(location, PhysicalExprOperator.INVOKE, firstInvocable, callArgs);
        }
    }

    private OperatorNode<PhysicalExprOperator> getModule(Location location, ContextPlanner planner) {
        if (module == null) {
            OperatorValue value = OperatorStep.create(planner.getValueTypeAdapter(), location,
                    PhysicalOperator.EVALUATE, OperatorNode.create(location, PhysicalExprOperator.ROOT_CONTEXT),
                    OperatorNode.create(location, PhysicalExprOperator.INJECT_MEMBERS,
                            OperatorNode.create(location, PhysicalExprOperator.NEW, type, ImmutableList.of())));
            module = OperatorNode.create(location, PhysicalExprOperator.VALUE, value);
        }
        return module;
    }

    @Override
    public OperatorNode<PhysicalExprOperator> property(Location location, ContextPlanner context, String name) {
        ObjectBuilder.MethodBuilder fieldGetter = fields.get(name);
        if (fieldGetter == null) {
            throw new ProgramCompileException(location, "Property '%s' not found on module %s", name, moduleName);
        }
        return OperatorNode.create(location, PhysicalExprOperator.INVOKE, fieldGetter.invoker(),
                ImmutableList.of(getModule(location, context)));
    }

    @Override
    public StreamValue pipe(Location location, ContextPlanner context, String name, StreamValue input,
            List<OperatorNode<ExpressionOperator>> arguments) {
        Collection<ObjectBuilder.MethodBuilder> targets = methods.get(name);
        if (targets.isEmpty()) {
            throw new ProgramCompileException(location, "Method '%s' not found on module %s", name, moduleName);
        }
        @SuppressWarnings("ConstantConditions")
        GambitCreator.Invocable firstInvocable = Iterables.getFirst(targets, null).invoker();
        TypeWidget outputType = firstInvocable.getReturnType();
        DynamicExpressionEvaluator eval = new DynamicExpressionEvaluator(context);
        List<OperatorNode<PhysicalExprOperator>> callArgs = Lists.newArrayList();
        callArgs.add(getModule(location, context));
        callArgs.add(context.getContextExpr());
        if (targets.size() > 1) {
            callArgs.add(input.materializeValue());
            callArgs.addAll(eval.applyAll(arguments));
            for (ObjectBuilder.MethodBuilder candidate : targets) {
                outputType = context.getValueTypeAdapter().unifyTypes(outputType,
                        candidate.invoker().getReturnType());
            }
            return StreamValue.iterate(context,
                    OperatorNode.create(location, PhysicalExprOperator.CALL, outputType, name, callArgs));
        } else {
            Iterator<TypeWidget> args = firstInvocable.getArgumentTypes().iterator();
            args.next();
            args.next();
            // consume the module & context
            callArgs.add(input.materializeValue());
            // consume the stream argument
            args.next();
            Iterator<OperatorNode<ExpressionOperator>> e = arguments.iterator();
            while (args.hasNext()) {
                if (!e.hasNext()) {
                    throw new ProgramCompileException(location,
                            "Argument length mismatch in call to %s (expects %d arguments)", name,
                            firstInvocable.getArgumentTypes().size());
                }
                callArgs.add(OperatorNode.create(location, PhysicalExprOperator.CAST, args.next(),
                        eval.apply(e.next())));
            }
            if (e.hasNext()) {
                throw new ProgramCompileException(location,
                        "Argument length mismatch in call to %s (expects %d arguments)", name,
                        firstInvocable.getArgumentTypes().size());
            }
            return StreamValue.iterate(context,
                    OperatorNode.create(location, PhysicalExprOperator.INVOKE, firstInvocable, callArgs));
        }
    }
}