예제 #1
0
        private IList<StmtClassForgeableFactory> ValidateContextDetail(
            ContextSpec contextSpec,
            int nestingLevel,
            CreateContextValidationEnv validationEnv)
        {
            ISet<string> eventTypesReferenced = new HashSet<string>();
            IList<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>();
            
            if (contextSpec is ContextSpecKeyed) {
                var segmented = (ContextSpecKeyed) contextSpec;
                IDictionary<string, EventType> asNames = new Dictionary<string, EventType>();
                var partitionHasNameAssignment = false;
                Type[] getterTypes = null;
                foreach (var partition in segmented.Items) {
                    Pair<FilterSpecCompiled, IList<StmtClassForgeableFactory>> pair = CompilePartitionedFilterSpec(
                        partition.FilterSpecRaw, eventTypesReferenced, validationEnv);
                    FilterSpecCompiled filterSpecCompiled = pair.First;
                    additionalForgeables.AddAll(pair.Second);
                   
                    partition.FilterSpecCompiled = filterSpecCompiled;

                    var getters = new EventPropertyGetterSPI[partition.PropertyNames.Count];
                    var serdes = new DataInputOutputSerdeForge[partition.PropertyNames.Count];
                    var eventType = (EventTypeSPI) filterSpecCompiled.FilterForEventType;
                    getterTypes = new Type[partition.PropertyNames.Count];
                    
                    for (var i = 0; i < partition.PropertyNames.Count; i++) {
                        var propertyName = partition.PropertyNames[i];
                        var getter = eventType.GetGetterSPI(propertyName);
                        if (getter == null) {
                            throw new ExprValidationException(
                                "For context '" + validationEnv.ContextName + "' property name '" + propertyName + "' not found on type " + eventType.Name);
                        }
                        getters[i] = getter;
                        getterTypes[i] = eventType.GetPropertyType(propertyName);
                        serdes[i] = validationEnv.Services.SerdeResolver.SerdeForFilter(
                            getterTypes[i], validationEnv.StatementRawInfo);
                    }

                    partition.Getters = getters;
                    partition.LookupableSerdes = serdes;

                    if (partition.AliasName != null) {
                        partitionHasNameAssignment = true;
                        ValidateAsName(asNames, partition.AliasName, filterSpecCompiled.FilterForEventType);
                    }
                }

                // plan multi-key, make sure we use the same multikey for all items
                MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey(
                    getterTypes, false, @base.StatementRawInfo, validationEnv.Services.SerdeResolver);
                additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables);
                foreach (ContextSpecKeyedItem partition in segmented.Items) {
                    partition.KeyMultiKey = multiKeyPlan.ClassRef;
                }
                segmented.MultiKeyClassRef = multiKeyPlan.ClassRef;
                
                if (segmented.OptionalInit != null) {
                    asNames.Clear();
                    foreach (var initCondition in segmented.OptionalInit) {
                        ContextDetailMatchPair pair = ValidateRewriteContextCondition(
                            true,
                            nestingLevel,
                            initCondition,
                            eventTypesReferenced,
                            new MatchEventSpec(),
                            new EmptySet<string>(),
                            validationEnv);
                        additionalForgeables.AddAll(pair.AdditionalForgeables);

                        var filterForType = initCondition.FilterSpecCompiled.FilterForEventType;
                        var found = false;
                        foreach (var partition in segmented.Items) {
                            if (partition.FilterSpecCompiled.FilterForEventType == filterForType) {
                                found = true;
                                break;
                            }
                        }

                        if (!found) {
                            throw new ExprValidationException(
                                "Segmented context '" +
                                validationEnv.ContextName +
                                "' requires that all of the event types that are listed in the initialized-by also appear in the partition-by, type '" +
                                filterForType.Name +
                                "' is not one of the types listed in partition-by");
                        }

                        if (initCondition.OptionalFilterAsName != null) {
                            if (partitionHasNameAssignment) {
                                throw new ExprValidationException(
                                    "Segmented context '" +
                                    validationEnv.ContextName +
                                    "' requires that either partition-by or initialized-by assign stream names, but not both");
                            }

                            ValidateAsName(asNames, initCondition.OptionalFilterAsName, filterForType);
                        }
                    }
                }

                if (segmented.OptionalTermination != null) {
                    var matchEventSpec = new MatchEventSpec();
                    var allTags = new LinkedHashSet<string>();
                    foreach (var partition in segmented.Items) {
                        if (partition.AliasName != null) {
                            allTags.Add(partition.AliasName);
                            var eventType = partition.FilterSpecCompiled.FilterForEventType;
                            matchEventSpec.TaggedEventTypes[partition.AliasName] = new Pair<EventType,string>(
                                eventType, partition.FilterSpecRaw.EventTypeName);
                            var serdeForgeables = SerdeEventTypeUtility.Plan(
                                eventType,
                                validationEnv.StatementRawInfo,
                                validationEnv.Services.SerdeEventTypeRegistry,
                                validationEnv.Services.SerdeResolver);
                            additionalForgeables.AddAll(serdeForgeables);
                        }
                    }

                    if (segmented.OptionalInit != null) {
                        foreach (var initCondition in segmented.OptionalInit) {
                            if (initCondition.OptionalFilterAsName != null) {
                                allTags.Add(initCondition.OptionalFilterAsName);
                                matchEventSpec.TaggedEventTypes.Put(
                                    initCondition.OptionalFilterAsName,
                                    new Pair<EventType, string>(
                                        initCondition.FilterSpecCompiled.FilterForEventType,
                                        initCondition.FilterSpecRaw.EventTypeName));
                            }
                        }
                    }

                    var endCondition = ValidateRewriteContextCondition(
                        false,
                        nestingLevel,
                        segmented.OptionalTermination,
                        eventTypesReferenced,
                        matchEventSpec,
                        allTags,
                        validationEnv);
                    additionalForgeables.AddAll(endCondition.AdditionalForgeables);

                    segmented.OptionalTermination = endCondition.Condition;
                }
            }
            else if (contextSpec is ContextSpecCategory) {
                // compile filter
                var category = (ContextSpecCategory) contextSpec;
                ValidateNotTable(category.FilterSpecRaw.EventTypeName, validationEnv.Services);
                var raw = new FilterStreamSpecRaw(
                    category.FilterSpecRaw,
                    ViewSpec.EMPTY_VIEWSPEC_ARRAY,
                    null,
                    StreamSpecOptions.DEFAULT);

                var compiledDesc = StreamSpecCompiler.CompileFilter(
                    raw,
                    false,
                    false,
                    true,
                    false,
                    null,
                    validationEnv.StatementRawInfo,
                    validationEnv.Services);
                var result = (FilterStreamSpecCompiled) compiledDesc.StreamSpecCompiled;
                additionalForgeables.AddAll(compiledDesc.AdditionalForgeables);
                
                category.FilterSpecCompiled = result.FilterSpecCompiled;
                validationEnv.FilterSpecCompileds.Add(result.FilterSpecCompiled);

                // compile expressions
                foreach (var item in category.Items) {
                    ValidateNotTable(category.FilterSpecRaw.EventTypeName, validationEnv.Services);
                    var filterSpecRaw = new FilterSpecRaw(
                        category.FilterSpecRaw.EventTypeName,
                        Collections.SingletonList(item.Expression),
                        null);
                    var rawExpr = new FilterStreamSpecRaw(
                        filterSpecRaw,
                        ViewSpec.EMPTY_VIEWSPEC_ARRAY,
                        null,
                        StreamSpecOptions.DEFAULT);
                    var compiledDescItems = StreamSpecCompiler.CompileFilter(
                        rawExpr,
                        false,
                        false,
                        true,
                        false,
                        null,
                        validationEnv.StatementRawInfo,
                        validationEnv.Services);
                    var compiled = (FilterStreamSpecCompiled) compiledDescItems.StreamSpecCompiled;
                    additionalForgeables.AddAll(compiledDescItems.AdditionalForgeables);
                    compiled.FilterSpecCompiled.TraverseFilterBooleanExpr(
                        node => validationEnv.FilterBooleanExpressions.Add(node));
                    item.FilterPlan = compiled.FilterSpecCompiled.Parameters;
                }
            }
            else if (contextSpec is ContextSpecHash) {
                var hashed = (ContextSpecHash) contextSpec;
                foreach (var hashItem in hashed.Items) {
                    var raw = new FilterStreamSpecRaw(
                        hashItem.FilterSpecRaw,
                        ViewSpec.EMPTY_VIEWSPEC_ARRAY,
                        null,
                        StreamSpecOptions.DEFAULT);
                    ValidateNotTable(hashItem.FilterSpecRaw.EventTypeName, validationEnv.Services);

                    var compiledDesc = StreamSpecCompiler.Compile(
                        raw,
                        eventTypesReferenced,
                        false,
                        false,
                        true,
                        false,
                        null,
                        0,
                        validationEnv.StatementRawInfo,
                        validationEnv.Services);
                    additionalForgeables.AddAll(compiledDesc.AdditionalForgeables);
                    var result = (FilterStreamSpecCompiled)  compiledDesc.StreamSpecCompiled;

                    validationEnv.FilterSpecCompileds.Add(result.FilterSpecCompiled);
                    hashItem.FilterSpecCompiled = result.FilterSpecCompiled;

                    // validate parameters
                    var streamTypes = new StreamTypeServiceImpl(
                        result.FilterSpecCompiled.FilterForEventType,
                        null,
                        true);
                    var validationContext =
                        new ExprValidationContextBuilder(
                                streamTypes,
                                validationEnv.StatementRawInfo,
                                validationEnv.Services)
                            .WithIsFilterExpression(true)
                            .Build();
                    ExprNodeUtilityValidate.Validate(
                        ExprNodeOrigin.CONTEXT,
                        Collections.SingletonList(hashItem.Function),
                        validationContext);
                }
            }
            else if (contextSpec is ContextSpecInitiatedTerminated) {
                var def = (ContextSpecInitiatedTerminated) contextSpec;
                var startCondition = ValidateRewriteContextCondition(
                    true,
                    nestingLevel,
                    def.StartCondition,
                    eventTypesReferenced,
                    new MatchEventSpec(),
                    new LinkedHashSet<string>(),
                    validationEnv);
                additionalForgeables.AddAll(startCondition.AdditionalForgeables);

                var endCondition = ValidateRewriteContextCondition(
                    false,
                    nestingLevel,
                    def.EndCondition,
                    eventTypesReferenced,
                    startCondition.Matches,
                    startCondition.AllTags,
                    validationEnv);
                additionalForgeables.AddAll(endCondition.AdditionalForgeables);
                
                def.StartCondition = startCondition.Condition;
                def.EndCondition = endCondition.Condition;

                if (def.DistinctExpressions != null) {
                    if (!(startCondition.Condition is ContextSpecConditionFilter)) {
                        throw new ExprValidationException(
                            "Distinct-expressions require a stream as the initiated-by condition");
                    }

                    var distinctExpressions = def.DistinctExpressions;
                    if (distinctExpressions.Length == 0) {
                        throw new ExprValidationException("Distinct-expressions have not been provided");
                    }

                    var filter = (ContextSpecConditionFilter) startCondition.Condition;
                    if (filter.OptionalFilterAsName == null) {
                        throw new ExprValidationException(
                            "Distinct-expressions require that a stream name is assigned to the stream using 'as'");
                    }

                    var types = new StreamTypeServiceImpl(
                        filter.FilterSpecCompiled.FilterForEventType,
                        filter.OptionalFilterAsName,
                        true);
                    var validationContext =
                        new ExprValidationContextBuilder(types, validationEnv.StatementRawInfo, validationEnv.Services)
                            .WithAllowBindingConsumption(true)
                            .Build();
                    for (var i = 0; i < distinctExpressions.Length; i++) {
                        ExprNodeUtilityValidate.ValidatePlainExpression(
                            ExprNodeOrigin.CONTEXTDISTINCT,
                            distinctExpressions[i]);
                        distinctExpressions[i] = ExprNodeUtilityValidate.GetValidatedSubtree(
                            ExprNodeOrigin.CONTEXTDISTINCT,
                            distinctExpressions[i],
                            validationContext);
                    }

                    var multiKeyPlan = MultiKeyPlanner.PlanMultiKey(
                        distinctExpressions,
                        false,
                        @base.StatementRawInfo,
                        validationEnv.Services.SerdeResolver);
                    def.DistinctMultiKey = multiKeyPlan.ClassRef;
                    additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables);
                }
            }
            else if (contextSpec is ContextNested) {
                var nested = (ContextNested) contextSpec;
                var level = 0;
                ISet<string> namesUsed = new HashSet<string>();
                namesUsed.Add(validationEnv.ContextName);
                foreach (var nestedContext in nested.Contexts) {
                    if (namesUsed.Contains(nestedContext.ContextName)) {
                        throw new ExprValidationException(
                            "Context by name '" +
                            nestedContext.ContextName +
                            "' has already been declared within nested context '" +
                            validationEnv.ContextName +
                            "'");
                    }

                    namesUsed.Add(nestedContext.ContextName);

                    var forgeables = ValidateContextDetail(nestedContext.ContextDetail, level, validationEnv);
                    additionalForgeables.AddAll(forgeables);
                    level++;
                }
            }
            else {
                throw new IllegalStateException("Unrecognized context detail " + contextSpec);
            }

            return additionalForgeables;
        }
