public static ExprDotNodeRealizedChain GetChainEvaluators( int?streamOfProviderIfApplicable, EPType inputType, IList <ExprChainedSpec> chainSpec, ExprValidationContext validationContext, bool isDuckTyping, ExprDotNodeFilterAnalyzerInput inputDesc) { var methodEvals = new List <ExprDotEval>(); var currentInputType = inputType; EnumMethodEnum?lastLambdaFunc = null; var lastElement = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1]; ExprDotNodeFilterAnalyzerDesc filterAnalyzerDesc = null; var chainSpecStack = new ArrayDeque <ExprChainedSpec>(chainSpec); while (!chainSpecStack.IsEmpty()) { var chainElement = chainSpecStack.RemoveFirst(); lastLambdaFunc = null; // reset // compile parameters for chain element var paramEvals = new ExprEvaluator[chainElement.Parameters.Count]; var paramTypes = new Type[chainElement.Parameters.Count]; for (var i = 0; i < chainElement.Parameters.Count; i++) { paramEvals[i] = chainElement.Parameters[i].ExprEvaluator; paramTypes[i] = paramEvals[i].ReturnType; } // check if special 'size' method if (currentInputType is ClassMultiValuedEPType) { var type = (ClassMultiValuedEPType)currentInputType; if ((chainElement.Name.ToLower() == "size") && paramTypes.Length == 0 && Equals(lastElement, chainElement)) { var sizeExpr = new ExprDotEvalArraySize(); methodEvals.Add(sizeExpr); currentInputType = sizeExpr.TypeInfo; continue; } if ((chainElement.Name.ToLower() == "get") && paramTypes.Length == 1 && paramTypes[0].GetBoxedType() == typeof(int?)) { var componentType = type.Component; var get = new ExprDotEvalArrayGet(paramEvals[0], componentType); methodEvals.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 } } // resolve lambda if (chainElement.Name.IsEnumerationMethod() && (!matchingMethod || methodTarget.IsArray || methodTarget.IsImplementsInterface(typeof(ICollection <object>)))) { var enumerationMethod = EnumMethodEnumExtensions.FromName(chainElement.Name); var eval = TypeHelper.Instantiate <ExprDotEvalEnumMethod>(enumerationMethod.GetImplementation()); eval.Init(streamOfProviderIfApplicable, enumerationMethod, chainElement.Name, currentInputType, chainElement.Parameters, validationContext); currentInputType = eval.TypeInfo; if (currentInputType == null) { throw new IllegalStateException("Enumeration method '" + chainElement.Name + "' has not returned type information"); } methodEvals.Add(eval); lastLambdaFunc = enumerationMethod; continue; } // resolve datetime if (chainElement.Name.IsDateTimeMethod() && (!matchingMethod || methodTarget == typeof(DateTimeOffset?))) { var datetimeMethod = DatetimeMethodEnumExtensions.FromName(chainElement.Name); var datetimeImpl = ExprDotEvalDTFactory.ValidateMake( validationContext.StreamTypeService, chainSpecStack, datetimeMethod, chainElement.Name, currentInputType, chainElement.Parameters, inputDesc, validationContext.EngineImportService.TimeZone, validationContext.EngineImportService.TimeAbacus); currentInputType = datetimeImpl.ReturnType; if (currentInputType == null) { throw new IllegalStateException("Date-time method '" + chainElement.Name + "' has not returned type information"); } methodEvals.Add(datetimeImpl.Eval); filterAnalyzerDesc = datetimeImpl.IntervalFilterDesc; continue; } // try to resolve as property if the last method returned a type if (currentInputType is EventEPType) { var inputEventType = ((EventEPType)currentInputType).EventType; var type = inputEventType.GetPropertyType(chainElement.Name); var getter = inputEventType.GetGetter(chainElement.Name); if (type != null && getter != null) { var noduck = new ExprDotEvalProperty(getter, EPTypeHelper.SingleValue(type.GetBoxedType())); methodEvals.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); var fastMethod = desc.FastMethod; paramEvals = desc.ChildEvals; ExprDotEval eval; if (currentInputType is ClassEPType) { // if followed by an enumeration method, convert array to collection if (fastMethod.ReturnType.IsArray && !chainSpecStack.IsEmpty() && chainSpecStack.First.Name.IsEnumerationMethod()) { eval = new ExprDotMethodEvalNoDuckWrapArray(validationContext.StatementName, fastMethod, paramEvals); } else { eval = new ExprDotMethodEvalNoDuck(validationContext.StatementName, fastMethod, paramEvals); } } else { eval = new ExprDotMethodEvalNoDuckUnderlying(validationContext.StatementName, fastMethod, paramEvals); } methodEvals.Add(eval); currentInputType = eval.TypeInfo; } catch (Exception e) { if (!isDuckTyping) { throw new ExprValidationException(e.Message, e); } else { var duck = new ExprDotMethodEvalDuck(validationContext.StatementName, validationContext.EngineImportService, chainElement.Name, paramTypes, paramEvals); methodEvals.Add(duck); currentInputType = duck.TypeInfo; } } continue; } var message = "Could not find event property, enumeration method or instance method named '" + chainElement.Name + "' in " + currentInputType.ToTypeDescriptive(); throw new ExprValidationException(message); } var intermediateEvals = methodEvals.ToArray(); if (lastLambdaFunc != null) { ExprDotEval finalEval = null; if (currentInputType is EventMultiValuedEPType) { var mvType = (EventMultiValuedEPType)currentInputType; var tableMetadata = validationContext.TableService.GetTableMetadataFromEventType(mvType.Component); if (tableMetadata != null) { finalEval = new ExprDotEvalUnpackCollEventBeanTable(mvType.Component, tableMetadata); } else { finalEval = new ExprDotEvalUnpackCollEventBean(mvType.Component); } } else if (currentInputType is EventEPType) { var epType = (EventEPType)currentInputType; var tableMetadata = validationContext.TableService.GetTableMetadataFromEventType(epType.EventType); if (tableMetadata != null) { finalEval = new ExprDotEvalUnpackBeanTable(epType.EventType, tableMetadata); } else { finalEval = new ExprDotEvalUnpackBean(epType.EventType); } } if (finalEval != null) { methodEvals.Add(finalEval); } } var unpackingEvals = methodEvals.ToArray(); return(new ExprDotNodeRealizedChain(intermediateEvals, unpackingEvals, filterAnalyzerDesc)); }
public override ExprNode Validate(ExprValidationContext validationContext) { // check for plannable methods: these are validated according to different rules var appDotMethod = GetAppDotMethod(validationContext.IsFilterExpression); if (appDotMethod != null) { return appDotMethod; } // validate all parameters ExprNodeUtilityValidate.Validate(ExprNodeOrigin.DOTNODEPARAMETER, ChainSpec, validationContext); // determine if there are enumeration method expressions in the chain var hasEnumerationMethod = false; foreach (var chain in ChainSpec) { if (EnumMethodEnumExtensions.IsEnumerationMethod(chain.Name)) { hasEnumerationMethod = true; break; } } // determine if there is an implied binding, replace first chain element with evaluation node if there is if (validationContext.StreamTypeService.HasTableTypes && validationContext.TableCompileTimeResolver != null && ChainSpec.Count > 1 && ChainSpec[0].IsProperty) { var tableNode = TableCompileTimeUtil.GetTableNodeChainable( validationContext.StreamTypeService, ChainSpec, validationContext.ImportService, validationContext.TableCompileTimeResolver); if (tableNode != null) { var node = ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.DOTNODE, tableNode.First, validationContext); if (tableNode.Second.IsEmpty()) { return node; } ChainSpec.Clear(); ChainSpec.AddAll(tableNode.Second); AddChildNode(node); } } // The root node expression may provide the input value: // Such as "window(*).doIt(...)" or "(select * from Window).doIt()" or "prevwindow(sb).doIt(...)", in which case the expression to act on is a child expression // var streamTypeService = validationContext.StreamTypeService; if (ChildNodes.Length != 0) { // the root expression is the first child node var rootNode = ChildNodes[0]; // the root expression may also provide a lambda-function input (Iterator<EventBean>) // Determine collection-type and evaluator if any for root node var enumSrc = ExprDotNodeUtility.GetEnumerationSource( rootNode, validationContext.StreamTypeService, hasEnumerationMethod, validationContext.IsDisablePropertyExpressionEventCollCache, validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); EPType typeInfoX; if (enumSrc.ReturnType == null) { typeInfoX = EPTypeHelper.SingleValue( rootNode.Forge.EvaluationType); // not a collection type, treat as scalar } else { typeInfoX = enumSrc.ReturnType; } var evalsX = ExprDotNodeUtility.GetChainEvaluators( enumSrc.StreamOfProviderIfApplicable, typeInfoX, ChainSpec, validationContext, isDuckTyping, new ExprDotNodeFilterAnalyzerInputExpr()); forge = new ExprDotNodeForgeRootChild( this, null, null, null, hasEnumerationMethod, rootNode.Forge, enumSrc.Enumeration, typeInfoX, evalsX.Chain, evalsX.ChainWithUnpack, false); return null; } // No root node, and this is a 1-element chain i.e. "something(param,...)". // Plug-in single-row methods are not handled here. // Plug-in aggregation methods are not handled here. if (ChainSpec.Count == 1) { var spec = ChainSpec[0]; if (spec.Parameters.IsEmpty()) { throw HandleNotFound(spec.Name); } // single-parameter can resolve to a property Pair<PropertyResolutionDescriptor, string> propertyInfoPairX = null; try { propertyInfoPairX = ExprIdentNodeUtil.GetTypeFromStream( streamTypeService, spec.Name, streamTypeService.HasPropertyAgnosticType, false, validationContext.TableCompileTimeResolver); } catch (ExprValidationPropertyException) { // fine } // if not a property then try built-in single-row non-grammar functions if (propertyInfoPairX == null && spec.Name.ToLowerInvariant() .Equals(ImportServiceCompileTime.EXT_SINGLEROW_FUNCTION_TRANSPOSE)) { if (spec.Parameters.Count != 1) { throw new ExprValidationException( "The " + ImportServiceCompileTime.EXT_SINGLEROW_FUNCTION_TRANSPOSE + " function requires a single parameter expression"); } forge = new ExprDotNodeForgeTransposeAsStream(this, ChainSpec[0].Parameters[0].Forge); } else if (spec.Parameters.Count != 1) { throw HandleNotFound(spec.Name); } else { if (propertyInfoPairX == null) { throw new ExprValidationException( "Unknown single-row function, aggregation function or mapped or indexed property named '" + spec.Name + "' could not be resolved"); } forge = GetPropertyPairEvaluator(spec.Parameters[0].Forge, propertyInfoPairX, validationContext); } return null; } // handle the case where the first chain spec element is a stream name. ExprValidationException prefixedStreamNumException = null; var prefixedStreamNumber = PrefixedStreamName(ChainSpec, validationContext.StreamTypeService); if (prefixedStreamNumber != -1) { var specAfterStreamName = ChainSpec[1]; // Attempt to resolve as property Pair<PropertyResolutionDescriptor, string> propertyInfoPairX = null; try { var propName = ChainSpec[0].Name + "." + specAfterStreamName.Name; propertyInfoPairX = ExprIdentNodeUtil.GetTypeFromStream( streamTypeService, propName, streamTypeService.HasPropertyAgnosticType, false, validationContext.TableCompileTimeResolver); } catch (ExprValidationPropertyException) { // fine } if (propertyInfoPairX != null) { if (specAfterStreamName.Parameters.Count != 1) { throw HandleNotFound(specAfterStreamName.Name); } forge = GetPropertyPairEvaluator( specAfterStreamName.Parameters[0].Forge, propertyInfoPairX, validationContext); return null; } // Attempt to resolve as event-underlying object instance method var eventType = validationContext.StreamTypeService.EventTypes[prefixedStreamNumber]; var type = eventType.UnderlyingType; IList<ExprChainedSpec> remainderChain = new List<ExprChainedSpec>(ChainSpec); remainderChain.RemoveAt(0); ExprValidationException methodEx = null; ExprDotForge[] underlyingMethodChain = null; try { var typeInfoX = EPTypeHelper.SingleValue(type); if (validationContext.TableCompileTimeResolver.ResolveTableFromEventType(eventType) != null) { typeInfoX = new ClassEPType(typeof(object[])); } underlyingMethodChain = ExprDotNodeUtility.GetChainEvaluators( prefixedStreamNumber, typeInfoX, remainderChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStream(prefixedStreamNumber)) .ChainWithUnpack; } catch (ExprValidationException ex) { methodEx = ex; // expected - may not be able to find the methods on the underlying } ExprDotForge[] eventTypeMethodChain = null; ExprValidationException enumDatetimeEx = null; FilterExprAnalyzerAffector filterExprAnalyzerAffector = null; try { var typeInfoX = EPTypeHelper.SingleEvent(eventType); var chain = ExprDotNodeUtility.GetChainEvaluators( prefixedStreamNumber, typeInfoX, remainderChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStream(prefixedStreamNumber)); eventTypeMethodChain = chain.ChainWithUnpack; filterExprAnalyzerAffector = chain.FilterAnalyzerDesc; } catch (ExprValidationException ex) { enumDatetimeEx = ex; // expected - may not be able to find the methods on the underlying } if (underlyingMethodChain != null) { forge = new ExprDotNodeForgeStream( this, filterExprAnalyzerAffector, prefixedStreamNumber, eventType, underlyingMethodChain, true); } else if (eventTypeMethodChain != null) { forge = new ExprDotNodeForgeStream( this, filterExprAnalyzerAffector, prefixedStreamNumber, eventType, eventTypeMethodChain, false); } if (forge != null) { return null; } if (ExprDotNodeUtility.IsDatetimeOrEnumMethod(remainderChain[0].Name)) { prefixedStreamNumException = enumDatetimeEx; } else { prefixedStreamNumException = new ExprValidationException( "Failed to solve '" + remainderChain[0].Name + "' to either an date-time or enumeration method, an event property or a method on the event underlying object: " + methodEx.Message, methodEx); } } // There no root node, in this case the classname or property name is provided as part of the chain. // Such as "MyClass.myStaticLib(...)" or "mycollectionproperty.doIt(...)" // IList<ExprChainedSpec> modifiedChain = new List<ExprChainedSpec>(ChainSpec); var firstItem = modifiedChain.DeleteAt(0); Pair<PropertyResolutionDescriptor, string> propertyInfoPair = null; try { propertyInfoPair = ExprIdentNodeUtil.GetTypeFromStream( streamTypeService, firstItem.Name, streamTypeService.HasPropertyAgnosticType, true, validationContext.TableCompileTimeResolver); } catch (ExprValidationPropertyException) { // not a property } // If property then treat it as such if (propertyInfoPair != null) { var propertyName = propertyInfoPair.First.PropertyName; var streamId = propertyInfoPair.First.StreamNum; var streamType = streamTypeService.EventTypes[streamId]; EPType typeInfoX; ExprEnumerationForge enumerationForge = null; EPType inputType; ExprForge rootNodeForge = null; EventPropertyGetterSPI getter; if (firstItem.Parameters.IsEmpty()) { getter = ((EventTypeSPI) streamType).GetGetterSPI(propertyInfoPair.First.PropertyName); var propertyEval = ExprDotNodeUtility.GetPropertyEnumerationSource( propertyInfoPair.First.PropertyName, streamId, streamType, hasEnumerationMethod, validationContext.IsDisablePropertyExpressionEventCollCache); typeInfoX = propertyEval.ReturnType; enumerationForge = propertyEval.Enumeration; inputType = propertyEval.ReturnType; rootNodeForge = new PropertyDotNonLambdaForge( streamId, getter, propertyInfoPair.First.PropertyType.GetBoxedType()); } else { // property with parameter - mapped or indexed property var desc = EventTypeUtility.GetNestablePropertyDescriptor( streamTypeService.EventTypes[propertyInfoPair.First.StreamNum], firstItem.Name); if (firstItem.Parameters.Count > 1) { throw new ExprValidationException( "Property '" + firstItem.Name + "' may not be accessed passing 2 or more parameters"); } var paramEval = firstItem.Parameters[0].Forge; typeInfoX = EPTypeHelper.SingleValue(desc.PropertyComponentType); inputType = typeInfoX; getter = null; if (desc.IsMapped) { if (paramEval.EvaluationType != typeof(string)) { throw new ExprValidationException( "Parameter expression to mapped property '" + propertyName + "' is expected to return a string-type value but returns " + paramEval.EvaluationType.CleanName()); } var mappedGetter = ((EventTypeSPI) propertyInfoPair.First.StreamEventType).GetGetterMappedSPI( propertyInfoPair.First.PropertyName); if (mappedGetter == null) { throw new ExprValidationException( "Mapped property named '" + propertyName + "' failed to obtain getter-object"); } rootNodeForge = new PropertyDotNonLambdaMappedForge( streamId, mappedGetter, paramEval, desc.PropertyComponentType); } if (desc.IsIndexed) { if (paramEval.EvaluationType.GetBoxedType() != typeof(int?)) { throw new ExprValidationException( "Parameter expression to mapped property '" + propertyName + "' is expected to return a Integer-type value but returns " + paramEval.EvaluationType.CleanName()); } var indexedGetter = ((EventTypeSPI) propertyInfoPair.First.StreamEventType).GetGetterIndexedSPI( propertyInfoPair.First.PropertyName); if (indexedGetter == null) { throw new ExprValidationException( "Mapped property named '" + propertyName + "' failed to obtain getter-object"); } rootNodeForge = new PropertyDotNonLambdaIndexedForge( streamId, indexedGetter, paramEval, desc.PropertyComponentType); } } if (typeInfoX == null) { throw new ExprValidationException( "Property '" + propertyName + "' is not a mapped or indexed property"); } // try to build chain based on the input (non-fragment) ExprDotNodeRealizedChain evalsX; var filterAnalyzerInputProp = new ExprDotNodeFilterAnalyzerInputProp( propertyInfoPair.First.StreamNum, propertyInfoPair.First.PropertyName); var rootIsEventBean = false; try { evalsX = ExprDotNodeUtility.GetChainEvaluators( streamId, inputType, modifiedChain, validationContext, isDuckTyping, filterAnalyzerInputProp); } catch (ExprValidationException) { // try building the chain based on the fragment event type (i.e. A.after(B) based on A-configured start time where A is a fragment) var fragment = propertyInfoPair.First.FragmentEventType; if (fragment == null) { throw; } EPType fragmentTypeInfo; if (fragment.IsIndexed) { fragmentTypeInfo = EPTypeHelper.CollectionOfEvents(fragment.FragmentType); } else { fragmentTypeInfo = EPTypeHelper.SingleEvent(fragment.FragmentType); } rootIsEventBean = true; evalsX = ExprDotNodeUtility.GetChainEvaluators( propertyInfoPair.First.StreamNum, fragmentTypeInfo, modifiedChain, validationContext, isDuckTyping, filterAnalyzerInputProp); rootNodeForge = new PropertyDotNonLambdaFragmentForge(streamId, getter); } var filterExprAnalyzerAffector = evalsX.FilterAnalyzerDesc; var streamNumReferenced = propertyInfoPair.First.StreamNum; var rootPropertyName = propertyInfoPair.First.PropertyName; forge = new ExprDotNodeForgeRootChild( this, filterExprAnalyzerAffector, streamNumReferenced, rootPropertyName, hasEnumerationMethod, rootNodeForge, enumerationForge, inputType, evalsX.Chain, evalsX.ChainWithUnpack, !rootIsEventBean); return null; } // If variable then resolve as such var variable = validationContext.VariableCompileTimeResolver.Resolve(firstItem.Name); if (variable != null) { if (variable.OptionalContextName != null) { throw new ExprValidationException( "Method invocation on context-specific variable is not supported"); } EPType typeInfoX; ExprDotStaticMethodWrap wrap; if (variable.Type.IsArray) { typeInfoX = EPTypeHelper.CollectionOfSingleValue( variable.Type.GetElementType(), variable.Type); wrap = new ExprDotStaticMethodWrapArrayScalar(variable.VariableName, variable.Type); } else if (variable.EventType != null) { typeInfoX = EPTypeHelper.SingleEvent(variable.EventType); wrap = null; } else { typeInfoX = EPTypeHelper.SingleValue(variable.Type); wrap = null; } var evalsX = ExprDotNodeUtility.GetChainEvaluators( null, typeInfoX, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); forge = new ExprDotNodeForgeVariable(this, variable, wrap, evalsX.ChainWithUnpack); return null; } // try resolve as enumeration class with value var enumconstant = ImportCompileTimeUtil.ResolveIdentAsEnumConst( firstItem.Name, validationContext.ImportService, false); if (enumconstant != null) { // try resolve method var methodSpec = modifiedChain[0]; var enumvalue = firstItem.Name; ExprNodeUtilResolveExceptionHandler handler = new ProxyExprNodeUtilResolveExceptionHandler { ProcHandle = ex => { return new ExprValidationException( "Failed to resolve method '" + methodSpec.Name + "' on enumeration value '" + enumvalue + "': " + ex.Message); } }; var wildcardType = validationContext.StreamTypeService.EventTypes.Length != 1 ? null : validationContext.StreamTypeService.EventTypes[0]; var methodDesc = ExprNodeUtilityResolve.ResolveMethodAllowWildcardAndStream( enumconstant.GetType().Name, enumconstant.GetType(), methodSpec.Name, methodSpec.Parameters, wildcardType != null, wildcardType, handler, methodSpec.Name, validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); // method resolved, hook up modifiedChain.RemoveAt(0); // we identified this piece var optionalLambdaWrapX = ExprDotStaticMethodWrapFactory.Make( methodDesc.ReflectionMethod, modifiedChain, null, validationContext); var typeInfoX = optionalLambdaWrapX != null ? optionalLambdaWrapX.TypeInfo : EPTypeHelper.SingleValue(methodDesc.ReflectionMethod.ReturnType); var evalsX = ExprDotNodeUtility.GetChainEvaluators( null, typeInfoX, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); forge = new ExprDotNodeForgeStaticMethod( this, false, firstItem.Name, methodDesc.ReflectionMethod, methodDesc.ChildForges, false, evalsX.ChainWithUnpack, optionalLambdaWrapX, false, enumconstant, validationContext.StatementName); return null; } // if prefixed by a stream name, we are giving up if (prefixedStreamNumException != null) { throw prefixedStreamNumException; } // If class then resolve as class var secondItem = modifiedChain.DeleteAt(0); var allowWildcard = validationContext.StreamTypeService.EventTypes.Length == 1; EventType streamZeroType = null; if (validationContext.StreamTypeService.EventTypes.Length > 0) { streamZeroType = validationContext.StreamTypeService.EventTypes[0]; } var method = ExprNodeUtilityResolve.ResolveMethodAllowWildcardAndStream( firstItem.Name, null, secondItem.Name, secondItem.Parameters, allowWildcard, streamZeroType, new ExprNodeUtilResolveExceptionHandlerDefault(firstItem.Name + "." + secondItem.Name, false), secondItem.Name, validationContext.StatementRawInfo, validationContext.StatementCompileTimeService); var isConstantParameters = method.IsAllConstants && isUDFCache; var isReturnsConstantResult = isConstantParameters && modifiedChain.IsEmpty(); // this may return a pair of null if there is no lambda or the result cannot be wrapped for lambda-function use var optionalLambdaWrap = ExprDotStaticMethodWrapFactory.Make( method.ReflectionMethod, modifiedChain, null, validationContext); var typeInfo = optionalLambdaWrap != null ? optionalLambdaWrap.TypeInfo : EPTypeHelper.SingleValue(method.ReflectionMethod.ReturnType); var evals = ExprDotNodeUtility.GetChainEvaluators( null, typeInfo, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); forge = new ExprDotNodeForgeStaticMethod( this, isReturnsConstantResult, firstItem.Name, method.ReflectionMethod, method.ChildForges, isConstantParameters, evals.ChainWithUnpack, optionalLambdaWrap, false, null, validationContext.StatementName); return null; }
public static ExprNodeUtilMethodDesc ResolveMethodAllowWildcardAndStream( string className, Type optionalClass, string methodName, IList<ExprNode> parameters, bool allowWildcard, EventType wildcardType, ExprNodeUtilResolveExceptionHandler exceptionHandler, string functionName, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { var paramTypes = new Type[parameters.Count]; var childForges = new ExprForge[parameters.Count]; var count = 0; var allowEventBeanType = new bool[parameters.Count]; var allowEventBeanCollType = new bool[parameters.Count]; var childEvalsEventBeanReturnTypesForges = new ExprForge[parameters.Count]; var allConstants = true; foreach (var childNode in parameters) { if (!EnumMethodEnumExtensions.IsEnumerationMethod(methodName) && childNode is ExprLambdaGoesNode) { throw new ExprValidationException( "Unexpected lambda-expression encountered as parameter to UDF or static method '" + methodName + "'"); } if (childNode is ExprWildcard) { if (wildcardType == null || !allowWildcard) { throw new ExprValidationException("Failed to resolve wildcard parameter to a given event type"); } childForges[count] = new ExprEvalStreamNumUnd(0, wildcardType.UnderlyingType); childEvalsEventBeanReturnTypesForges[count] = new ExprEvalStreamNumEvent(0); paramTypes[count] = wildcardType.UnderlyingType; allowEventBeanType[count] = true; allConstants = false; count++; continue; } if (childNode is ExprStreamUnderlyingNode) { var und = (ExprStreamUnderlyingNode) childNode; var tableMetadata = services.TableCompileTimeResolver.ResolveTableFromEventType(und.EventType); if (tableMetadata == null) { childForges[count] = childNode.Forge; childEvalsEventBeanReturnTypesForges[count] = new ExprEvalStreamNumEvent(und.StreamId); } else { childForges[count] = new ExprEvalStreamTable( und.StreamId, und.EventType.UnderlyingType, tableMetadata); childEvalsEventBeanReturnTypesForges[count] = new ExprEvalStreamNumEventTable(und.StreamId, tableMetadata); } paramTypes[count] = childForges[count].EvaluationType; allowEventBeanType[count] = true; allConstants = false; count++; continue; } if (childNode.Forge is ExprEnumerationForge) { var enumeration = (ExprEnumerationForge) childNode.Forge; var eventType = enumeration.GetEventTypeSingle(statementRawInfo, services); childForges[count] = childNode.Forge; paramTypes[count] = childForges[count].EvaluationType; allConstants = false; if (eventType != null) { childEvalsEventBeanReturnTypesForges[count] = new ExprEvalStreamNumEnumSingleForge(enumeration); allowEventBeanType[count] = true; count++; continue; } var eventTypeColl = enumeration.GetEventTypeCollection(statementRawInfo, services); if (eventTypeColl != null) { childEvalsEventBeanReturnTypesForges[count] = new ExprEvalStreamNumEnumCollForge(enumeration); allowEventBeanCollType[count] = true; count++; continue; } } paramTypes[count] = childNode.Forge.EvaluationType; childForges[count] = childNode.Forge; count++; if (!childNode.Forge.ForgeConstantType.IsCompileTimeConstant) { allConstants = false; } } // Try to resolve the method MethodInfo method; try { if (optionalClass != null) { method = services.ImportServiceCompileTime.ResolveMethod( optionalClass, methodName, paramTypes, allowEventBeanType); } else { method = services.ImportServiceCompileTime.ResolveMethodOverloadChecked( className, methodName, paramTypes, allowEventBeanType, allowEventBeanCollType); } } catch (Exception e) { throw exceptionHandler.Handle(e); } var parameterTypes = method.GetParameterTypes(); // rewrite those evaluator that should return the event itself if (CollectionUtil.IsAnySet(allowEventBeanType)) { for (var i = 0; i < parameters.Count; i++) { if (allowEventBeanType[i] && parameterTypes[i] == typeof(EventBean)) { childForges[i] = childEvalsEventBeanReturnTypesForges[i]; } } } // rewrite those evaluators that should return the event collection if (CollectionUtil.IsAnySet(allowEventBeanCollType)) { for (var i = 0; i < parameters.Count; i++) { if (allowEventBeanCollType[i] && (parameterTypes[i] == typeof(ICollection<EventBean>))) { childForges[i] = childEvalsEventBeanReturnTypesForges[i]; } } } // add an evaluator if the method expects a context object if (!method.IsVarArgs() && parameterTypes.Length > 0 && parameterTypes[parameterTypes.Length - 1] == typeof(EPLMethodInvocationContext)) { var node = new ExprEvalMethodContext(functionName); childForges = (ExprForge[]) CollectionUtil.ArrayExpandAddSingle(childForges, node); } // handle varargs if (method.IsVarArgs()) { // handle context parameter var numMethodParams = parameterTypes.Length; if (numMethodParams > 1 && parameterTypes[numMethodParams - 2] == typeof(EPLMethodInvocationContext)) { var rewrittenForges = new ExprForge[childForges.Length + 1]; Array.Copy(childForges, 0, rewrittenForges, 0, numMethodParams - 2); rewrittenForges[numMethodParams - 2] = new ExprEvalMethodContext(functionName); Array.Copy( childForges, numMethodParams - 2, rewrittenForges, numMethodParams - 1, childForges.Length - (numMethodParams - 2)); childForges = rewrittenForges; } var pair = ExprNodeUtilityMake.MakeVarargArrayEval(method, childForges); childForges = pair.First; } return new ExprNodeUtilMethodDesc(allConstants, childForges, method); }
public override ExprNode Validate(ExprValidationContext validationContext) { // validate all parameters ExprNodeUtility.Validate(ExprNodeOrigin.DOTNODEPARAMETER, _chainSpec, validationContext); // determine if there are enumeration method expressions in the chain bool hasEnumerationMethod = false; foreach (ExprChainedSpec chain in _chainSpec) { if (EnumMethodEnumExtensions.IsEnumerationMethod(chain.Name)) { hasEnumerationMethod = true; break; } } // determine if there is an implied binding, replace first chain element with evaluation node if there is if (validationContext.StreamTypeService.HasTableTypes && validationContext.TableService != null && _chainSpec.Count > 1 && _chainSpec[0].IsProperty) { Pair <ExprNode, IList <ExprChainedSpec> > tableNode = validationContext.TableService.GetTableNodeChainable(validationContext.StreamTypeService, _chainSpec, validationContext.MethodResolutionService.EngineImportService); if (tableNode != null) { ExprNode node = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.DOTNODE, tableNode.First, validationContext); if (tableNode.Second.IsEmpty()) { return(node); } _chainSpec.Clear(); _chainSpec.AddAll(tableNode.Second); AddChildNode(node); } } // The root node expression may provide the input value: // Such as "window(*).doIt(...)" or "(select * from Window).doIt()" or "prevwindow(sb).doIt(...)", in which case the expression to act on is a child expression // StreamTypeService streamTypeService = validationContext.StreamTypeService; if (ChildNodes.Length != 0) { // the root expression is the first child node ExprNode rootNode = ChildNodes[0]; ExprEvaluator rootNodeEvaluator = rootNode.ExprEvaluator; // the root expression may also provide a lambda-function input (GetEnumerator<EventBean>) // Determine collection-type and evaluator if any for root node ExprDotEnumerationSource enumSrc = ExprDotNodeUtility.GetEnumerationSource(rootNode, validationContext.StreamTypeService, validationContext.EventAdapterService, validationContext.StatementId, hasEnumerationMethod, validationContext.IsDisablePropertyExpressionEventCollCache); EPType typeInfo; if (enumSrc.ReturnType == null) { typeInfo = EPTypeHelper.SingleValue(rootNodeEvaluator.ReturnType); // not a collection type, treat as scalar } else { typeInfo = enumSrc.ReturnType; } ExprDotNodeRealizedChain evals = ExprDotNodeUtility.GetChainEvaluators(enumSrc.StreamOfProviderIfApplicable, typeInfo, _chainSpec, validationContext, _isDuckTyping, new ExprDotNodeFilterAnalyzerInputExpr()); _exprEvaluator = new ExprDotEvalRootChild(hasEnumerationMethod, this, rootNodeEvaluator, enumSrc.Enumeration, typeInfo, evals.Chain, evals.ChainWithUnpack, false); return(null); } // No root node, and this is a 1-element chain i.e. "something(param,...)". // Plug-in single-row methods are not handled here. // Plug-in aggregation methods are not handled here. if (_chainSpec.Count == 1) { ExprChainedSpec spec = _chainSpec[0]; if (spec.Parameters.IsEmpty()) { throw HandleNotFound(spec.Name); } // single-parameter can resolve to a property Pair <PropertyResolutionDescriptor, string> propertyInfoPair = null; try { propertyInfoPair = ExprIdentNodeUtil.GetTypeFromStream(streamTypeService, spec.Name, streamTypeService.HasPropertyAgnosticType, false); } catch (ExprValidationPropertyException) { // fine } // if not a property then try built-in single-row non-grammar functions if (propertyInfoPair == null && string.Equals(spec.Name, EngineImportServiceConstants.EXT_SINGLEROW_FUNCTION_TRANSPOSE, StringComparison.OrdinalIgnoreCase)) { if (spec.Parameters.Count != 1) { throw new ExprValidationException("The " + EngineImportServiceConstants.EXT_SINGLEROW_FUNCTION_TRANSPOSE + " function requires a single parameter expression"); } _exprEvaluator = new ExprDotEvalTransposeAsStream(_chainSpec[0].Parameters[0].ExprEvaluator); } else if (spec.Parameters.Count != 1) { throw HandleNotFound(spec.Name); } else { if (propertyInfoPair == null) { throw new ExprValidationException("Unknown single-row function, aggregation function or mapped or indexed property named '" + spec.Name + "' could not be resolved"); } _exprEvaluator = GetPropertyPairEvaluator(spec.Parameters[0].ExprEvaluator, propertyInfoPair, validationContext); _streamNumReferenced = propertyInfoPair.First.StreamNum; } return(null); } // handle the case where the first chain spec element is a stream name. ExprValidationException prefixedStreamNumException = null; int prefixedStreamNumber = PrefixedStreamName(_chainSpec, validationContext.StreamTypeService); if (prefixedStreamNumber != -1) { ExprChainedSpec specAfterStreamName = _chainSpec[1]; // Attempt to resolve as property Pair <PropertyResolutionDescriptor, string> propertyInfoPair = null; try { string propName = _chainSpec[0].Name + "." + specAfterStreamName.Name; propertyInfoPair = ExprIdentNodeUtil.GetTypeFromStream(streamTypeService, propName, streamTypeService.HasPropertyAgnosticType, false); } catch (ExprValidationPropertyException) { // fine } if (propertyInfoPair != null) { if (specAfterStreamName.Parameters.Count != 1) { throw HandleNotFound(specAfterStreamName.Name); } _exprEvaluator = GetPropertyPairEvaluator(specAfterStreamName.Parameters[0].ExprEvaluator, propertyInfoPair, validationContext); _streamNumReferenced = propertyInfoPair.First.StreamNum; return(null); } // Attempt to resolve as event-underlying object instance method EventType eventType = validationContext.StreamTypeService.EventTypes[prefixedStreamNumber]; Type type = eventType.UnderlyingType; IList <ExprChainedSpec> remainderChain = new List <ExprChainedSpec>(_chainSpec); remainderChain.RemoveAt(0); ExprValidationException methodEx = null; ExprDotEval[] underlyingMethodChain = null; try { EPType typeInfo = EPTypeHelper.SingleValue(type); underlyingMethodChain = ExprDotNodeUtility.GetChainEvaluators(prefixedStreamNumber, typeInfo, remainderChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStream(prefixedStreamNumber)).ChainWithUnpack; } catch (ExprValidationException ex) { methodEx = ex; // expected - may not be able to find the methods on the underlying } ExprDotEval[] eventTypeMethodChain = null; ExprValidationException enumDatetimeEx = null; try { EPType typeInfo = EPTypeHelper.SingleEvent(eventType); ExprDotNodeRealizedChain chain = ExprDotNodeUtility.GetChainEvaluators(prefixedStreamNumber, typeInfo, remainderChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStream(prefixedStreamNumber)); eventTypeMethodChain = chain.ChainWithUnpack; _exprDotNodeFilterAnalyzerDesc = chain.FilterAnalyzerDesc; } catch (ExprValidationException ex) { enumDatetimeEx = ex; // expected - may not be able to find the methods on the underlying } if (underlyingMethodChain != null) { _exprEvaluator = new ExprDotEvalStreamMethod(this, prefixedStreamNumber, underlyingMethodChain); _streamNumReferenced = prefixedStreamNumber; } else if (eventTypeMethodChain != null) { _exprEvaluator = new ExprDotEvalStreamEventBean(this, prefixedStreamNumber, eventTypeMethodChain); _streamNumReferenced = prefixedStreamNumber; } if (_exprEvaluator != null) { return(null); } else { if (ExprDotNodeUtility.IsDatetimeOrEnumMethod(remainderChain[0].Name)) { prefixedStreamNumException = enumDatetimeEx; } else { prefixedStreamNumException = new ExprValidationException("Failed to solve '" + remainderChain[0].Name + "' to either a date-time or enumeration method, an event property or a method on the event underlying object: " + methodEx.Message, methodEx); } } } // There no root node, in this case the classname or property name is provided as part of the chain. // Such as "MyClass.myStaticLib(...)" or "mycollectionproperty.doIt(...)" // IList <ExprChainedSpec> modifiedChain = new List <ExprChainedSpec>(_chainSpec); ExprChainedSpec firstItem = modifiedChain.Pluck(0); Pair <PropertyResolutionDescriptor, string> propertyInfoPairX = null; try { propertyInfoPairX = ExprIdentNodeUtil.GetTypeFromStream(streamTypeService, firstItem.Name, streamTypeService.HasPropertyAgnosticType, true); } catch (ExprValidationPropertyException) { // not a property } // If property then treat it as such if (propertyInfoPairX != null) { string propertyName = propertyInfoPairX.First.PropertyName; int streamId = propertyInfoPairX.First.StreamNum; EventType streamType = streamTypeService.EventTypes[streamId]; EPType typeInfo; ExprEvaluatorEnumeration enumerationEval = null; EPType inputType; ExprEvaluator rootNodeEvaluator = null; EventPropertyGetter getter; if (firstItem.Parameters.IsEmpty()) { getter = streamType.GetGetter(propertyInfoPairX.First.PropertyName); ExprDotEnumerationSourceForProps propertyEval = ExprDotNodeUtility.GetPropertyEnumerationSource( propertyInfoPairX.First.PropertyName, streamId, streamType, hasEnumerationMethod, validationContext.IsDisablePropertyExpressionEventCollCache); typeInfo = propertyEval.ReturnType; enumerationEval = propertyEval.Enumeration; inputType = propertyEval.ReturnType; rootNodeEvaluator = new PropertyExprEvaluatorNonLambda(streamId, getter, propertyInfoPairX.First.PropertyType); } else { // property with parameter - mapped or indexed property EventPropertyDescriptor desc = EventTypeUtility.GetNestablePropertyDescriptor(streamTypeService.EventTypes[propertyInfoPairX.First.StreamNum], firstItem.Name); if (firstItem.Parameters.Count > 1) { throw new ExprValidationException("Property '" + firstItem.Name + "' may not be accessed passing 2 or more parameters"); } ExprEvaluator paramEval = firstItem.Parameters[0].ExprEvaluator; typeInfo = EPTypeHelper.SingleValue(desc.PropertyComponentType); inputType = typeInfo; getter = null; if (desc.IsMapped) { if (paramEval.ReturnType != typeof(string)) { throw new ExprValidationException("Parameter expression to mapped property '" + propertyName + "' is expected to return a string-type value but returns " + paramEval.ReturnType.GetTypeNameFullyQualPretty()); } EventPropertyGetterMapped mappedGetter = propertyInfoPairX.First.StreamEventType.GetGetterMapped(propertyInfoPairX.First.PropertyName); if (mappedGetter == null) { throw new ExprValidationException("Mapped property named '" + propertyName + "' failed to obtain getter-object"); } rootNodeEvaluator = new PropertyExprEvaluatorNonLambdaMapped(streamId, mappedGetter, paramEval, desc.PropertyComponentType); } if (desc.IsIndexed) { if (paramEval.ReturnType.GetBoxedType() != typeof(int?)) { throw new ExprValidationException("Parameter expression to mapped property '" + propertyName + "' is expected to return a Integer-type value but returns " + paramEval.ReturnType.GetTypeNameFullyQualPretty()); } EventPropertyGetterIndexed indexedGetter = propertyInfoPairX.First.StreamEventType.GetGetterIndexed(propertyInfoPairX.First.PropertyName); if (indexedGetter == null) { throw new ExprValidationException("Mapped property named '" + propertyName + "' failed to obtain getter-object"); } rootNodeEvaluator = new PropertyExprEvaluatorNonLambdaIndexed(streamId, indexedGetter, paramEval, desc.PropertyComponentType); } } if (typeInfo == null) { throw new ExprValidationException("Property '" + propertyName + "' is not a mapped or indexed property"); } // try to build chain based on the input (non-fragment) ExprDotNodeRealizedChain evals; ExprDotNodeFilterAnalyzerInputProp filterAnalyzerInputProp = new ExprDotNodeFilterAnalyzerInputProp(propertyInfoPairX.First.StreamNum, propertyInfoPairX.First.PropertyName); bool rootIsEventBean = false; try { evals = ExprDotNodeUtility.GetChainEvaluators(streamId, inputType, modifiedChain, validationContext, _isDuckTyping, filterAnalyzerInputProp); } catch (ExprValidationException ex) { // try building the chain based on the fragment event type (i.e. A.after(B) based on A-configured start time where A is a fragment) FragmentEventType fragment = propertyInfoPairX.First.FragmentEventType; if (fragment == null) { throw; } EPType fragmentTypeInfo; if (fragment.IsIndexed) { fragmentTypeInfo = EPTypeHelper.CollectionOfEvents(fragment.FragmentType); } else { fragmentTypeInfo = EPTypeHelper.SingleEvent(fragment.FragmentType); } rootIsEventBean = true; evals = ExprDotNodeUtility.GetChainEvaluators(propertyInfoPairX.First.StreamNum, fragmentTypeInfo, modifiedChain, validationContext, _isDuckTyping, filterAnalyzerInputProp); rootNodeEvaluator = new PropertyExprEvaluatorNonLambdaFragment(streamId, getter, fragment.FragmentType.UnderlyingType); } _exprEvaluator = new ExprDotEvalRootChild(hasEnumerationMethod, this, rootNodeEvaluator, enumerationEval, inputType, evals.Chain, evals.ChainWithUnpack, !rootIsEventBean); _exprDotNodeFilterAnalyzerDesc = evals.FilterAnalyzerDesc; _streamNumReferenced = propertyInfoPairX.First.StreamNum; _rootPropertyName = propertyInfoPairX.First.PropertyName; return(null); } // If variable then resolve as such string contextNameVariable = validationContext.VariableService.IsContextVariable(firstItem.Name); if (contextNameVariable != null) { throw new ExprValidationException("Method invocation on context-specific variable is not supported"); } VariableReader variableReader = validationContext.VariableService.GetReader(firstItem.Name, EPStatementStartMethodConst.DEFAULT_AGENT_INSTANCE_ID); if (variableReader != null) { EPType typeInfo; ExprDotStaticMethodWrap wrap; if (variableReader.VariableMetaData.VariableType.IsArray) { typeInfo = EPTypeHelper.CollectionOfSingleValue(variableReader.VariableMetaData.VariableType.GetElementType()); wrap = new ExprDotStaticMethodWrapArrayScalar(variableReader.VariableMetaData.VariableName, variableReader.VariableMetaData.VariableType.GetElementType()); } else if (variableReader.VariableMetaData.EventType != null) { typeInfo = EPTypeHelper.SingleEvent(variableReader.VariableMetaData.EventType); wrap = null; } else { typeInfo = EPTypeHelper.SingleValue(variableReader.VariableMetaData.VariableType); wrap = null; } ExprDotNodeRealizedChain evals = ExprDotNodeUtility.GetChainEvaluators(null, typeInfo, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); _exprEvaluator = new ExprDotEvalVariable(this, variableReader, wrap, evals.ChainWithUnpack); return(null); } // try resolve as enumeration class with value object enumconstant = TypeHelper.ResolveIdentAsEnumConst(firstItem.Name, validationContext.MethodResolutionService, null, false); if (enumconstant != null) { // try resolve method ExprChainedSpec methodSpec = modifiedChain[0]; string enumvalue = firstItem.Name; ExprNodeUtilResolveExceptionHandler handler = new ProxyExprNodeUtilResolveExceptionHandler { ProcHandle = ex => new ExprValidationException("Failed to resolve method '" + methodSpec.Name + "' on enumeration value '" + enumvalue + "': " + ex.Message), }; EventType wildcardType = validationContext.StreamTypeService.EventTypes.Length != 1 ? null : validationContext.StreamTypeService.EventTypes[0]; ExprNodeUtilMethodDesc methodDesc = ExprNodeUtility.ResolveMethodAllowWildcardAndStream(enumconstant.GetType().Name, enumconstant.GetType(), methodSpec.Name, methodSpec.Parameters, validationContext.MethodResolutionService, validationContext.EventAdapterService, validationContext.StatementId, wildcardType != null, wildcardType, handler, methodSpec.Name, validationContext.TableService); // method resolved, hook up modifiedChain.RemoveAt(0); // we identified this piece ExprDotStaticMethodWrap optionalLambdaWrap = ExprDotStaticMethodWrapFactory.Make(methodDesc.ReflectionMethod, validationContext.EventAdapterService, modifiedChain); EPType typeInfo = optionalLambdaWrap != null ? optionalLambdaWrap.TypeInfo : EPTypeHelper.SingleValue(methodDesc.FastMethod.ReturnType); ExprDotNodeRealizedChain evals = ExprDotNodeUtility.GetChainEvaluators(null, typeInfo, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); _exprEvaluator = new ExprDotEvalStaticMethod(validationContext.StatementName, firstItem.Name, methodDesc.FastMethod, methodDesc.ChildEvals, false, optionalLambdaWrap, evals.ChainWithUnpack, false, enumconstant); return(null); } // if prefixed by a stream name, we are giving up if (prefixedStreamNumException != null) { throw prefixedStreamNumException; } // If class then resolve as class ExprChainedSpec secondItem = modifiedChain.Pluck(0); bool allowWildcard = validationContext.StreamTypeService.EventTypes.Length == 1; EventType streamZeroType = null; if (validationContext.StreamTypeService.EventTypes.Length > 0) { streamZeroType = validationContext.StreamTypeService.EventTypes[0]; } ExprNodeUtilMethodDesc method = ExprNodeUtility.ResolveMethodAllowWildcardAndStream(firstItem.Name, null, secondItem.Name, secondItem.Parameters, validationContext.MethodResolutionService, validationContext.EventAdapterService, validationContext.StatementId, allowWildcard, streamZeroType, new ExprNodeUtilResolveExceptionHandlerDefault(firstItem.Name + "." + secondItem.Name, false), secondItem.Name, validationContext.TableService); bool isConstantParameters = method.IsAllConstants && _isUDFCache; _isReturnsConstantResult = isConstantParameters && modifiedChain.IsEmpty(); // this may return a pair of null if there is no lambda or the result cannot be wrapped for lambda-function use ExprDotStaticMethodWrap optionalLambdaWrapX = ExprDotStaticMethodWrapFactory.Make(method.ReflectionMethod, validationContext.EventAdapterService, modifiedChain); EPType typeInfoX = optionalLambdaWrapX != null ? optionalLambdaWrapX.TypeInfo : EPTypeHelper.SingleValue(method.ReflectionMethod.ReturnType); ExprDotNodeRealizedChain evalsX = ExprDotNodeUtility.GetChainEvaluators(null, typeInfoX, modifiedChain, validationContext, false, new ExprDotNodeFilterAnalyzerInputStatic()); _exprEvaluator = new ExprDotEvalStaticMethod(validationContext.StatementName, firstItem.Name, method.FastMethod, method.ChildEvals, isConstantParameters, optionalLambdaWrapX, evalsX.ChainWithUnpack, false, null); return(null); }
public static bool IsDatetimeOrEnumMethod(string name) { return EnumMethodEnumExtensions.IsEnumerationMethod(name) || DatetimeMethodEnumHelper.IsDateTimeMethod(name); }
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); }