Example #1
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            if (Script.ParameterNames.Length != Parameters.Count) {
                throw new ExprValidationException(
                    string.Format(
                        "Invalid number of parameters for script '{0}', expected {1} parameters but received {2} parameters",
                        Script.Name,
                        Script.ParameterNames.Length,
                        Parameters.Count));
            }

            if (!validationContext.StatementCompileTimeService.Configuration.Compiler.Scripts.IsEnabled) {
                throw new ExprValidationException("Script compilation has been disabled by configuration");
            }

            // validate all expression parameters
            var validatedParameters = Parameters
                .Select(
                    expr => ExprNodeUtilityValidate.GetValidatedSubtree(
                        ExprNodeOrigin.SCRIPTPARAMS,
                        expr,
                        validationContext))
                .ToList();

            // set up map of input parameter names and evaluators
            var forges = new ExprForge[Script.ParameterNames.Length];
            for (var i = 0; i < Script.ParameterNames.Length; i++) {
                forges[i] = validatedParameters[i].Forge;
            }

            Parameters = validatedParameters;

            // Compile script
            var parameterTypes = ExprNodeUtilityQuery.GetExprResultTypes(forges);
            var dialect = Script.OptionalDialect ?? _defaultDialect;
            var compiled = CompileScript(
                dialect,
                Script.Name,
                Script.Expression,
                Script.ParameterNames,
                parameterTypes,
                Script.CompiledBuf,
                validationContext.ImportService,
                validationContext.ScriptCompiler);

            // Determine declared return type
            var declaredReturnType = GetDeclaredReturnType(Script.OptionalReturnTypeName, validationContext);
            if (Script.IsOptionalReturnTypeIsArray && declaredReturnType != null) {
                declaredReturnType = TypeHelper.GetArrayType(declaredReturnType);
            }

            Type returnType;
            if (compiled.KnownReturnType == null && Script.OptionalReturnTypeName == null) {
                returnType = typeof(object);
            }
            else if (compiled.KnownReturnType != null) {
                if (declaredReturnType == null) {
                    returnType = compiled.KnownReturnType;
                }
                else {
                    var knownReturnType = compiled.KnownReturnType;
                    if (declaredReturnType.IsArray && knownReturnType.IsArray) {
                        // we are fine
                    }
                    else if (!knownReturnType.IsAssignmentCompatible(declaredReturnType)) {
                        throw new ExprValidationException(
                            "Return type and declared type not compatible for script '" +
                            Script.Name +
                            "', known return type is " +
                            knownReturnType.Name +
                            " versus declared return type " +
                            declaredReturnType.Name);
                    }

                    returnType = declaredReturnType;
                }
            }
            else {
                returnType = declaredReturnType;
            }

            if (returnType == null) {
                returnType = typeof(object);
            }

            _eventTypeCollection = null;
            if (Script.OptionalEventTypeName != null) {
                if (returnType.IsArray && returnType.GetElementType() == typeof(EventBean)) {
                    _eventTypeCollection = EventTypeUtility.RequireEventType(
                        "Script",
                        Script.Name,
                        Script.OptionalEventTypeName,
                        validationContext.StatementCompileTimeService.EventTypeCompileTimeResolver);
                }
                else {
                    throw new ExprValidationException(EventTypeUtility.DisallowedAtTypeMessage());
                }
            }

            _scriptDescriptor = new ScriptDescriptorCompileTime(
                Script.OptionalDialect,
                Script.Name,
                Script.Expression,
                Script.ParameterNames,
                Parameters.ToArray(),
                returnType,
                _defaultDialect);
            return null;
        }