예제 #2
0
        public override ExprNode Validate(ExprValidationContext validationContext)
        {
            ExprNodeUtilityValidate.Validate(ExprNodeOrigin.PLUGINSINGLEROWPARAM, ChainSpec, validationContext);

            // get first chain item
            IList<ExprChainedSpec> chainList = new List<ExprChainedSpec>(ChainSpec);
            var firstItem = chainList.DeleteAt(0);

            // Get the types of the parameters for the first invocation
            var allowWildcard = validationContext.StreamTypeService.EventTypes.Length == 1;
            EventType streamZeroType = null;
            if (validationContext.StreamTypeService.EventTypes.Length > 0) {
                streamZeroType = validationContext.StreamTypeService.EventTypes[0];
            }

            var staticMethodDesc = ExprNodeUtilityResolve.ResolveMethodAllowWildcardAndStream(
                clazz.FullName,
                null,
                firstItem.Name,
                firstItem.Parameters,
                allowWildcard,
                streamZeroType,
                new ExprNodeUtilResolveExceptionHandlerDefault(firstItem.Name, true),
                FunctionName,
                validationContext.StatementRawInfo,
                validationContext.StatementCompileTimeService);

            var allowValueCache = true;
            bool isReturnsConstantResult;
            switch (config.ValueCache) {
                case ConfigurationCompilerPlugInSingleRowFunction.ValueCacheEnum.DISABLED:
                    isReturnsConstantResult = false;
                    allowValueCache = false;
                    break;

                case ConfigurationCompilerPlugInSingleRowFunction.ValueCacheEnum.CONFIGURED: {
                    var isUDFCache = validationContext.StatementCompileTimeService.Configuration.Compiler.Expression
                        .IsUdfCache;
                    isReturnsConstantResult = isUDFCache && staticMethodDesc.IsAllConstants && chainList.IsEmpty();
                    allowValueCache = isUDFCache;
                    break;
                }

                case ConfigurationCompilerPlugInSingleRowFunction.ValueCacheEnum.ENABLED:
                    isReturnsConstantResult = staticMethodDesc.IsAllConstants && chainList.IsEmpty();
                    break;

                default:
                    throw new IllegalStateException("Invalid value cache code " + config.ValueCache);
            }

            // this may return a pair of null if there is no lambda or the result cannot be wrapped for lambda-function use
            ExprDotStaticMethodWrap optionalLambdaWrap = ExprDotStaticMethodWrapFactory.Make(
                staticMethodDesc.ReflectionMethod,
                chainList,
                config.OptionalEventTypeName,
                validationContext);
            var typeInfo = optionalLambdaWrap != null
                ? optionalLambdaWrap.TypeInfo
                : EPTypeHelper.SingleValue(staticMethodDesc.ReflectionMethod.ReturnType);

            var eval = ExprDotNodeUtility.GetChainEvaluators(
                    -1,
                    typeInfo,
                    chainList,
                    validationContext,
                    false,
                    new ExprDotNodeFilterAnalyzerInputStatic())
                .ChainWithUnpack;
            var staticMethodForge = new ExprDotNodeForgeStaticMethod(
                this,
                isReturnsConstantResult,
                clazz.Name,
                staticMethodDesc.ReflectionMethod,
                staticMethodDesc.ChildForges,
                allowValueCache && staticMethodDesc.IsAllConstants,
                eval,
                optionalLambdaWrap,
                config.IsRethrowExceptions,
                null,
                validationContext.StatementName);

            // If caching the result, evaluate now and return the result.
            if (isReturnsConstantResult) {
                forge = new ExprPlugInSingleRowNodeForgeConst(this, staticMethodForge);
            }
            else {
                forge = new ExprPlugInSingleRowNodeForgeNC(this, staticMethodForge);
            }

            return null;
        }
예제 #3
0
        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;
        }