Example #1
0
        internal ResolvedAttributeSet FetchResolvedAttributes(ResolveOptions resOpt = null, AttributeContextParameters acpInContext = null)
        {
            bool wasPreviouslyResolving = this.Ctx.Corpus.isCurrentlyResolving;

            this.Ctx.Corpus.isCurrentlyResolving = true;
            if (resOpt == null)
            {
                resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives);
            }

            bool inCircularReference    = false;
            bool wasInCircularReference = resOpt.InCircularReference;

            if (this is CdmEntityDefinition entity)
            {
                inCircularReference = resOpt.CurrentlyResolvingEntities.Contains(entity);
                resOpt.CurrentlyResolvingEntities.Add(entity);
                resOpt.InCircularReference = inCircularReference;

                // uncomment this line as a test to turn off allowing cycles
                //if (inCircularReference)
                //{
                //    return new ResolvedAttributeSet();
                //}
            }

            int currentDepth = resOpt.DepthInfo.CurrentDepth;

            const string   kind = "rasb";
            ResolveContext ctx  = this.Ctx as ResolveContext;
            ResolvedAttributeSetBuilder rasbResult = null;
            ResolvedAttributeSetBuilder rasbCache  = this.FetchObjectFromCache(resOpt, acpInContext);
            CdmAttributeContext         underCtx;

            // store the previous document set, we will need to add it with
            // children found from the constructResolvedTraits call
            SymbolSet currDocRefSet = resOpt.SymbolRefSet;

            if (currDocRefSet == null)
            {
                currDocRefSet = new SymbolSet();
            }
            resOpt.SymbolRefSet = new SymbolSet();

            // if using the cache passes the maxDepth, we cannot use it
            if (rasbCache != null && resOpt.DepthInfo.CurrentDepth + rasbCache.ResolvedAttributeSet.DepthTraveled > resOpt.DepthInfo.MaxDepth)
            {
                rasbCache = null;
            }

            if (rasbCache == null)
            {
                // a new context node is needed for these attributes,
                // this tree will go into the cache, so we hang it off a placeholder parent
                // when it is used from the cache (or now), then this placeholder parent is ignored and the things under it are
                // put into the 'receiving' tree
                underCtx = CdmAttributeContext.GetUnderContextForCacheContext(resOpt, this.Ctx, acpInContext);

                rasbCache = this.ConstructResolvedAttributes(resOpt, underCtx);

                if (rasbCache != null)
                {
                    // register set of possible docs
                    CdmObjectDefinition oDef = this.FetchObjectDefinition <CdmObjectDefinitionBase>(resOpt);
                    if (oDef != null)
                    {
                        ctx.Corpus.RegisterDefinitionReferenceSymbols(oDef, kind, resOpt.SymbolRefSet);

                        if (this.ObjectType == CdmObjectType.EntityDef)
                        {
                            // if we just got attributes for an entity, take the time now to clean up this cached tree and prune out
                            // things that don't help explain where the final set of attributes came from
                            if (underCtx != null)
                            {
                                var scopesForAttributes = new HashSet <CdmAttributeContext>();
                                underCtx.CollectContextFromAtts(rasbCache.ResolvedAttributeSet, scopesForAttributes); // the context node for every final attribute
                                if (!underCtx.PruneToScope(scopesForAttributes))
                                {
                                    return(null);
                                }
                            }
                        }

                        // get the new cache tag now that we have the list of docs
                        string cacheTag = ctx.Corpus.CreateDefinitionCacheTag(resOpt, this, kind, acpInContext != null ? "ctx" : null);

                        // save this as the cached version
                        if (!string.IsNullOrWhiteSpace(cacheTag))
                        {
                            ctx.AttributeCache[cacheTag] = rasbCache;
                        }
                    }
                    // get the 'underCtx' of the attribute set from the acp that is wired into
                    // the target tree
                    underCtx = rasbCache.ResolvedAttributeSet.AttributeContext?.GetUnderContextFromCacheContext(resOpt, acpInContext);
                }
            }
            else
            {
                // get the 'underCtx' of the attribute set from the cache. The one stored there was build with a different
                // acp and is wired into the fake placeholder. so now build a new underCtx wired into the output tree but with
                // copies of all cached children
                underCtx = rasbCache.ResolvedAttributeSet.AttributeContext?.GetUnderContextFromCacheContext(resOpt, acpInContext);
                //underCtx.ValidateLineage(resOpt); // debugging
            }

            if (rasbCache != null)
            {
                // either just built something or got from cache
                // either way, same deal: copy resolved attributes and copy the context tree associated with it
                // 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
                // 2. deep copy the tree.

                // 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
                rasbResult = new ResolvedAttributeSetBuilder
                {
                    ResolvedAttributeSet = rasbCache.ResolvedAttributeSet.Copy()
                };

                // 2. deep copy the tree and map the context references.
                if (underCtx != null) // null context? means there is no tree, probably 0 attributes came out
                {
                    if (!underCtx.AssociateTreeCopyWithAttributes(resOpt, rasbResult.ResolvedAttributeSet))
                    {
                        return(null);
                    }
                }
            }

            if (this is CdmEntityAttributeDefinition)
            {
                // current depth should now be set to this entity attribute level
                resOpt.DepthInfo.CurrentDepth = currentDepth;
                // now at the top of the chain where max depth does not influence the cache
                if (currentDepth == 0)
                {
                    resOpt.DepthInfo.MaxDepthExceeded = false;
                }
            }

            if (!inCircularReference && this.ObjectType == CdmObjectType.EntityDef)
            {
                // should be removed from the root level only
                // if it is in a circular reference keep it there
                resOpt.CurrentlyResolvingEntities.Remove(this as CdmEntityDefinition);
            }
            resOpt.InCircularReference = wasInCircularReference;

            // merge child document set with current
            currDocRefSet.Merge(resOpt.SymbolRefSet);
            resOpt.SymbolRefSet = currDocRefSet;

            this.Ctx.Corpus.isCurrentlyResolving = wasPreviouslyResolving;

            return(rasbResult?.ResolvedAttributeSet);
        }