Example #2
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            if (_evaluator != null)
            {
                return(null);
            }

            if (Script.ParameterNames.Count != Parameters.Count)
            {
                throw new ExprValidationException(
                          string.Format(
                              "Invalid number of parameters for script '{0}', expected {1} parameters but received {2} parameters",
                              Script.Name,
                              Script.ParameterNames.Count,
                              Parameters.Count));
            }

            // validate all expression parameters
            var validatedParameters = Parameters
                                      .Select(
                expr => ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.SCRIPTPARAMS, expr, validationContext))
                                      .ToList();

            // set up map of input parameter names and evaluators
            var inputParamNames = new string[Script.ParameterNames.Count];
            var evaluators      = new ExprEvaluator[Script.ParameterNames.Count];

            for (int i = 0; i < Script.ParameterNames.Count; i++)
            {
                inputParamNames[i] = Script.ParameterNames[i];
                evaluators[i]      = validatedParameters[i].ExprEvaluator;
            }

            // Compile script
            if (Script.Compiled == null)
            {
                CompileScript(validationContext.ScriptingService, evaluators, validationContext.EngineImportService);
            }

            // Determine declared return type
            Type declaredReturnType = GetDeclaredReturnType(Script.OptionalReturnTypeName, validationContext);

            if (Script.IsOptionalReturnTypeIsArray && declaredReturnType != null)
            {
                declaredReturnType = TypeHelper.GetArrayType(declaredReturnType);
            }
            Type returnType;

            if (Script.Compiled.KnownReturnType == null && Script.OptionalReturnTypeName == null)
            {
                returnType = typeof(Object);
            }
            else if (Script.Compiled.KnownReturnType != null)
            {
                if (declaredReturnType == null)
                {
                    returnType = Script.Compiled.KnownReturnType;
                }
                else
                {
                    Type knownReturnType = Script.Compiled.KnownReturnType;
                    if (declaredReturnType.IsArray && knownReturnType.IsArray)
                    {
                        // we are fine
                    }
                    else if (!knownReturnType.IsAssignmentCompatible(declaredReturnType))
                    {
                        throw new ExprValidationException(
                                  "Return type and declared type not compatible for script '" + Script.Name +
                                  "', known return type is " + knownReturnType.Name + " versus declared return type " +
                                  declaredReturnType.Name);
                    }
                    returnType = declaredReturnType;
                }
            }
            else
            {
                returnType = declaredReturnType;
            }
            if (returnType == null)
            {
                returnType = typeof(Object);
            }

            EventType eventTypeCollection = null;

            if (Script.OptionalEventTypeName != null)
            {
                if (returnType.IsArray && returnType.GetElementType() == typeof(EventBean))
                {
                    eventTypeCollection = EventTypeUtility.RequireEventType(
                        "Script", Script.Name, validationContext.EventAdapterService, Script.OptionalEventTypeName);
                }
                else
                {
                    throw new ExprValidationException(EventTypeUtility.DisallowedAtTypeMessage());
                }
            }

            // Prepare evaluator - this sets the evaluator
            PrepareEvaluator(
                validationContext.StatementName, inputParamNames, evaluators, returnType, eventTypeCollection);
            return(null);
        }
