Beispiel #1
0
 public static bool IsDatetimeOrEnumMethod(
     string name,
     ImportServiceCompileTime importService)
 {
     return(EnumMethodResolver.IsEnumerationMethod(name, importService) ||
            DatetimeMethodResolver.IsDateTimeMethod(name, importService));
 }
Beispiel #2
0
        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 (!EnumMethodResolver.IsEnumerationMethod(methodName, services.ImportServiceCompileTime) && childNode is ExprLambdaGoesNode) {
                    throw new ExprValidationException(
                        "Unrecognized 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,
                        services.ClassProvidedExtension);
                }
            }
            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;
                }

                childForges = ExprNodeUtilityMake.MakeVarargArrayForges(method, childForges);
            }

            var localInlinedClass = services.ClassProvidedExtension.IsLocalInlinedClass(method.DeclaringType);
            return new ExprNodeUtilMethodDesc(allConstants, childForges, method, localInlinedClass);
        }
Beispiel #3
0
        public static ExprDotNodeRealizedChain GetChainEvaluators(
            int?streamOfProviderIfApplicable,
            EPType inputType,
            IList <Chainable> chainSpec,
            ExprValidationContext validationContext,
            bool isDuckTyping,
            ExprDotNodeFilterAnalyzerInput inputDesc)
        {
            var                        methodForges       = new List <ExprDotForge>();
            var                        currentInputType   = inputType;
            EnumMethodDesc             lastLambdaFunc     = null;
            var                        lastElement        = chainSpec.IsEmpty() ? null : chainSpec[chainSpec.Count - 1];
            FilterExprAnalyzerAffector filterAnalyzerDesc = null;

            Deque <Chainable> chainSpecStack = new ArrayDeque <Chainable>(chainSpec);

            while (!chainSpecStack.IsEmpty())
            {
                var chainElement     = chainSpecStack.RemoveFirst();
                var parameters       = chainElement.GetParametersOrEmpty();
                var chainElementName = chainElement.GetRootNameOrEmptyString();
                var last             = chainSpecStack.IsEmpty();
                lastLambdaFunc = null;                 // reset

                // compile parameters for chain element
                var paramForges = new ExprForge[parameters.Count];
                var paramTypes  = new Type[parameters.Count];
                for (var i = 0; i < parameters.Count; i++)
                {
                    paramForges[i] = parameters[i].Forge;
                    paramTypes[i]  = paramForges[i].EvaluationType;
                }

                // check if special 'size' method
                if (currentInputType is ClassMultiValuedEPType)
                {
                    var type = (ClassMultiValuedEPType)currentInputType;
                    if (string.Equals(chainElementName, "size", StringComparison.InvariantCultureIgnoreCase) &&
                        paramTypes.Length == 0 &&
                        lastElement == chainElement)
                    {
                        ExprDotForge size;
                        var          containerType = ((ClassMultiValuedEPType)currentInputType).Container;
                        if (containerType.IsArray)
                        {
                            size = new ExprDotForgeSizeArray();
                        }
                        else
                        {
                            size = new ExprDotForgeSizeCollection();
                        }

                        methodForges.Add(size);
                        currentInputType = size.TypeInfo;
                        continue;
                    }

                    if (string.Equals(chainElementName, "get", StringComparison.InvariantCultureIgnoreCase) &&
                        paramTypes.Length == 1 &&
                        paramTypes[0].GetBoxedType() == typeof(int?))
                    {
                        ExprDotForge get;
                        var          componentType = type.Component.GetBoxedType();
                        if (type.Container.IsArray)
                        {
                            get = new ExprDotForgeGetArray(paramForges[0], componentType);
                        }
                        else
                        {
                            get = new ExprDotForgeGetCollection(paramForges[0], componentType);
                        }

                        methodForges.Add(get);
                        currentInputType = get.TypeInfo;
                        continue;
                    }

                    if (chainElement is ChainableArray && type.Container.IsArray)
                    {
                        var array     = (ChainableArray)chainElement;
                        var typeInfo  = currentInputType;
                        var indexExpr = ChainableArray.ValidateSingleIndexExpr(
                            array.Indexes,
                            () => "operation on type " + typeInfo.ToTypeDescriptive());
                        var componentType = type.Component.GetBoxedType();
                        var get           = new ExprDotForgeGetArray(indexExpr.Forge, componentType);
                        methodForges.Add(get);
                        currentInputType = get.TypeInfo;
                        continue;
                    }
                }

                // determine if there is a matching method or property
                var methodTarget   = GetMethodTarget(currentInputType);
                var matchingMethod = false;
                if (methodTarget != null && (!(chainElement is ChainableArray)))
                {
                    try {
                        GetValidateMethodDescriptor(methodTarget, chainElementName, parameters, validationContext);
                        matchingMethod = true;
                    }
                    catch (ExprValidationException) {
                        // expected
                    }
                }

                if (EnumMethodResolver.IsEnumerationMethod(chainElementName, validationContext.ImportService) &&
                    (!matchingMethod || methodTarget.IsArray || methodTarget.IsGenericCollection()))
                {
                    var enumerationMethod = EnumMethodResolver.FromName(chainElementName, validationContext.ImportService);
                    if (enumerationMethod == null)
                    {
                        throw new EPException("unable to determine enumeration method from name");
                    }

                    var eval = enumerationMethod.Factory.Invoke(chainElement.GetParametersOrEmpty().Count);
                    if (currentInputType is ClassEPType classEpType && classEpType.Clazz.IsGenericCollection() && !classEpType.Clazz.IsArray)
                    {
                        currentInputType = EPTypeHelper.CollectionOfSingleValue(typeof(object), null);
                    }

                    eval.Init(streamOfProviderIfApplicable, enumerationMethod, chainElementName, currentInputType, parameters, validationContext);
                    currentInputType = eval.TypeInfo;
                    if (currentInputType == null)
                    {
                        throw new IllegalStateException("Enumeration method '" + chainElementName + "' has not returned type information");
                    }

                    methodForges.Add(eval);
                    lastLambdaFunc = enumerationMethod;
                    continue;
                }

                // resolve datetime
                if (DatetimeMethodResolver.IsDateTimeMethod(chainElementName, validationContext.ImportService) &&
                    (!matchingMethod ||
                     methodTarget == typeof(DateTimeEx) ||
                     methodTarget == typeof(DateTimeOffset) ||
                     methodTarget == typeof(DateTime)))
                {
                    var datetimeMethod = DatetimeMethodResolver.FromName(chainElementName, validationContext.ImportService);
                    var datetimeImpl   = ExprDotDTFactory.ValidateMake(
                        validationContext.StreamTypeService,
                        chainSpecStack,
                        datetimeMethod,
                        chainElementName,
                        currentInputType,
                        parameters,
                        inputDesc,
                        validationContext.ImportService.TimeAbacus,
                        validationContext.TableCompileTimeResolver,
                        validationContext.ImportService,
                        validationContext.StatementRawInfo);
                    currentInputType = datetimeImpl.ReturnType;
                    if (currentInputType == null)
                    {
                        throw new IllegalStateException(
                                  "Date-time method '" + chainElementName + "' 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)
                {
                    if (chainElement is ChainableArray)
                    {
                        throw new ExprValidationException("Could not perform array operation on type " + currentInputType.ToTypeDescriptive());
                    }

                    var          inputEventType = (EventTypeSPI)((EventEPType)currentInputType).EventType;
                    var          type           = inputEventType.GetPropertyType(chainElementName);
                    var          getter         = inputEventType.GetGetterSPI(chainElementName);
                    var          fragmentType   = inputEventType.GetFragmentType(chainElementName);
                    ExprDotForge forge;
                    if (type != null && getter != null)
                    {
                        if (fragmentType == null || last)
                        {
                            forge            = new ExprDotForgeProperty(getter, EPTypeHelper.SingleValue(type.GetBoxedType()));
                            currentInputType = forge.TypeInfo;
                        }
                        else
                        {
                            if (!fragmentType.IsIndexed)
                            {
                                currentInputType = EPTypeHelper.SingleEvent(fragmentType.FragmentType);
                            }
                            else
                            {
                                currentInputType = EPTypeHelper.ArrayOfEvents(fragmentType.FragmentType);
                            }

                            forge = new ExprDotForgePropertyFragment(getter, currentInputType);
                        }

                        methodForges.Add(forge);
                        continue;
                    }
                }

                if (currentInputType is EventMultiValuedEPType eventMultiValuedEpType && chainElement is ChainableArray chainableArray)
                {
                    var inputEventType = (EventTypeSPI)eventMultiValuedEpType.Component;
                    var typeInfo       = currentInputType;
                    var indexExpr      = ChainableArray.ValidateSingleIndexExpr(
                        chainableArray.Indexes,
                        () => "operation on type " + typeInfo.ToTypeDescriptive());
                    currentInputType = EPTypeHelper.SingleEvent(inputEventType);
                    var forge = new ExprDotForgeEventArrayAtIndex(currentInputType, indexExpr);
                    methodForges.Add(forge);
                    continue;
                }

                // Finally try to resolve the method
                if (methodTarget != null && !(chainElement is ChainableArray))
                {
                    try {
                        // find descriptor again, allow for duck typing
                        var desc = GetValidateMethodDescriptor(methodTarget, chainElementName, 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() &&
                                EnumMethodResolver.IsEnumerationMethod(chainSpecStack.First.GetRootNameOrEmptyString(), validationContext.ImportService))
                            {
                                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,
                            chainElementName,
                            paramTypes,
                            paramForges);
                        methodForges.Add(duck);
                        currentInputType = duck.TypeInfo;
                    }

                    continue;
                }

                string message;
                if (!(chainElement is ChainableArray))
                {
                    message = "Could not find event property or method named '" + chainElementName + "' in " + currentInputType.ToTypeDescriptive();
                }
                else
                {
                    message = "Could not perform array operation on type " + currentInputType.ToTypeDescriptive();
                }

                throw new ExprValidationException(message);
            }

            var intermediateEvals = methodForges.ToArray();

            if (lastLambdaFunc != null)
            {
                ExprDotForge finalEval = null;
                if (currentInputType is EventMultiValuedEPType mvType)
                {
                    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 epType)
                {
                    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));
        }