Example #2
0
        internal ResolvedAttributeSet FetchResolvedAttributes(ResolveOptions resOpt = null, AttributeContextParameters acpInContext = null)
        {
            bool wasPreviouslyResolving = this.Ctx.Corpus.isCurrentlyResolving;

            this.Ctx.Corpus.isCurrentlyResolving = true;
            if (resOpt == null)
            {
                resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives);
            }


            const string   kind = "rasb";
            ResolveContext ctx  = this.Ctx as ResolveContext;
            ResolvedAttributeSetBuilder rasbResult = null;
            // keep track of the context node that the results of this call would like to use as the parent
            CdmAttributeContext         parentCtxForResult = null;
            ResolvedAttributeSetBuilder rasbCache          = this.FetchObjectFromCache(resOpt, acpInContext);
            CdmAttributeContext         underCtx           = null;

            if (acpInContext != null)
            {
                parentCtxForResult = acpInContext.under;
            }

            // store the previous document set, we will need to add it with
            // children found from the constructResolvedTraits call
            SymbolSet currDocRefSet = resOpt.SymbolRefSet;

            if (currDocRefSet == null)
            {
                currDocRefSet = new SymbolSet();
            }
            resOpt.SymbolRefSet = new SymbolSet();

            // if using the cache passes the maxDepth, we cannot use it
            if (rasbCache != null && resOpt.DepthInfo != null && resOpt.DepthInfo.CurrentDepth + rasbCache.ResolvedAttributeSet.DepthTraveled > resOpt.DepthInfo.MaxDepth)
            {
                rasbCache = null;
            }

            if (rasbCache == null)
            {
                if (this.resolvingAttributes)
                {
                    // re-entered this attribute through some kind of self or looping reference.
                    this.Ctx.Corpus.isCurrentlyResolving = wasPreviouslyResolving;
                    //return new ResolvedAttributeSet();  // uncomment this line as a test to turn off allowing cycles
                    resOpt.InCircularReference = true;
                    this.circularReference     = true;
                }
                this.resolvingAttributes = true;

                // a new context node is needed for these attributes,
                // this tree will go into the cache, so we hang it off a placeholder parent
                // when it is used from the cache (or now), then this placeholder parent is ignored and the things under it are
                // put into the 'receiving' tree
                underCtx = CdmAttributeContext.GetUnderContextForCacheContext(resOpt, this.Ctx, acpInContext);

                rasbCache = this.ConstructResolvedAttributes(resOpt, underCtx);

                this.resolvingAttributes = false;

                if (rasbCache != null)
                {
                    // register set of possible docs
                    CdmObjectDefinition oDef = this.FetchObjectDefinition <CdmObjectDefinitionBase>(resOpt);
                    if (oDef != null)
                    {
                        ctx.Corpus.RegisterDefinitionReferenceSymbols(oDef, kind, resOpt.SymbolRefSet);

                        // get the new cache tag now that we have the list of docs
                        string cacheTag = ctx.Corpus.CreateDefinitionCacheTag(resOpt, this, kind, acpInContext != null ? "ctx" : null);

                        // save this as the cached version
                        if (!string.IsNullOrWhiteSpace(cacheTag))
                        {
                            ctx.Cache[cacheTag] = rasbCache;
                        }
                    }
                    // get the 'underCtx' of the attribute set from the acp that is wired into
                    // the target tree
                    underCtx = (rasbCache as ResolvedAttributeSetBuilder).ResolvedAttributeSet.AttributeContext?.GetUnderContextFromCacheContext(resOpt, acpInContext);
                }

                if (this.circularReference)
                {
                    resOpt.InCircularReference = false;
                }
            }
            else
            {
                // get the 'underCtx' of the attribute set from the cache. The one stored there was build with a different
                // acp and is wired into the fake placeholder. so now build a new underCtx wired into the output tree but with
                // copies of all cached children
                underCtx = (rasbCache as ResolvedAttributeSetBuilder).ResolvedAttributeSet.AttributeContext?.GetUnderContextFromCacheContext(resOpt, acpInContext);
                //underCtx.ValidateLineage(resOpt); // debugging
            }

            if (rasbCache != null)
            {
                // either just built something or got from cache
                // either way, same deal: copy resolved attributes and copy the context tree associated with it
                // 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
                // 2. deep copy the tree.

                // 1. deep copy the resolved att set (may have groups) and leave the attCtx pointers set to the old tree
                rasbResult = new ResolvedAttributeSetBuilder();
                rasbResult.ResolvedAttributeSet = (rasbCache as ResolvedAttributeSetBuilder).ResolvedAttributeSet.Copy();

                // 2. deep copy the tree and map the context references.
                if (underCtx != null) // null context? means there is no tree, probably 0 attributes came out
                {
                    if (underCtx.AssociateTreeCopyWithAttributes(resOpt, rasbResult.ResolvedAttributeSet) == false)
                    {
                        return(null);
                    }
                }
            }

            DepthInfo currDepthInfo = resOpt.DepthInfo;

            if (this is CdmEntityAttributeDefinition && currDepthInfo != null)
            {
                // if we hit the maxDepth, we are now going back up
                currDepthInfo.CurrentDepth--;
                // now at the top of the chain where max depth does not influence the cache
                if (currDepthInfo.CurrentDepth <= 0)
                {
                    resOpt.DepthInfo = null;
                }
            }

            // merge child document set with current
            currDocRefSet.Merge(resOpt.SymbolRefSet);
            resOpt.SymbolRefSet = currDocRefSet;

            this.Ctx.Corpus.isCurrentlyResolving = wasPreviouslyResolving;
            return(rasbResult?.ResolvedAttributeSet);
        }