public static ExprDotEvalDTMethodDesc ValidateMake( StreamTypeService streamTypeService, Deque <ExprChainedSpec> chainSpecStack, DatetimeMethodEnum dtMethod, String dtMethodName, EPType inputType, IList <ExprNode> parameters, ExprDotNodeFilterAnalyzerInput inputDesc, TimeZoneInfo timeZone) { // verify input String message = "Date-time enumeration method '" + dtMethodName + "' requires either a DateTime or long value as input or events of an event type that declares a timestamp property"; if (inputType is EventEPType) { if (((EventEPType)inputType).EventType.StartTimestampPropertyName == null) { throw new ExprValidationException(message); } } else { if (!(inputType is ClassEPType || inputType is NullEPType)) { throw new ExprValidationException(message + " but received " + EPTypeHelper.ToTypeDescriptive(inputType)); } if (inputType is ClassEPType) { ClassEPType classEPType = (ClassEPType)inputType; if (!TypeHelper.IsDateTime(classEPType.Clazz)) { throw new ExprValidationException( message + " but received " + classEPType.Clazz.GetTypeNameFullyQualPretty()); } } } IList <CalendarOp> calendarOps = new List <CalendarOp>(); ReformatOp reformatOp = null; IntervalOp intervalOp = null; DatetimeMethodEnum currentMethod = dtMethod; IList <ExprNode> currentParameters = parameters; String currentMethodName = dtMethodName; // drain all calendar ops ExprDotNodeFilterAnalyzerDesc filterAnalyzerDesc = null; while (true) { // handle the first one only if its a calendar op var evaluators = GetEvaluators(currentParameters); var opFactory = currentMethod.MetaData().OpFactory; // compile parameter abstract for validation against available footprints var footprintProvided = DotMethodUtil.GetProvidedFootprint(currentParameters); // validate parameters DotMethodUtil.ValidateParametersDetermineFootprint( currentMethod.Footprints(), DotMethodTypeEnum.DATETIME, currentMethodName, footprintProvided, DotMethodInputTypeMatcherImpl.DEFAULT_ALL); if (opFactory is CalendarOpFactory) { CalendarOp calendarOp = ((CalendarOpFactory)opFactory).GetOp(currentMethod, currentMethodName, currentParameters, evaluators); calendarOps.Add(calendarOp); } else if (opFactory is ReformatOpFactory) { reformatOp = ((ReformatOpFactory)opFactory).GetOp(timeZone, currentMethod, currentMethodName, currentParameters); // compile filter analyzer information if there are no calendar ops in the chain if (calendarOps.IsEmpty()) { filterAnalyzerDesc = reformatOp.GetFilterDesc(streamTypeService.EventTypes, currentMethod, currentParameters, inputDesc); } else { filterAnalyzerDesc = null; } } else if (opFactory is IntervalOpFactory) { intervalOp = ((IntervalOpFactory)opFactory).GetOp(streamTypeService, currentMethod, currentMethodName, currentParameters, evaluators); // compile filter analyzer information if there are no calendar ops in the chain if (calendarOps.IsEmpty()) { filterAnalyzerDesc = intervalOp.GetFilterDesc(streamTypeService.EventTypes, currentMethod, currentParameters, inputDesc); } else { filterAnalyzerDesc = null; } } else { throw new IllegalStateException("Invalid op factory class " + opFactory); } // see if there is more if (chainSpecStack.IsEmpty() || !DatetimeMethodEnumExtensions.IsDateTimeMethod(chainSpecStack.First.Name)) { break; } // pull next var next = chainSpecStack.RemoveFirst(); currentMethod = DatetimeMethodEnumExtensions.FromName(next.Name); currentParameters = next.Parameters; currentMethodName = next.Name; if ((reformatOp != null || intervalOp != null)) { throw new ExprValidationException("Invalid input for date-time method '" + next.Name + "'"); } } ExprDotEval dotEval; EPType returnType; dotEval = new ExprDotEvalDT(calendarOps, timeZone, reformatOp, intervalOp, EPTypeHelper.GetClassSingleValued(inputType), EPTypeHelper.GetEventTypeSingleValued(inputType)); returnType = dotEval.TypeInfo; return(new ExprDotEvalDTMethodDesc(dotEval, returnType, filterAnalyzerDesc)); }
public void Init( int?streamOfProviderIfApplicable, EnumMethodEnum enumMethodEnum, String enumMethodUsedName, EPType typeInfo, IList <ExprNode> parameters, ExprValidationContext validationContext) { var eventTypeColl = EPTypeHelper.GetEventTypeMultiValued(typeInfo); var eventTypeBean = EPTypeHelper.GetEventTypeSingleValued(typeInfo); var collectionComponentType = EPTypeHelper.GetClassMultiValued(typeInfo); _enumMethodEnum = enumMethodEnum; _enumMethodUsedName = enumMethodUsedName; _streamCountIncoming = validationContext.StreamTypeService.EventTypes.Length; if (eventTypeColl == null && collectionComponentType == null && eventTypeBean == null) { throw new ExprValidationException( "Invalid input for built-in enumeration method '" + enumMethodUsedName + "', expecting collection of event-type or scalar values as input, received " + EPTypeHelper.ToTypeDescriptive(typeInfo)); } // compile parameter abstract for validation against available footprints var footprintProvided = DotMethodUtil.GetProvidedFootprint(parameters); // validate parameters DotMethodInputTypeMatcher inputTypeMatcher = new ProxyDotMethodInputTypeMatcher { ProcMatches = fp => { if (fp.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeBean == null && eventTypeColl == null) { return(false); } if (fp.Input == DotMethodFPInputEnum.SCALAR_ANY && collectionComponentType == null) { return(false); } return(true); } }; var footprint = DotMethodUtil.ValidateParametersDetermineFootprint( enumMethodEnum.GetFootprints(), DotMethodTypeEnum.ENUM, enumMethodUsedName, footprintProvided, inputTypeMatcher); // validate input criteria met for this footprint if (footprint.Input != DotMethodFPInputEnum.ANY) { var message = "Invalid input for built-in enumeration method '" + enumMethodUsedName + "' and " + footprint.Parameters.Length + "-parameter footprint, expecting collection of "; var received = " as input, received " + EPTypeHelper.ToTypeDescriptive(typeInfo); if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeColl == null) { throw new ExprValidationException(message + "events" + received); } if (footprint.Input.IsScalar() && collectionComponentType == null) { throw new ExprValidationException(message + "values (typically scalar values)" + received); } if (footprint.Input == DotMethodFPInputEnum.SCALAR_NUMERIC && !collectionComponentType.IsNumeric()) { throw new ExprValidationException(message + "numeric values" + received); } } // manage context of this lambda-expression in regards to outer lambda-expression that may call this one. ExpressionResultCacheForEnumerationMethod enumerationMethodCache = validationContext.ExprEvaluatorContext.ExpressionResultCacheService.AllocateEnumerationMethod; enumerationMethodCache.PushStack(this); var bodiesAndParameters = new List <ExprDotEvalParam>(); var count = 0; var inputEventType = eventTypeBean ?? eventTypeColl; foreach (var node in parameters) { var bodyAndParameter = GetBodyAndParameter( enumMethodUsedName, count++, node, inputEventType, collectionComponentType, validationContext, bodiesAndParameters, footprint); bodiesAndParameters.Add(bodyAndParameter); } _enumEval = GetEnumEval( validationContext.EngineImportService, validationContext.EventAdapterService, validationContext.StreamTypeService, validationContext.StatementId, enumMethodUsedName, bodiesAndParameters, inputEventType, collectionComponentType, _streamCountIncoming, validationContext.IsDisablePropertyExpressionEventCollCache); _enumEvalNumRequiredEvents = _enumEval.StreamNumSize; // determine the stream ids of event properties asked for in the Evaluator(s) var streamsRequired = new HashSet <int>(); var visitor = new ExprNodeIdentifierCollectVisitor(); foreach (var desc in bodiesAndParameters) { desc.Body.Accept(visitor); foreach (var ident in visitor.ExprProperties) { streamsRequired.Add(ident.StreamId); } } if (streamOfProviderIfApplicable != null) { streamsRequired.Add(streamOfProviderIfApplicable.Value); } // We turn on caching if the stack is not empty (we are an inner lambda) and the dependency does not include the stream. var isInner = !enumerationMethodCache.PopLambda(); if (isInner) { // If none of the properties that the current lambda uses comes from the ultimate Parent(s) or subsequent streams, then cache. var parents = enumerationMethodCache.GetStack(); var found = false; foreach (var req in streamsRequired) { var first = (ExprDotEvalEnumMethodBase)parents.First; var parentIncoming = first._streamCountIncoming - 1; var selfAdded = _streamCountIncoming; // the one we use ourselfs if (req > parentIncoming && req < selfAdded) { found = true; } } _cache = !found; } }
public static ExprDotNodeRealizedChain GetChainEvaluators( int? streamOfProviderIfApplicable, EPType inputType, IList<ExprChainedSpec> chainSpec, ExprValidationContext validationContext, bool isDuckTyping, ExprDotNodeFilterAnalyzerInput inputDesc) { IList<ExprDotForge> methodForges = new List<ExprDotForge>(); var currentInputType = inputType; EnumMethodEnum? lastLambdaFunc = null; var lastElement = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1]; FilterExprAnalyzerAffector filterAnalyzerDesc = null; Deque<ExprChainedSpec> chainSpecStack = new ArrayDeque<ExprChainedSpec>(chainSpec); while (!chainSpecStack.IsEmpty()) { var chainElement = chainSpecStack.RemoveFirst(); lastLambdaFunc = null; // reset // compile parameters for chain element var paramForges = new ExprForge[chainElement.Parameters.Count]; var paramTypes = new Type[chainElement.Parameters.Count]; for (var i = 0; i < chainElement.Parameters.Count; i++) { paramForges[i] = chainElement.Parameters[i].Forge; paramTypes[i] = paramForges[i].EvaluationType; } // check if special 'size' method if (currentInputType is ClassMultiValuedEPType) { var type = (ClassMultiValuedEPType) currentInputType; if (chainElement.Name.Equals("size", StringComparison.InvariantCultureIgnoreCase) && paramTypes.Length == 0 && lastElement == chainElement) { var sizeExpr = new ExprDotForgeArraySize(); methodForges.Add(sizeExpr); currentInputType = sizeExpr.TypeInfo; continue; } if (chainElement.Name.Equals("get", StringComparison.InvariantCultureIgnoreCase) && paramTypes.Length == 1 && Boxing.GetBoxedType(paramTypes[0]) == typeof(int?)) { var componentType = Boxing.GetBoxedType(type.Component); var get = new ExprDotForgeArrayGet(paramForges[0], componentType); methodForges.Add(get); currentInputType = get.TypeInfo; continue; } } // determine if there is a matching method var matchingMethod = false; var methodTarget = GetMethodTarget(currentInputType); if (methodTarget != null) { try { GetValidateMethodDescriptor( methodTarget, chainElement.Name, chainElement.Parameters, validationContext); matchingMethod = true; } catch (ExprValidationException) { // expected } } if (EnumMethodEnumExtensions.IsEnumerationMethod(chainElement.Name) && (!matchingMethod || methodTarget.IsArray || methodTarget.IsGenericCollection())) { var enumerationMethod = EnumMethodEnumExtensions.FromName(chainElement.Name); if (enumerationMethod == null) { throw new EPException("unable to determine enumeration method from name"); } var eval = TypeHelper.Instantiate<ExprDotForgeEnumMethod>( enumerationMethod.Value.GetImplementation()); eval.Init( streamOfProviderIfApplicable, enumerationMethod.Value, chainElement.Name, currentInputType, chainElement.Parameters, validationContext); currentInputType = eval.TypeInfo; if (currentInputType == null) { throw new IllegalStateException( "Enumeration method '" + chainElement.Name + "' has not returned type information"); } methodForges.Add(eval); lastLambdaFunc = enumerationMethod; continue; } // resolve datetime if (DatetimeMethodEnumHelper.IsDateTimeMethod(chainElement.Name) && (!matchingMethod || methodTarget == typeof(DateTimeEx) || methodTarget == typeof(DateTimeOffset) || methodTarget == typeof(DateTime))) { var dateTimeMethod = DatetimeMethodEnumHelper.FromName(chainElement.Name); var datetimeImpl = ExprDotDTFactory.ValidateMake( validationContext.StreamTypeService, chainSpecStack, dateTimeMethod, chainElement.Name, currentInputType, chainElement.Parameters, inputDesc, validationContext.ImportService.TimeAbacus, null, validationContext.TableCompileTimeResolver); currentInputType = datetimeImpl.ReturnType; if (currentInputType == null) { throw new IllegalStateException( "Date-time method '" + chainElement.Name + "' has not returned type information"); } methodForges.Add(datetimeImpl.Forge); filterAnalyzerDesc = datetimeImpl.IntervalFilterDesc; continue; } // try to resolve as property if the last method returned a type if (currentInputType is EventEPType) { var inputEventType = (EventTypeSPI) ((EventEPType) currentInputType).EventType; var type = inputEventType.GetPropertyType(chainElement.Name); var getter = inputEventType.GetGetterSPI(chainElement.Name); if (type != null && getter != null) { var noduck = new ExprDotForgeProperty( getter, EPTypeHelper.SingleValue(Boxing.GetBoxedType(type))); methodForges.Add(noduck); currentInputType = EPTypeHelper.SingleValue(EPTypeHelper.GetClassSingleValued(noduck.TypeInfo)); continue; } } // Finally try to resolve the method if (methodTarget != null) { try { // find descriptor again, allow for duck typing var desc = GetValidateMethodDescriptor( methodTarget, chainElement.Name, chainElement.Parameters, validationContext); paramForges = desc.ChildForges; ExprDotForge forge; if (currentInputType is ClassEPType) { // if followed by an enumeration method, convert array to collection if (desc.ReflectionMethod.ReturnType.IsArray && !chainSpecStack.IsEmpty() && EnumMethodEnumExtensions.IsEnumerationMethod(chainSpecStack.First.Name)) { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.WRAPARRAY); } else { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.PLAIN); } } else { forge = new ExprDotMethodForgeNoDuck( validationContext.StatementName, desc.ReflectionMethod, paramForges, ExprDotMethodForgeNoDuck.DuckType.UNDERLYING); } methodForges.Add(forge); currentInputType = forge.TypeInfo; } catch (Exception e) { if (!isDuckTyping) { throw new ExprValidationException(e.Message, e); } var duck = new ExprDotMethodForgeDuck( validationContext.StatementName, validationContext.ImportService, chainElement.Name, paramTypes, paramForges); methodForges.Add(duck); currentInputType = duck.TypeInfo; } continue; } var message = "Could not find event property, enumeration method or instance method named '" + chainElement.Name + "' in " + EPTypeHelper.ToTypeDescriptive(currentInputType); throw new ExprValidationException(message); } var intermediateEvals = methodForges.ToArray(); if (lastLambdaFunc != null) { ExprDotForge finalEval = null; if (currentInputType is EventMultiValuedEPType) { var mvType = (EventMultiValuedEPType) currentInputType; var tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(mvType.Component); if (tableMetadata != null) { finalEval = new ExprDotForgeUnpackCollEventBeanTable(mvType.Component, tableMetadata); } else { finalEval = new ExprDotForgeUnpackCollEventBean(mvType.Component); } } else if (currentInputType is EventEPType) { var epType = (EventEPType) currentInputType; var tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(epType.EventType); if (tableMetadata != null) { finalEval = new ExprDotForgeUnpackBeanTable(epType.EventType, tableMetadata); } else { finalEval = new ExprDotForgeUnpackBean(epType.EventType); } } if (finalEval != null) { methodForges.Add(finalEval); } } var unpackingForges = methodForges.ToArray(); return new ExprDotNodeRealizedChain(intermediateEvals, unpackingForges, filterAnalyzerDesc); }