private JoinPlanResult HandleJoin(
            string[] streamNames,
            Viewable[] streamViews,
            ResultSetProcessor resultSetProcessor,
            AgentInstanceContext agentInstanceContext,
            IList <StopCallback> stopCallbacks,
            StreamJoinAnalysisResult joinAnalysisResult,
            bool isRecoveringResilient)
        {
            var joinSetComposerDesc = _joinSetComposerPrototype.Create(streamViews, false, agentInstanceContext, isRecoveringResilient);

            stopCallbacks.Add(new ProxyStopCallback(() => joinSetComposerDesc.JoinSetComposer.Destroy()));

            var filter        = new JoinSetFilter(joinSetComposerDesc.PostJoinFilterEvaluator);
            var indicatorView = _outputProcessViewFactory.MakeView(resultSetProcessor, agentInstanceContext);

            // Create strategy for join execution
            JoinExecutionStrategy execution = new JoinExecutionStrategyImpl(joinSetComposerDesc.JoinSetComposer, filter, indicatorView, agentInstanceContext);

            // The view needs a reference to the join execution to pull iterator values
            indicatorView.JoinExecutionStrategy = execution;

            // Hook up dispatchable with buffer and execution strategy
            var joinStatementDispatch = new JoinExecStrategyDispatchable(execution, _statementSpec.StreamSpecs.Length);

            agentInstanceContext.EpStatementAgentInstanceHandle.OptionalDispatchable = joinStatementDispatch;

            JoinPreloadMethod preloadMethod;

            if (joinAnalysisResult.UnidirectionalStreamNumber >= 0)
            {
                preloadMethod = new JoinPreloadMethodNull();
            }
            else
            {
                if (!joinSetComposerDesc.JoinSetComposer.AllowsInit)
                {
                    preloadMethod = new JoinPreloadMethodNull();
                }
                else
                {
                    preloadMethod = new JoinPreloadMethodImpl(streamNames.Length, joinSetComposerDesc.JoinSetComposer);
                }
            }

            // Create buffer for each view. Point buffer to dispatchable for join.
            for (var i = 0; i < _statementSpec.StreamSpecs.Length; i++)
            {
                var buffer = new BufferView(i);
                streamViews[i].AddView(buffer);
                buffer.Observer = joinStatementDispatch;
                preloadMethod.SetBuffer(buffer, i);
            }

            return(new JoinPlanResult(indicatorView, preloadMethod, joinSetComposerDesc));
        }
        private EPPreparedQueryResult Process(ICollection <EventBean>[] snapshots)
        {
            var numStreams = _processors.Length;

            UniformPair <EventBean[]> results;

            if (numStreams == 1)
            {
                if (_statementSpec.FilterRootNode != null)
                {
                    snapshots[0] = GetFiltered(snapshots[0], _statementSpec.FilterRootNode.AsSingleton());
                }
                EventBean[] rows = snapshots[0].ToArray();
                results = _resultSetProcessor.ProcessViewResult(rows, null, true);
            }
            else
            {
                var viewablePerStream = new Viewable[numStreams];
                for (var i = 0; i < numStreams; i++)
                {
                    var instance = _processors[i].GetProcessorInstance(_agentInstanceContext);
                    if (instance == null)
                    {
                        throw new UnsupportedOperationException("Joins against named windows that are under context are not supported");
                    }
                    viewablePerStream[i] = instance.TailViewInstance;
                }

                var           joinSetComposerDesc = _joinSetComposerPrototype.Create(viewablePerStream, true, _agentInstanceContext);
                var           joinComposer        = joinSetComposerDesc.JoinSetComposer;
                JoinSetFilter joinFilter;
                if (joinSetComposerDesc.PostJoinFilterEvaluator != null)
                {
                    joinFilter = new JoinSetFilter(joinSetComposerDesc.PostJoinFilterEvaluator);
                }
                else
                {
                    joinFilter = null;
                }

                var oldDataPerStream = new EventBean[numStreams][];
                var newDataPerStream = new EventBean[numStreams][];
                for (var i = 0; i < numStreams; i++)
                {
                    newDataPerStream[i] = snapshots[i].ToArray();
                }
                var result = joinComposer.Join(newDataPerStream, oldDataPerStream, _agentInstanceContext);
                if (joinFilter != null)
                {
                    joinFilter.Process(result.First, null, _agentInstanceContext);
                }
                results = _resultSetProcessor.ProcessJoinResult(result.First, null, true);
            }

            if (_statementSpec.SelectClauseSpec.IsDistinct)
            {
                results.First = EventBeanUtility.GetDistinctByProp(results.First, _eventBeanReader);
            }

            return(new EPPreparedQueryResult(_resultSetProcessor.ResultEventType, results.First));
        }