Example #3
0
        public static HistoricalEventViewableMethodForge CreateMethodStatementView(
            int stream,
            MethodStreamSpec methodStreamSpec,
            StatementBaseInfo @base,
            StatementCompileTimeServices services)
        {
            var variableMetaData = services.VariableCompileTimeResolver.Resolve(methodStreamSpec.ClassName);
            MethodPollingExecStrategyEnum strategy;
            MethodInfo methodReflection = null;
            string eventTypeNameProvidedUDFOrScript = null;
            var contextName = @base.StatementSpec.Raw.OptionalContextName;
            var classpathImportService = services.ImportServiceCompileTime;

            // see if this is a script in the from-clause
            ExprNodeScript scriptExpression = null;
            if (methodStreamSpec.ClassName == null && methodStreamSpec.MethodName != null) {
                var script = services.ScriptCompileTimeResolver.Resolve(
                    methodStreamSpec.MethodName,
                    methodStreamSpec.Expressions.Count);
                if (script != null) {
                    scriptExpression = new ExprNodeScript(
                        services.Configuration.Compiler.Scripts.DefaultDialect,
                        script,
                        methodStreamSpec.Expressions);
                }
            }

            try {
                if (scriptExpression != null) {
                    eventTypeNameProvidedUDFOrScript = scriptExpression.EventTypeNameAnnotation;
                    strategy = MethodPollingExecStrategyEnum.TARGET_SCRIPT;
                    EPLValidationUtil.ValidateSimpleGetSubtree(
                        ExprNodeOrigin.METHODINVJOIN,
                        scriptExpression,
                        null,
                        false,
                        @base.StatementRawInfo,
                        services);
                }
                else if (variableMetaData != null) {
                    var variableName = variableMetaData.VariableName;
                    if (variableMetaData.OptionalContextName != null) {
                        if (contextName == null || !contextName.Equals(variableMetaData.OptionalContextName)) {
                            throw new ExprValidationException(
                                "Variable by name '" +
                                variableMetaData.VariableName +
                                "' has been declared for context '" +
                                variableMetaData.OptionalContextName +
                                "' and can only be used within the same context");
                        }

                        strategy = MethodPollingExecStrategyEnum.TARGET_VAR_CONTEXT;
                    }
                    else {
                        if (variableMetaData.IsConstant) {
                            strategy = MethodPollingExecStrategyEnum.TARGET_CONST;
                        }
                        else {
                            strategy = MethodPollingExecStrategyEnum.TARGET_VAR;
                        }
                    }

                    methodReflection = classpathImportService.ResolveNonStaticMethodOverloadChecked(
                        variableMetaData.Type,
                        methodStreamSpec.MethodName);
                }
                else if (methodStreamSpec.ClassName == null) { // must be either UDF or script
                    Pair<Type, ImportSingleRowDesc> udf;
                    try {
                        udf = classpathImportService.ResolveSingleRow(
                            methodStreamSpec.MethodName,
                            services.ClassProvidedExtension);
                    }
                    catch (ImportException ex) {
                        throw new ExprValidationException(
                            "Failed to find user-defined function '" + methodStreamSpec.MethodName + "': " + ex.Message,
                            ex);
                    }

                    methodReflection = classpathImportService.ResolveMethodOverloadChecked(
                        udf.First,
                        methodStreamSpec.MethodName);
                    eventTypeNameProvidedUDFOrScript = udf.Second.OptionalEventTypeName;
                    strategy = MethodPollingExecStrategyEnum.TARGET_CONST;
                }
                else {
                    methodReflection = classpathImportService.ResolveMethodOverloadChecked(
                        methodStreamSpec.ClassName,
                        methodStreamSpec.MethodName,
                        services.ClassProvidedExtension);
                    strategy = MethodPollingExecStrategyEnum.TARGET_CONST;
                }
            }
            catch (ExprValidationException) {
                throw;
            }
            catch (Exception e) {
                throw new ExprValidationException(e.Message, e);
            }

            Type methodProviderClass = null;
            Type beanClass;
            IDictionary<string, object> oaType = null;
            IDictionary<string, object> mapType = null;
            var isCollection = false;
            var isEnumerator = false;
            EventType eventType;
            EventType eventTypeWhenMethodReturnsEventBeans = null;
            var isStaticMethod = false;

            if (methodReflection != null) {
                methodProviderClass = methodReflection.DeclaringType;
                isStaticMethod = variableMetaData == null;

                // Determine object type returned by method
                beanClass = methodReflection.ReturnType;
                if (beanClass == typeof(void) || beanClass == typeof(void) || beanClass.IsBuiltinDataType()) {
                    throw new ExprValidationException(
                        "Invalid return type for static method '" +
                        methodReflection.Name +
                        "' of class '" +
                        methodStreamSpec.ClassName +
                        "', expecting a type");
                }

                if (methodReflection.ReturnType.IsArray &&
                    methodReflection.ReturnType.GetElementType() != typeof(EventBean)) {
                    beanClass = methodReflection.ReturnType.GetElementType();
                }

                isCollection = beanClass.IsGenericCollection() && !beanClass.IsGenericDictionary();
                Type collectionClass = null;
                if (isCollection) {
                    collectionClass = TypeHelper.GetGenericReturnType(methodReflection, true);
                    beanClass = collectionClass;
                }

                isEnumerator = beanClass.IsGenericEnumerator();
                Type enumerator = null;
                if (isEnumerator) {
                    enumerator = TypeHelper.GetGenericReturnType(methodReflection, true);
                    beanClass = enumerator;
                }

                // If the method returns a Map, look up the map type
                string mapTypeName = null;
                if (methodReflection.ReturnType.IsGenericDictionary() ||
                    methodReflection.ReturnType.IsArray &&
                    methodReflection.ReturnType.GetElementType().IsGenericDictionary() ||
                    isCollection && collectionClass.IsGenericDictionary() ||
                    isEnumerator && enumerator.IsGenericDictionary()) {
                    MethodMetadataDesc metadata;
                    if (variableMetaData != null) {
                        metadata = GetCheckMetadataVariable(
                            methodStreamSpec.MethodName,
                            variableMetaData,
                            classpathImportService,
                            typeof(IDictionary<string, object>));
                    }
                    else {
                        metadata = GetCheckMetadataNonVariable(
                            methodStreamSpec.MethodName,
                            methodStreamSpec.ClassName,
                            classpathImportService,
                            typeof(IDictionary<string, object>));
                    }

                    mapTypeName = metadata.TypeName;
                    mapType = (IDictionary<string, object>) metadata.TypeMetadata;
                }

                // If the method returns an Object[] or Object[][], look up the type information
                string oaTypeName = null;
                if (methodReflection.ReturnType == typeof(object[]) ||
                    methodReflection.ReturnType == typeof(object[][]) ||
                    isCollection && collectionClass == typeof(object[]) ||
                    isEnumerator && enumerator == typeof(object[])) {
                    MethodMetadataDesc metadata;
                    if (variableMetaData != null) {
                        metadata = GetCheckMetadataVariable(
                            methodStreamSpec.MethodName,
                            variableMetaData,
                            classpathImportService,
                            typeof(IDictionary<string, object>));
                    }
                    else {
                        metadata = GetCheckMetadataNonVariable(
                            methodStreamSpec.MethodName,
                            methodStreamSpec.ClassName,
                            classpathImportService,
                            typeof(IDictionary<string, object>));
                    }

                    oaTypeName = metadata.TypeName;
                    oaType = (IDictionary<string, object>) metadata.TypeMetadata;
                }

                // Determine event type from class and method name
                // If the method returns EventBean[], require the event type
                Func<EventTypeApplicationType, EventTypeMetadata> metadataFunction = apptype => {
                    var eventTypeName = services.EventTypeNameGeneratorStatement.GetAnonymousMethodHistorical(stream);
                    return new EventTypeMetadata(
                        eventTypeName,
                        @base.ModuleName,
                        EventTypeTypeClass.METHODPOLLDERIVED,
                        apptype,
                        NameAccessModifier.TRANSIENT,
                        EventTypeBusModifier.NONBUS,
                        false,
                        EventTypeIdPair.Unassigned());
                };
                if (methodReflection.ReturnType.IsArray &&
                    methodReflection.ReturnType.GetElementType() == typeof(EventBean) ||
                    isCollection && collectionClass == typeof(EventBean) ||
                    isEnumerator && enumerator == typeof(EventBean)) {
                    var typeName = methodStreamSpec.EventTypeName == null
                        ? eventTypeNameProvidedUDFOrScript
                        : methodStreamSpec.EventTypeName;
                    eventType = EventTypeUtility.RequireEventType(
                        "Method",
                        methodReflection.Name,
                        typeName,
                        services.EventTypeCompileTimeResolver);
                    eventTypeWhenMethodReturnsEventBeans = eventType;
                }
                else if (mapType != null) {
                    eventType = BaseNestableEventUtil.MakeMapTypeCompileTime(
                        metadataFunction.Invoke(EventTypeApplicationType.MAP),
                        mapType,
                        null,
                        null,
                        null,
                        null,
                        services.BeanEventTypeFactoryPrivate,
                        services.EventTypeCompileTimeResolver);
                    services.EventTypeCompileTimeRegistry.NewType(eventType);
                }
                else if (oaType != null) {
                    eventType = BaseNestableEventUtil.MakeOATypeCompileTime(
                        metadataFunction.Invoke(EventTypeApplicationType.OBJECTARR),
                        oaType,
                        null,
                        null,
                        null,
                        null,
                        services.BeanEventTypeFactoryPrivate,
                        services.EventTypeCompileTimeResolver);
                    services.EventTypeCompileTimeRegistry.NewType(eventType);
                }
                else {
                    var stem = services.BeanEventTypeStemService.GetCreateStem(beanClass, null);
                    eventType = new BeanEventType(
                        services.Container,
                        stem,
                        metadataFunction.Invoke(EventTypeApplicationType.CLASS),
                        services.BeanEventTypeFactoryPrivate,
                        null,
                        null,
                        null,
                        null);
                    services.EventTypeCompileTimeRegistry.NewType(eventType);
                }

                // the @type is only allowed in conjunction with EventBean return types
                if (methodStreamSpec.EventTypeName != null && eventTypeWhenMethodReturnsEventBeans == null) {
                    throw new ExprValidationException(EventTypeUtility.DisallowedAtTypeMessage());
                }
            }
            else {
                var eventTypeName = methodStreamSpec.EventTypeName == null
                    ? scriptExpression.EventTypeNameAnnotation
                    : methodStreamSpec.EventTypeName;
                eventType = EventTypeUtility.RequireEventType(
                    "Script",
                    scriptExpression.Script.Name,
                    eventTypeName,
                    services.EventTypeCompileTimeResolver);
            }

            // metadata
            var meta = new MethodPollingViewableMeta(
                methodProviderClass,
                isStaticMethod,
                mapType,
                oaType,
                strategy,
                isCollection,
                isEnumerator,
                variableMetaData,
                eventTypeWhenMethodReturnsEventBeans,
                scriptExpression);
            return new HistoricalEventViewableMethodForge(stream, eventType, methodStreamSpec, meta);
        }
        /// <summary>
        /// Creates a method-invocation polling view for use as a stream that calls a method, or pulls results from cache.
        /// </summary>
        /// <param name="streamNumber">the stream number</param>
        /// <param name="methodStreamSpec">defines the class and method to call</param>
        /// <param name="eventAdapterService">for creating event types and events</param>
        /// <param name="epStatementAgentInstanceHandle">for time-based callbacks</param>
        /// <param name="engineImportService">for resolving configurations</param>
        /// <param name="schedulingService">for scheduling callbacks in expiry-time based caches</param>
        /// <param name="scheduleBucket">for schedules within the statement</param>
        /// <param name="exprEvaluatorContext">expression evaluation context</param>
        /// <param name="variableService">variable service</param>
        /// <param name="statementContext">statement context</param>
        /// <param name="contextName">context name</param>
        /// <param name="dataCacheFactory">factory for cache</param>
        /// <exception cref="ExprValidationException">
        /// if the expressions cannot be validated or the method descriptor
        /// has incorrect class and method names, or parameter number and types don't match
        /// </exception>
        /// <returns>pollable view</returns>
        public static HistoricalEventViewable CreatePollMethodView(
            int streamNumber,
            MethodStreamSpec methodStreamSpec,
            EventAdapterService eventAdapterService,
            EPStatementAgentInstanceHandle epStatementAgentInstanceHandle,
            EngineImportService engineImportService,
            SchedulingService schedulingService,
            ScheduleBucket scheduleBucket,
            ExprEvaluatorContext exprEvaluatorContext,
            VariableService variableService,
            string contextName,
            DataCacheFactory dataCacheFactory,
            StatementContext statementContext)
        {
            VariableMetaData variableMetaData = variableService.GetVariableMetaData(methodStreamSpec.ClassName);
            MethodPollingExecStrategyEnum strategy;
            VariableReader variableReader   = null;
            string         variableName     = null;
            MethodInfo     methodReflection = null;
            object         invocationTarget = null;
            string         eventTypeNameProvidedUDFOrScript = null;

            // see if this is a script in the from-clause
            ExprNodeScript scriptExpression = null;

            if (methodStreamSpec.ClassName == null && methodStreamSpec.MethodName != null)
            {
                var scriptsByName = statementContext.ExprDeclaredService.GetScriptsByName(methodStreamSpec.MethodName);
                if (scriptsByName != null)
                {
                    scriptExpression =
                        ExprDeclaredHelper.GetExistsScript(
                            statementContext.ConfigSnapshot.EngineDefaults.Scripts.DefaultDialect,
                            methodStreamSpec.MethodName, methodStreamSpec.Expressions, scriptsByName,
                            statementContext.ExprDeclaredService);
                }
            }

            try
            {
                if (scriptExpression != null)
                {
                    eventTypeNameProvidedUDFOrScript = scriptExpression.EventTypeNameAnnotation;
                    strategy = MethodPollingExecStrategyEnum.TARGET_SCRIPT;
                    ExprNodeUtility.ValidateSimpleGetSubtree(
                        ExprNodeOrigin.METHODINVJOIN, scriptExpression, statementContext, null, false);
                }
                else if (variableMetaData != null)
                {
                    variableName = variableMetaData.VariableName;
                    if (variableMetaData.ContextPartitionName != null)
                    {
                        if (contextName == null || !contextName.Equals(variableMetaData.ContextPartitionName))
                        {
                            throw new ExprValidationException(
                                      "Variable by name '" + variableMetaData.VariableName +
                                      "' has been declared for context '" + variableMetaData.ContextPartitionName +
                                      "' and can only be used within the same context");
                        }
                        strategy         = MethodPollingExecStrategyEnum.TARGET_VAR_CONTEXT;
                        variableReader   = null;
                        invocationTarget = null;
                    }
                    else
                    {
                        variableReader = variableService.GetReader(
                            methodStreamSpec.ClassName, EPStatementStartMethodConst.DEFAULT_AGENT_INSTANCE_ID);
                        if (variableMetaData.IsConstant)
                        {
                            invocationTarget = variableReader.Value;
                            if (invocationTarget is EventBean)
                            {
                                invocationTarget = ((EventBean)invocationTarget).Underlying;
                            }
                            strategy = MethodPollingExecStrategyEnum.TARGET_CONST;
                        }
                        else
                        {
                            invocationTarget = null;
                            strategy         = MethodPollingExecStrategyEnum.TARGET_VAR;
                        }
                    }
                    methodReflection = engineImportService.ResolveNonStaticMethodOverloadChecked(
                        variableMetaData.VariableType, methodStreamSpec.MethodName);
                }
                else if (methodStreamSpec.ClassName == null)
                {
                    // must be either UDF or script
                    Pair <Type, EngineImportSingleRowDesc> udf = null;
                    try
                    {
                        udf = engineImportService.ResolveSingleRow(methodStreamSpec.MethodName);
                    }
                    catch (EngineImportException ex)
                    {
                        throw new ExprValidationException(
                                  "Failed to find user-defined function '" + methodStreamSpec.MethodName + "': " + ex.Message,
                                  ex);
                    }
                    methodReflection = engineImportService.ResolveMethodOverloadChecked(udf.First, methodStreamSpec.MethodName);
                    invocationTarget = null;
                    variableReader   = null;
                    variableName     = null;
                    strategy         = MethodPollingExecStrategyEnum.TARGET_CONST;
                    eventTypeNameProvidedUDFOrScript = udf.Second.OptionalEventTypeName;
                }
                else
                {
                    methodReflection = engineImportService.ResolveMethodOverloadChecked(methodStreamSpec.ClassName, methodStreamSpec.MethodName);
                    invocationTarget = null;
                    variableReader   = null;
                    variableName     = null;
                    strategy         = MethodPollingExecStrategyEnum.TARGET_CONST;
                }
            }
            catch (ExprValidationException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new ExprValidationException(e.Message, e);
            }

            Type methodProviderClass = null;
            Type beanClass;
            IDictionary <string, object> oaType  = null;
            IDictionary <string, object> mapType = null;
            bool      isCollection = false;
            bool      isIterator   = false;
            EventType eventType;
            EventType eventTypeWhenMethodReturnsEventBeans = null;
            bool      isStaticMethod = false;

            if (methodReflection != null)
            {
                methodProviderClass = methodReflection.DeclaringType;
                isStaticMethod      = variableMetaData == null;

                // Determine object type returned by method
                beanClass = methodReflection.ReturnType;
                if ((beanClass == typeof(void)) || (beanClass.IsBuiltinDataType()))
                {
                    throw new ExprValidationException(
                              "Invalid return type for static method '" + methodReflection.Name + "' of class '" +
                              methodStreamSpec.ClassName + "', expecting a class");
                }

                if (methodReflection.ReturnType.IsArray &&
                    methodReflection.ReturnType.GetElementType() != typeof(EventBean))
                {
                    beanClass = methodReflection.ReturnType.GetElementType();
                }

                Type collectionClass = null;
                Type iteratorClass   = null;

                if (!beanClass.IsGenericDictionary())
                {
                    isCollection = beanClass.IsGenericCollection();
                    if (isCollection)
                    {
                        collectionClass = TypeHelper.GetGenericReturnType(methodReflection, true);
                        beanClass       = collectionClass;
                    }

                    isIterator = beanClass.IsGenericEnumerator() && !beanClass.IsGenericDictionary();
                    if (isIterator)
                    {
                        iteratorClass = TypeHelper.GetGenericReturnType(methodReflection, true);
                        beanClass     = iteratorClass;
                    }
                }

                // If the method returns a Map, look up the map type
                string mapTypeName = null;

                if ((methodReflection.ReturnType.IsGenericStringDictionary()) ||
                    (methodReflection.ReturnType.IsArray && methodReflection.ReturnType.GetElementType().IsGenericStringDictionary()) ||
                    (isCollection && collectionClass.IsImplementsInterface(typeof(Map))) ||
                    (isIterator && iteratorClass.IsImplementsInterface(typeof(Map))))
                {
                    MethodMetadataDesc metadata;
                    if (variableMetaData != null)
                    {
                        metadata = GetCheckMetadataVariable(
                            methodStreamSpec.MethodName, variableMetaData, variableReader, engineImportService,
                            typeof(Map));
                    }
                    else
                    {
                        metadata = GetCheckMetadataNonVariable(
                            methodStreamSpec.MethodName, methodStreamSpec.ClassName, engineImportService, typeof(Map));
                    }
                    mapTypeName = metadata.TypeName;
                    mapType     = (IDictionary <string, object>)metadata.TypeMetadata;
                }

                // If the method returns an object[] or object[][], look up the type information
                string oaTypeName = null;
                if (methodReflection.ReturnType == typeof(object[]) ||
                    methodReflection.ReturnType == typeof(object[][]) ||
                    (isCollection && collectionClass == typeof(object[])) ||
                    (isIterator && iteratorClass == typeof(object[])))
                {
                    MethodMetadataDesc metadata;
                    if (variableMetaData != null)
                    {
                        metadata = GetCheckMetadataVariable(
                            methodStreamSpec.MethodName, variableMetaData, variableReader, engineImportService,
                            typeof(IDictionary <string, object>));
                    }
                    else
                    {
                        metadata = GetCheckMetadataNonVariable(
                            methodStreamSpec.MethodName, methodStreamSpec.ClassName, engineImportService,
                            typeof(IDictionary <string, object>));
                    }
                    oaTypeName = metadata.TypeName;
                    oaType     = (IDictionary <string, object>)metadata.TypeMetadata;
                }

                // Determine event type from class and method name
                // If the method returns EventBean[], require the event type
                if ((methodReflection.ReturnType.IsArray &&
                     methodReflection.ReturnType.GetElementType() == typeof(EventBean)) ||
                    (isCollection && collectionClass == typeof(EventBean)) ||
                    (isIterator && iteratorClass == typeof(EventBean)))
                {
                    string typeName = methodStreamSpec.EventTypeName == null
                        ? eventTypeNameProvidedUDFOrScript
                        : methodStreamSpec.EventTypeName;
                    eventType = EventTypeUtility.RequireEventType(
                        "Method", methodReflection.Name, eventAdapterService, typeName);
                    eventTypeWhenMethodReturnsEventBeans = eventType;
                }
                else if (mapType != null)
                {
                    eventType = eventAdapterService.AddNestableMapType(
                        mapTypeName, mapType, null, false, true, true, false, false);
                }
                else if (oaType != null)
                {
                    eventType = eventAdapterService.AddNestableObjectArrayType(
                        oaTypeName, oaType, null, false, true, true, false, false, false, null);
                }
                else
                {
                    eventType = eventAdapterService.AddBeanType(beanClass.GetDefaultTypeName(), beanClass, false, true, true);
                }

                // the @type is only allowed in conjunction with EventBean return types
                if (methodStreamSpec.EventTypeName != null && eventTypeWhenMethodReturnsEventBeans == null)
                {
                    throw new ExprValidationException(EventTypeUtility.DisallowedAtTypeMessage());
                }
            }
            else
            {
                string eventTypeName = methodStreamSpec.EventTypeName == null
                    ? scriptExpression.EventTypeNameAnnotation
                    : methodStreamSpec.EventTypeName;
                eventType = EventTypeUtility.RequireEventType(
                    "Script", scriptExpression.Script.Name, eventAdapterService, eventTypeName);
            }

            // get configuration for cache
            string configName = methodProviderClass != null ? methodProviderClass.FullName : methodStreamSpec.MethodName;
            ConfigurationMethodRef configCache = engineImportService.GetConfigurationMethodRef(configName);

            if (configCache == null)
            {
                configCache = engineImportService.GetConfigurationMethodRef(configName);
            }
            ConfigurationDataCache dataCacheDesc = (configCache != null) ? configCache.DataCacheDesc : null;
            DataCache dataCache = dataCacheFactory.GetDataCache(
                dataCacheDesc, statementContext, epStatementAgentInstanceHandle, schedulingService, scheduleBucket,
                streamNumber);

            // metadata
            var meta = new MethodPollingViewableMeta(
                methodProviderClass, isStaticMethod, mapType, oaType, invocationTarget, strategy, isCollection,
                isIterator, variableReader, variableName, eventTypeWhenMethodReturnsEventBeans, scriptExpression);

            return(new MethodPollingViewable(methodStreamSpec, dataCache, eventType, exprEvaluatorContext, meta, statementContext.ThreadLocalManager));
        }