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

com.mysema.query.collections.DefaultEvaluatorFactory Maven / Gradle / Ivy

/*
 * Copyright (c) 2010 Mysema Ltd.
 * All rights reserved.
 *
 */
package com.mysema.query.collections;

import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

import net.jcip.annotations.Immutable;

import org.apache.commons.lang.ClassUtils;

import com.mysema.codegen.Evaluator;
import com.mysema.codegen.EvaluatorFactory;
import com.mysema.codegen.model.ClassType;
import com.mysema.codegen.model.SimpleType;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.codegen.model.Types;
import com.mysema.query.JoinExpression;
import com.mysema.query.JoinType;
import com.mysema.query.QueryMetadata;
import com.mysema.query.support.CollectionAnyVisitor;
import com.mysema.query.support.Context;
import com.mysema.query.types.Expression;
import com.mysema.query.types.FactoryExpression;
import com.mysema.query.types.Operation;
import com.mysema.query.types.ParamExpression;
import com.mysema.query.types.ParamNotSetException;
import com.mysema.query.types.Predicate;

/**
 * DefaultEvaluatorFactory extends the EvaluatorFactory class to provide Java source
 * templates for evaluation of ColQuery queries
 *
 * @author tiwe
 *
 */
@Immutable
public class DefaultEvaluatorFactory {

    private final EvaluatorFactory factory;

    private final ColQueryTemplates templates;

    public DefaultEvaluatorFactory(ColQueryTemplates templates){
        // TODO : which ClassLoader to pick ?!?
        this(templates,
        (URLClassLoader)DefaultEvaluatorFactory.class.getClassLoader(),
        ToolProvider.getSystemJavaCompiler());
    }

    public DefaultEvaluatorFactory(ColQueryTemplates templates,
            URLClassLoader classLoader, JavaCompiler compiler){
        this.templates = templates;
        this.factory = new EvaluatorFactory(classLoader, compiler);
    }

    /**
     * Create an Evaluator for the given query sources and projection
     *
     * @param 
     * @param sources
     * @param projection
     * @return
     */
    public  Evaluator create(QueryMetadata metadata, List> sources, Expression projection) {
        ColQuerySerializer serializer = new ColQuerySerializer(templates);
        serializer.handle(projection);

        Map constantToLabel = serializer.getConstantToLabel();
        Map constants = getConstants(metadata, constantToLabel);
        Class[] types = new Class[sources.size()];
        String[] names = new String[sources.size()];
        for (int i = 0; i < sources.size(); i++) {
            types[i] = sources.get(i).getType();
            names[i] = sources.get(i).toString();
        }

        // normalize types
        for (int i = 0; i < types.length; i++){
            if (ClassUtils.wrapperToPrimitive(types[i]) != null){
                types[i] = ClassUtils.wrapperToPrimitive(types[i]);
            }
        }

        String javaSource = serializer.toString();
        if (projection instanceof FactoryExpression){
            javaSource = "("+com.mysema.codegen.support.ClassUtils.getName(projection.getType())+")(" + javaSource+")";
        }

        return factory.createEvaluator("return " + javaSource +";", projection.getType(), names, types, constants);
    }

    /**
     * Create an Evaluator for the given source and filter
     *
     * @param 
     * @param source
     * @param filter
     * @return
     */
    public  Evaluator> createEvaluator(QueryMetadata metadata, Expression source, Predicate filter){
        String typeName = com.mysema.codegen.support.ClassUtils.getName(source.getType());
        ColQuerySerializer ser = new ColQuerySerializer(templates);
        ser.append("java.util.List<"+typeName+"> rv = new java.util.ArrayList<"+typeName+">();\n");
        ser.append("for (" + typeName + " "+ source + " : " + source + "_){\n");
        ser.append("    if (").handle(filter).append("){\n");
        ser.append("        rv.add("+source+");\n");
        ser.append("    }\n");
        ser.append("}\n");
        ser.append("return rv;");

        Map constantToLabel = ser.getConstantToLabel();
        Map constants = getConstants(metadata, constantToLabel);

        Type sourceType = new ClassType(TypeCategory.SIMPLE, source.getType());
        ClassType sourceListType = new ClassType(TypeCategory.SIMPLE, Iterable.class, sourceType);

        return factory.createEvaluator(
                ser.toString(),
                sourceListType,
                new String[]{source+"_"},
                new Type[]{sourceListType},
                new Class[]{Iterable.class},
                constants);
    }

