com.espertech.esper.epl.join.assemble.AssemblyStrategyTreeBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.espertech.esper.epl.join.assemble.AssemblyStrategyTreeBuilder.java

Source

/**************************************************************************************
 * Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
 * http://esper.codehaus.org                                                          *
 * http://www.espertech.com                                                           *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the GPL license       *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package com.espertech.esper.epl.join.assemble;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.io.PrintWriter;
import java.io.StringWriter;

import com.espertech.esper.util.IndentWriter;
import com.espertech.esper.epl.join.plan.NStreamOuterQueryPlanBuilder;

/**
 * Builds a tree of assembly nodes given a strategy for how to join streams.
 */
public class AssemblyStrategyTreeBuilder {
    /**
     * Builds a tree of {@link BaseAssemblyNode} from join strategy information.
     * @param rootStream - the root stream supplying the event to evaluate
     * @param streamsJoinedPerStream - a map in which the key is the stream number to supply an event,
     * and the value is an array of streams to find events in for the given event
     * @param isRequiredPerStream - indicates which streams are required join streams versus optional streams
     * @return root assembly node
     */
    public static BaseAssemblyNode build(int rootStream, Map<Integer, int[]> streamsJoinedPerStream,
            boolean isRequiredPerStream[]) {
        if (streamsJoinedPerStream.size() < 3) {
            throw new IllegalArgumentException("Not a 3-way join");
        }
        if ((rootStream < 0) || (rootStream >= streamsJoinedPerStream.size())) {
            throw new IllegalArgumentException("Invalid root stream");
        }
        if (isRequiredPerStream.length != streamsJoinedPerStream.size()) {
            throw new IllegalArgumentException("Arrays not matching up");
        }

        NStreamOuterQueryPlanBuilder.verifyJoinedPerStream(rootStream, streamsJoinedPerStream);

        if (log.isDebugEnabled()) {
            log.debug(".build Building node for root stream " + rootStream + " streamsJoinedPerStream="
                    + NStreamOuterQueryPlanBuilder.print(streamsJoinedPerStream) + " isRequiredPerStream="
                    + Arrays.toString(isRequiredPerStream));
        }

        BaseAssemblyNode topNode = createNode(true, rootStream, streamsJoinedPerStream.size(),
                streamsJoinedPerStream.get(rootStream), isRequiredPerStream);

        recursiveBuild(rootStream, topNode, streamsJoinedPerStream, isRequiredPerStream);

        if (log.isDebugEnabled()) {
            StringWriter buf = new StringWriter();
            PrintWriter print = new PrintWriter(buf);
            IndentWriter indentWriter = new IndentWriter(print, 0, 2);
            topNode.printDescendends(indentWriter);

            log.debug(".build Dumping root node for stream " + rootStream + ": \n" + buf.toString());
        }

        return topNode;
    }

    private static void recursiveBuild(int parentStreamNum, BaseAssemblyNode parentNode,
            Map<Integer, int[]> streamsJoinedPerStream, boolean isRequiredPerStream[]) {
        int numStreams = streamsJoinedPerStream.size();

        for (int i = 0; i < streamsJoinedPerStream.get(parentStreamNum).length; i++) {
            int streamJoined = streamsJoinedPerStream.get(parentStreamNum)[i];
            BaseAssemblyNode childNode = createNode(false, streamJoined, numStreams,
                    streamsJoinedPerStream.get(streamJoined), isRequiredPerStream);
            parentNode.addChild(childNode);

            if (streamsJoinedPerStream.get(streamJoined).length > 0) {
                recursiveBuild(streamJoined, childNode, streamsJoinedPerStream, isRequiredPerStream);
            }
        }
    }

    private static BaseAssemblyNode createNode(boolean isRoot, int streamNum, int numStreams, int[] joinedStreams,
            boolean isRequiredPerStream[]) {
        if (joinedStreams.length == 0) {
            return new LeafAssemblyNode(streamNum, numStreams);
        }
        if (joinedStreams.length == 1) {
            int joinedStream = joinedStreams[0];
            boolean isRequired = isRequiredPerStream[joinedStream];
            if (isRequired) {
                if (isRoot) {
                    return new RootRequiredAssemblyNode(streamNum, numStreams);
                } else {
                    return new BranchRequiredAssemblyNode(streamNum, numStreams);
                }
            } else {
                if (isRoot) {
                    return new RootOptionalAssemblyNode(streamNum, numStreams);
                } else {
                    return new BranchOptionalAssemblyNode(streamNum, numStreams);
                }
            }
        }

        // Determine if all substream are outer (optional) joins
        boolean allSubStreamsOptional = true;
        for (int i = 0; i < joinedStreams.length; i++) {
            int stream = joinedStreams[i];
            if (isRequiredPerStream[stream]) {
                allSubStreamsOptional = false;
            }
        }

        // Make node for building a cartesian product
        if (isRoot) {
            return new RootCartProdAssemblyNode(streamNum, numStreams, allSubStreamsOptional);
        } else {
            return new CartesianProdAssemblyNode(streamNum, numStreams, allSubStreamsOptional);
        }
    }

    private static final Log log = LogFactory.getLog(AssemblyStrategyTreeBuilder.class);
}