/* * ************************************************************************************* * 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.dataflow.core; import com.espertech.esper.client.annotation.AuditEnum; import com.espertech.esper.client.dataflow.EPDataFlowExceptionHandler; import com.espertech.esper.client.dataflow.EPDataFlowInstantiationOptions; import com.espertech.esper.client.dataflow.EPDataFlowSignal; import com.espertech.esper.core.service.EPServicesContext; import com.espertech.esper.core.service.StatementContext; import com.espertech.esper.dataflow.annotations.DataFlowContext; import com.espertech.esper.dataflow.interfaces.EPDataFlowEmitter; import com.espertech.esper.dataflow.util.*; import com.espertech.esper.util.JavaClassHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.*; public class RealizationFactoryInterface { private static final Log log = LogFactory.getLog(RealizationFactoryInterface.class); public static DataflowStartDesc realize(String dataFlowName, Map<Integer, Object> operators, Map<Integer, OperatorMetadataDescriptor> operatorMetadata, Set<Integer> operatorBuildOrder, List<LogicalChannelBinding> bindings, DataFlowSignalManager dataFlowSignalManager, EPDataFlowInstantiationOptions options, EPServicesContext services, StatementContext statementContext) { // First pass: inject runtime context Map<Integer, EPDataFlowEmitter> runtimeContexts = new HashMap<Integer, EPDataFlowEmitter>(); OperatorStatisticsProvider statisticsProvider = null; if (options.isOperatorStatistics()) { statisticsProvider = new OperatorStatisticsProvider(operatorMetadata); } boolean audit = AuditEnum.DATAFLOW_OP.getAudit(statementContext.getAnnotations()) != null; for (int producerOpNum : operatorBuildOrder) { String operatorPrettyPrint = operatorMetadata.get(producerOpNum).getOperatorPrettyPrint(); if (log.isDebugEnabled()) { log.debug("Generating runtime context for " + operatorPrettyPrint); } // determine the number of output streams Object producingOp = operators.get(producerOpNum); int numOutputStreams = operatorMetadata.get(producerOpNum).getOperatorSpec().getOutput().getItems().size(); List<ObjectBindingPair>[] targets = getOperatorConsumersPerStream(numOutputStreams, producerOpNum, operators, operatorMetadata, bindings); EPDataFlowEmitter runtimeContext = generateRuntimeContext(statementContext.getEngineURI(), statementContext.getStatementName(), audit, dataFlowName, producerOpNum, operatorPrettyPrint, dataFlowSignalManager, targets, options); if (options.isOperatorStatistics()) { runtimeContext = new EPDataFlowEmitterWrapperWStatistics(runtimeContext, producerOpNum, statisticsProvider, options.isCpuStatistics()); } JavaClassHelper.setFieldForAnnotation(producingOp, DataFlowContext.class, runtimeContext); runtimeContexts.put(producerOpNum, runtimeContext); } // Second pass: hook punctuation such that it gets forwarded for (int producerOpNum : operatorBuildOrder) { String operatorPrettyPrint = operatorMetadata.get(producerOpNum).getOperatorPrettyPrint(); if (log.isDebugEnabled()) { log.debug("Handling signals for " + operatorPrettyPrint); } // determine consumers that receive punctuation Set<Integer> consumingOperatorsWithPunctuation = new HashSet<Integer>(); for (LogicalChannelBinding binding : bindings) { if (!binding.getLogicalChannel().getOutputPort().isHasPunctuation() || binding.getLogicalChannel().getOutputPort().getProducingOpNum() != producerOpNum) { continue; } consumingOperatorsWithPunctuation.add(binding.getLogicalChannel().getConsumingOpNum()); } // hook up a listener for each for (int consumerPunc : consumingOperatorsWithPunctuation) { final EPDataFlowEmitter context = runtimeContexts.get(consumerPunc); if (context == null) { continue; } dataFlowSignalManager.addSignalListener(producerOpNum, new DataFlowSignalListener() { public void processSignal(EPDataFlowSignal signal) { context.submitSignal(signal); } }); } } return new DataflowStartDesc(statisticsProvider); } private static List<ObjectBindingPair>[] getOperatorConsumersPerStream(int numOutputStreams, int producingOperator, Map<Integer, Object> operators, Map<Integer, OperatorMetadataDescriptor> operatorMetadata, List<LogicalChannelBinding> bindings) { List<LogicalChannelBinding> channelsForProducer = LogicalChannelUtil.getBindingsConsuming(producingOperator, bindings); if (channelsForProducer.isEmpty()) { return null; } List<ObjectBindingPair>[] submitTargets = new List[numOutputStreams]; for (int i = 0; i < numOutputStreams; i++) { submitTargets[i] = new ArrayList<ObjectBindingPair>(); } for (LogicalChannelBinding binding : channelsForProducer) { int consumingOp = binding.getLogicalChannel().getConsumingOpNum(); Object operator = operators.get(consumingOp); int producingStreamNum = binding.getLogicalChannel().getOutputPort().getStreamNumber(); List<ObjectBindingPair> pairs = submitTargets[producingStreamNum]; OperatorMetadataDescriptor metadata = operatorMetadata.get(consumingOp); pairs.add(new ObjectBindingPair(operator, metadata.getOperatorPrettyPrint(), binding)); } return submitTargets; } private static SignalHandler getSignalHandler(int producerNum, Object target, LogicalChannelBindingMethodDesc consumingSignalBindingDesc) { if (consumingSignalBindingDesc == null) { return SignalHandlerDefault.INSTANCE; } else { if (consumingSignalBindingDesc.getBindingType() instanceof LogicalChannelBindingTypePassAlong) { return new SignalHandlerDefaultWInvoke(target, consumingSignalBindingDesc.getMethod()); } else if (consumingSignalBindingDesc.getBindingType() instanceof LogicalChannelBindingTypePassAlongWStream) { LogicalChannelBindingTypePassAlongWStream streamInfo = (LogicalChannelBindingTypePassAlongWStream) consumingSignalBindingDesc.getBindingType(); return new SignalHandlerDefaultWInvokeStream(target, consumingSignalBindingDesc.getMethod(), streamInfo.getStreamNum()); } else { throw new IllegalStateException("Unrecognized signal binding: " + consumingSignalBindingDesc.getBindingType()); } } } private static SubmitHandler getSubmitHandler(String engineURI, String statementName, boolean audit, String dataflowName, int producerOpNum, String operatorPrettyPrint, DataFlowSignalManager dataFlowSignalManager, ObjectBindingPair target, EPDataFlowExceptionHandler optionalExceptionHandler) { SignalHandler signalHandler = getSignalHandler(producerOpNum, target.getTarget(), target.getBinding().getConsumingSignalBindingDesc()); int receivingOpNum = target.getBinding().getLogicalChannel().getConsumingOpNum(); String receivingOpPretty = target.getBinding().getLogicalChannel().getConsumingOpPrettyPrint(); String receivingOpName = target.getBinding().getLogicalChannel().getConsumingOpName(); EPDataFlowEmitterExceptionHandler exceptionHandler = new EPDataFlowEmitterExceptionHandler(engineURI, statementName, audit, dataflowName, receivingOpName, receivingOpNum, receivingOpPretty, optionalExceptionHandler); LogicalChannelBindingType bindingType = target.getBinding().getConsumingBindingDesc().getBindingType(); if (bindingType instanceof LogicalChannelBindingTypePassAlong) { return new EPDataFlowEmitter1Stream1TargetPassAlong(producerOpNum, dataFlowSignalManager, signalHandler, exceptionHandler, target); } else if (bindingType instanceof LogicalChannelBindingTypePassAlongWStream) { LogicalChannelBindingTypePassAlongWStream type = (LogicalChannelBindingTypePassAlongWStream) bindingType; return new EPDataFlowEmitter1Stream1TargetPassAlongWStream(producerOpNum, dataFlowSignalManager, signalHandler, exceptionHandler, target, type.getStreamNum()); } else if (bindingType instanceof LogicalChannelBindingTypeUnwind) { return new EPDataFlowEmitter1Stream1TargetUnwind(producerOpNum, dataFlowSignalManager, signalHandler, exceptionHandler, target); } else { throw new UnsupportedOperationException("TODO"); } } private static EPDataFlowEmitter generateRuntimeContext(String engineURI, String statementName, boolean audit, String dataflowName, int producerOpNum, String operatorPrettyPrint, DataFlowSignalManager dataFlowSignalManager, List<ObjectBindingPair>[] targetsPerStream, EPDataFlowInstantiationOptions options) { // handle no targets if (targetsPerStream == null) { return new EPDataFlowEmitterNoTarget(producerOpNum, dataFlowSignalManager); } // handle single-stream case if (targetsPerStream.length == 1) { List<ObjectBindingPair> targets = targetsPerStream[0]; // handle single-stream single target case if (targets.size() == 1) { ObjectBindingPair target = targets.get(0); return getSubmitHandler(engineURI, statementName, audit, dataflowName, producerOpNum, operatorPrettyPrint, dataFlowSignalManager, target, options.getExceptionHandler()); } SubmitHandler[] handlers = new SubmitHandler[targets.size()]; for (int i = 0; i < handlers.length; i++) { handlers[i] = getSubmitHandler(engineURI, statementName, audit, dataflowName, producerOpNum, operatorPrettyPrint, dataFlowSignalManager, targets.get(i), options.getExceptionHandler()); } return new EPDataFlowEmitter1StreamNTarget(producerOpNum, dataFlowSignalManager, handlers); } // handle multi-stream case else { SubmitHandler[][] handlersPerStream = new SubmitHandler[targetsPerStream.length][]; for (int streamNum = 0; streamNum < targetsPerStream.length; streamNum++) { SubmitHandler[] handlers = new SubmitHandler[targetsPerStream[streamNum].size()]; handlersPerStream[streamNum] = handlers; for (int i = 0; i < handlers.length; i++) { handlers[i] = getSubmitHandler(engineURI, statementName, audit, dataflowName, producerOpNum, operatorPrettyPrint, dataFlowSignalManager, targetsPerStream[streamNum].get(i), options.getExceptionHandler()); } } return new EPDataFlowEmitterNStreamNTarget(producerOpNum, dataFlowSignalManager, handlersPerStream); } } }