    /**
     * Create an Evaluator for the given sources and the given optional filter
     *
     * @param joins
     * @param filter
     * @return
     */
    @SuppressWarnings("unchecked")
    public Evaluator> createEvaluator(QueryMetadata metadata, List joins, @Nullable Predicate filter){
        List sourceNames = new ArrayList();
        List sourceTypes = new ArrayList();
        List sourceClasses = new ArrayList();
        StringBuilder vars = new StringBuilder();
        ColQuerySerializer ser = new ColQuerySerializer(templates);
        ser.append("java.util.List rv = new java.util.ArrayList();\n");

        List anyJoinMatchers = new ArrayList();

        // creating context
        for (JoinExpression join : joins){
            Expression target = join.getTarget();
            String typeName = com.mysema.codegen.support.ClassUtils.getName(target.getType());
            if (vars.length() > 0){
                vars.append(",");
            }
            if (join.getType() == JoinType.DEFAULT){
                ser.append("for (" + typeName + " "+ target + " : " + target + "_){\n");
                vars.append(target);
                sourceNames.add(target+"_");
                sourceTypes.add(new SimpleType(Types.ITERABLE, new ClassType(TypeCategory.SIMPLE,target.getType())));
                sourceClasses.add(Iterable.class);

            }else if (join.getType() == JoinType.INNERJOIN){
                Operation alias = (Operation)join.getTarget();
                boolean colAnyJoin = join.getCondition() != null && join.getCondition().toString().equals("any");
                if (colAnyJoin){
                    String matcher = alias.getArg(1).toString() + "_matched";
                    ser.append("boolean " + matcher + " = false;\n");
                    anyJoinMatchers.add(matcher);
                }
                ser.append("for ( " + typeName + " " + alias.getArg(1) + " : ");
                if (colAnyJoin){
                    Context context = new Context();
                    Expression replacement = (Expression) alias.getArg(0).accept(CollectionAnyVisitor.DEFAULT, context);
                    ser.handle(replacement);
                }else{
                    ser.handle(alias.getArg(0));
                }
                if (alias.getArg(0).getType().equals(Map.class)){
                    ser.append(".values()");
                }
                ser.append("){\n");
                vars.append(alias.getArg(1));

            }else{
                throw new IllegalArgumentException("Illegal join expression " + join);
            }
        }

        // filter
        if (filter != null){
            ser.append("if (");
            for (String matcher : anyJoinMatchers){
                ser.append("!" + matcher + " && ");
            }
            ser.handle(filter).append("){\n");
            for (String matcher : anyJoinMatchers){
                ser.append("    "+ matcher + " = true;\n");
            }
            ser.append("    rv.add(new Object[]{"+vars+"});\n");
            ser.append("}\n");
        }else{
            ser.append("rv.add(new Object[]{"+vars+"});\n");
        }

        // closing context
        for (int i = 0; i < joins.size(); i++){
            ser.append("}\n");
        }
        ser.append("return rv;");

        Map constantToLabel = ser.getConstantToLabel();
        Map constants = getConstants(metadata, constantToLabel);

        ClassType projectionType = new ClassType(TypeCategory.LIST, List.class, Types.OBJECTS);
        return factory.createEvaluator(
                ser.toString(),
                projectionType,
                sourceNames.toArray(new String[sourceNames.size()]),
                sourceTypes.toArray(new Type[sourceTypes.size()]),
                sourceClasses.toArray(new Class[sourceClasses.size()]),
                constants);
    }

    private Map getConstants(QueryMetadata metadata, Map constantToLabel) {
        Map constants = new HashMap();
        for (Map.Entry entry : constantToLabel.entrySet()){
            if (entry.getKey() instanceof ParamExpression){
                Object value = metadata.getParams().get(entry.getKey());
                if (value == null){
                    throw new ParamNotSetException((ParamExpression) entry.getKey());
                }
                constants.put(entry.getValue(), value);
            }else{
                constants.put(entry.getValue(), entry.getKey());
            }
        }
        return constants;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy