Example #1
0
        public string FetchValueString(ResolveOptions resOpt)
        {
            if (this.Value == null)
            {
                return("");
            }

            if (this.Value is string || this.Value is JValue)
            {
                return((string)this.Value);
            }
            if (Value is CdmObject value)
            {
                CdmObjectDefinition def = value.FetchObjectDefinition <CdmObjectDefinition>(resOpt);
                if (value.ObjectType == CdmObjectType.EntityRef && def?.ObjectType == CdmObjectType.ConstantEntityDef)
                {
                    CdmEntityReference    entShape  = (def as CdmConstantEntityDefinition).EntityShape;
                    List <List <string> > entValues = (def as CdmConstantEntityDefinition).ConstantValues;
                    if (entValues == null || entValues?.Count == 0)
                    {
                        return("");
                    }
                    List <IDictionary <string, string> > rows = new List <IDictionary <string, string> >();
                    ResolvedAttributeSet shapeAtts            = entShape.FetchResolvedAttributes(resOpt);
                    for (int r = 0; r < entValues.Count; r++)
                    {
                        List <string> rowData            = entValues[r];
                        IDictionary <string, string> row = new SortedDictionary <string, string>();
                        if (rowData?.Count > 0)
                        {
                            for (int c = 0; c < rowData.Count; c++)
                            {
                                string            tvalue = rowData[c];
                                ResolvedAttribute colAtt = shapeAtts.Set[c];
                                if (colAtt != null)
                                {
                                    row.Add(colAtt.ResolvedName, tvalue);
                                }
                            }
                            rows.Add(row);
                        }
                    }
                    return(JsonConvert.SerializeObject(rows, Formatting.None, new JsonSerializerSettings {
                        NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver()
                    }));
                }
                dynamic data = value.CopyData(resOpt, new CopyOptions {
                    StringRefs = false
                });
                if (data is string)
                {
                    return((string)data);
                }

                return(JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings {
                    NullValueHandling = NullValueHandling.Ignore, ContractResolver = new CamelCasePropertyNamesContractResolver()
                }));
            }
            return("");
        }
Example #2
0
        internal override void ConstructResolvedTraits(ResolvedTraitSetBuilder rtsb, ResolveOptions resOpt)
        {
            CdmObjectDefinition objDef = this.FetchObjectDefinition <CdmObjectDefinition>(resOpt);

            if (objDef != null)
            {
                ResolvedTraitSet rtsInh = (objDef as CdmObjectDefinitionBase).FetchResolvedTraits(resOpt);
                if (rtsInh != null)
                {
                    rtsInh = rtsInh.DeepCopy();
                }
                rtsb.TakeReference(rtsInh);
            }
            else
            {
                string defName = this.FetchObjectDefinitionName();
                Logger.Warning(defName, this.Ctx, $"unable to resolve an object from the reference '{defName}'");
            }

            if (this.AppliedTraits != null)
            {
                foreach (CdmTraitReference at in this.AppliedTraits)
                {
                    rtsb.MergeTraits(at.FetchResolvedTraits(resOpt));
                }
            }
        }
        public CdmObjectDefinition FetchResolvedReference(ResolveOptions resOpt = null)
        {
            if (resOpt == null)
            {
                resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives);
            }

            if (this.ExplicitReference != null)
            {
                return(this.ExplicitReference);
            }

            if (this.Ctx == null)
            {
                return(null);
            }

            ResolveContext          ctx = this.Ctx as ResolveContext;
            CdmObjectDefinitionBase res = null;

            // if this is a special request for a resolved attribute, look that up now
            int seekResAtt = offsetAttributePromise(this.NamedReference);

            if (seekResAtt >= 0)
            {
                string entName = this.NamedReference.Substring(0, seekResAtt);
                string attName = this.NamedReference.Slice(seekResAtt + resAttToken.Length);
                // get the entity
                CdmObjectDefinition ent = (this.Ctx.Corpus as CdmCorpusDefinition).ResolveSymbolReference(resOpt, this.InDocument, entName, CdmObjectType.EntityDef, retry: true);
                if (ent == null)
                {
                    Logger.Warning(nameof(CdmObjectReferenceBase), ctx, $"unable to resolve an entity named '{entName}' from the reference '{this.NamedReference}");
                    return(null);
                }

                // get the resolved attribute
                ResolvedAttributeSet ras = (ent as CdmObjectDefinitionBase).FetchResolvedAttributes(resOpt);
                ResolvedAttribute    ra  = null;
                if (ras != null)
                {
                    ra = ras.Get(attName);
                }
                if (ra != null)
                {
                    res = ra.Target as dynamic;
                }
                else
                {
                    Logger.Warning(nameof(CdmObjectReferenceBase), ctx, $"couldn't resolve the attribute promise for '{this.NamedReference}'", $"{resOpt.WrtDoc.AtCorpusPath}");
                }
            }
            else
            {
                // normal symbolic reference, look up from the Corpus, it knows where everything is
                res = (this.Ctx.Corpus as CdmCorpusDefinition).ResolveSymbolReference(resOpt, this.InDocument, this.NamedReference, this.ObjectType, retry: true);
            }

            return(res);
        }
Example #4
0
        /// <summary>
        /// Fetches the corresponding object definition for every object reference.
        /// </summary>
        /// <param name="objects"></param>
        /// <param name="resOpt"></param>
        internal void ResolveObjectDefinitions(ResolveOptions resOpt)
        {
            ResolveContext ctx = this.Ctx as ResolveContext;

            resOpt.IndexingDoc = this;

            foreach (var obj in this.InternalObjects)
            {
                switch (obj.ObjectType)
                {
                case CdmObjectType.AttributeRef:
                case CdmObjectType.AttributeGroupRef:
                case CdmObjectType.AttributeContextRef:
                case CdmObjectType.DataTypeRef:
                case CdmObjectType.EntityRef:
                case CdmObjectType.PurposeRef:
                case CdmObjectType.TraitRef:
                    ctx.RelativePath = obj.DeclaredPath;
                    CdmObjectReferenceBase reff = obj as CdmObjectReferenceBase;

                    if (CdmObjectReferenceBase.offsetAttributePromise(reff.NamedReference) < 0)
                    {
                        CdmObjectDefinition resNew = reff.FetchObjectDefinition <CdmObjectDefinition>(resOpt);

                        if (resNew == null)
                        {
                            // It's okay if references can't be resolved when shallow validation is enabled.
                            if (resOpt.ShallowValidation)
                            {
                                Logger.Warning(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, CdmLogCode.WarnResolveReferenceFailure, reff.NamedReference);
                            }
                            else
                            {
                                Logger.Error(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, CdmLogCode.ErrResolveReferenceFailure, reff.NamedReference);

                                // don't check in this file without both of these comments. handy for debug of failed lookups
                                // CdmObjectDefinitionBase resTest = ref.FetchObjectDefinition(resOpt);
                            }
                        }
                        else
                        {
                            Logger.Info(ctx, Tag, nameof(ResolveObjectDefinitions), this.AtCorpusPath, $"resolved '{reff.NamedReference}'");
                        }
                    }
                    break;

                case CdmObjectType.ParameterDef:
                    // when a parameter has a datatype that is a cdm object, validate that any default value is the
                    // right kind object
                    CdmParameterDefinition parameter = obj as CdmParameterDefinition;
                    parameter.ConstTypeCheck(resOpt, this, null);
                    break;
                }
            }

            resOpt.IndexingDoc = null;
        }
Example #5
0
        internal bool IsDerivedFromDef(ResolveOptions resOpt, CdmObjectReference baseCdmObjectRef, string name, string seek)
        {
            if (seek == name)
            {
                return(true);
            }

            CdmObjectDefinition def = baseCdmObjectRef?.FetchObjectDefinition <CdmObjectDefinition>(resOpt);

            if (def != null)
            {
                return(def.IsDerivedFrom(seek, resOpt));
            }
            return(false);
        }
Example #6
0
        /// <summary>
        /// Create a copy of the reference object
        /// </summary>
        public static dynamic CopyIdentifierRef(CdmObjectReference objRef, ResolveOptions resOpt, CopyOptions options)
        {
            string identifier = objRef.NamedReference;

            if (options == null || options.StringRefs == null || options.StringRefs == false)
            {
                return(identifier);
            }

            CdmObjectDefinition resolved = objRef.FetchObjectDefinition <CdmObjectDefinition>(resOpt);

            if (resolved == null)
            {
                return(identifier);
            }

            return(new { AtCorpusPath = resolved.AtCorpusPath, Identifier = identifier });
        }
Example #7
0
        public ResolvedEntityReferenceSet FetchResolvedEntityReferences(ResolveOptions resOpt = null)
        {
            if (resOpt == null)
            {
                resOpt = new ResolveOptions(this, this.Ctx.Corpus.DefaultResolutionDirectives);
            }

            CdmObjectDefinition cdmObjectDef = this.FetchResolvedReference(resOpt);

            if (cdmObjectDef != null)
            {
                return((cdmObjectDef as CdmAttributeGroupDefinition).FetchResolvedEntityReferences(resOpt));
            }
            if (this.ExplicitReference != null)
            {
                return((this.ExplicitReference as CdmAttributeGroupDefinition).FetchResolvedEntityReferences(resOpt));
            }
            return(null);
        }
Example #8
0
 internal CdmObjectDefinition SetObjectDef(CdmObjectDefinition def)
 {
     throw new InvalidOperationException("not a ref");
 }
        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;
            string         cacheTag  = ctx.Corpus.CreateDefinitionCacheTag(resOpt, this, kind, acpInContext != null ? "ctx" : "");
            dynamic        rasbCache = null;

            if (cacheTag != null)
            {
                ctx.Cache.TryGetValue(cacheTag, out rasbCache);
            }
            CdmAttributeContext underCtx = null;

            // 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();

            // get the moniker that was found and needs to be appended to all
            // refs in the children attribute context nodes
            string fromMoniker = resOpt.FromMoniker;

            resOpt.FromMoniker = 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());
                }
                this.resolvingAttributes = true;

                // if a new context node is needed for these attributes, make it now
                if (acpInContext != null)
                {
                    underCtx = CdmAttributeContext.CreateChildUnder(resOpt, acpInContext);
                }

                rasbCache = this.ConstructResolvedAttributes(resOpt, underCtx);

                if (rasbCache != null)
                {
                    this.resolvingAttributes = false;

                    // 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
                        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;
                        }

                        if (!string.IsNullOrWhiteSpace(fromMoniker) && acpInContext != null &&
                            (this is CdmObjectReferenceBase) && (this as CdmObjectReferenceBase).NamedReference != null)
                        {
                            // create a fresh context
                            CdmAttributeContext oldContext = acpInContext.under.Contents[acpInContext.under.Contents.Count - 1] as CdmAttributeContext;
                            acpInContext.under.Contents.RemoveAt(acpInContext.under.Contents.Count - 1);
                            underCtx = CdmAttributeContext.CreateChildUnder(resOpt, acpInContext);

                            CdmAttributeContext newContext = oldContext.CopyAttributeContextTree(resOpt, underCtx, rasbCache.ResolvedAttributeSet, null, fromMoniker);
                            // since THIS should be a refererence to a thing found in a moniker document, it already has a moniker in the reference
                            // this function just added that same moniker to everything in the sub-tree but now this one symbol has too many
                            // remove one
                            string monikerPathAdded = $"{fromMoniker}/";
                            if (newContext.Definition != null && newContext.Definition.NamedReference != null &&
                                newContext.Definition.NamedReference.StartsWith(monikerPathAdded))
                            {
                                // slice it off the front
                                newContext.Definition.NamedReference = newContext.Definition.NamedReference.Substring(monikerPathAdded.Length);
                            }
                        }
                    }
                }
            }
            else
            {
                // cache found. if we are building a context, then fix what we got instead of making a new one
                if (acpInContext != null)
                {
                    // make the new context
                    underCtx = CdmAttributeContext.CreateChildUnder(resOpt, acpInContext);

                    rasbCache.ResolvedAttributeSet.AttributeContext.CopyAttributeContextTree(resOpt, underCtx, rasbCache.ResolvedAttributeSet, null, fromMoniker);
                }
            }

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

            this.Ctx.Corpus.isCurrentlyResolving = wasPreviouslyResolving;
            return(rasbCache?.ResolvedAttributeSet);
        }
Example #10
0
        internal override ResolvedAttributeSetBuilder ConstructResolvedAttributes(ResolveOptions resOpt, CdmAttributeContext under = null)
        {
            // find and cache the complete set of attributes
            // attributes definitions originate from and then get modified by subsequent re-definitions from (in this order):
            // an extended entity, traits applied to extended entity, exhibited traits of main entity, the (datatype or entity) used as an attribute, traits applied to that datatype or entity,
            // the relationsip of the attribute, the attribute definition itself and included attribute groups, dynamic traits applied to the attribute.
            this.Rasb = new ResolvedAttributeSetBuilder();
            this.Rasb.ResolvedAttributeSet.AttributeContext = under;

            if (this.ExtendsEntity != null)
            {
                CdmObjectReference         extRef          = this.ExtendsEntityRef;
                CdmAttributeContext        extendsRefUnder = null;
                AttributeContextParameters acpExtEnt       = null;

                if (under != null)
                {
                    AttributeContextParameters acpExt = new AttributeContextParameters
                    {
                        under         = under,
                        type          = CdmAttributeContextType.EntityReferenceExtends,
                        Name          = "extends",
                        Regarding     = null,
                        IncludeTraits = false
                    };
                    extendsRefUnder = this.Rasb.ResolvedAttributeSet.CreateAttributeContext(resOpt, acpExt);
                }

                if (extRef.ExplicitReference != null && extRef.FetchObjectDefinition <CdmObjectDefinition>(resOpt).ObjectType == CdmObjectType.ProjectionDef)
                {
                    // A Projection

                    CdmObjectDefinition extRefObjDef = extRef.FetchObjectDefinition <CdmObjectDefinition>(resOpt);
                    if (extendsRefUnder != null)
                    {
                        acpExtEnt = new AttributeContextParameters
                        {
                            under         = extendsRefUnder,
                            type          = CdmAttributeContextType.Projection,
                            Name          = extRefObjDef.GetName(),
                            Regarding     = extRef,
                            IncludeTraits = false
                        };
                    }

                    ProjectionDirective projDirective = new ProjectionDirective(resOpt, this, ownerRef: extRef);
                    CdmProjection       projDef       = (CdmProjection)extRefObjDef;
                    ProjectionContext   projCtx       = projDef.ConstructProjectionContext(projDirective, extendsRefUnder);

                    this.Rasb.ResolvedAttributeSet = projDef.ExtractResolvedAttributes(projCtx);
                }
                else
                {
                    // An Entity Reference

                    if (extendsRefUnder != null)
                    {
                        // usually the extended entity is a reference to a name.
                        // it is allowed however to just define the entity inline.
                        acpExtEnt = new AttributeContextParameters
                        {
                            under         = extendsRefUnder,
                            type          = CdmAttributeContextType.Entity,
                            Name          = extRef.NamedReference ?? extRef.ExplicitReference.GetName(),
                            Regarding     = extRef,
                            IncludeTraits = false
                        };
                    }

                    // save moniker, extended entity may attach a different moniker that we do not
                    // want to pass along to getting this entities attributes
                    string oldMoniker = resOpt.FromMoniker;

                    this.Rasb.MergeAttributes((this.ExtendsEntityRef as CdmObjectReferenceBase).FetchResolvedAttributes(resOpt, acpExtEnt));

                    if (!resOpt.CheckAttributeCount(this.Rasb.ResolvedAttributeSet.ResolvedAttributeCount))
                    {
                        Logger.Error(nameof(CdmEntityDefinition), this.Ctx, $"Maximum number of resolved attributes reached for the entity: {this.EntityName}.");
                        return(null);
                    }

                    if (this.ExtendsEntityResolutionGuidance != null)
                    {
                        // some guidance was given on how to integrate the base attributes into the set. apply that guidance
                        ResolvedTraitSet rtsBase = this.FetchResolvedTraits(resOpt);

                        // this context object holds all of the info about what needs to happen to resolve these attributes.
                        // make a copy and set defaults if needed
                        CdmAttributeResolutionGuidance resGuide = (CdmAttributeResolutionGuidance)this.ExtendsEntityResolutionGuidance.Copy(resOpt);
                        resGuide.UpdateAttributeDefaults(resGuide.FetchObjectDefinitionName());
                        // holds all the info needed by the resolver code
                        AttributeResolutionContext arc = new AttributeResolutionContext(resOpt, resGuide, rtsBase);

                        this.Rasb.GenerateApplierAttributes(arc, false); // true = apply the prepared traits to new atts
                    }

                    // reset to the old moniker
                    resOpt.FromMoniker = oldMoniker;
                }
            }

            this.Rasb.MarkInherited();
            this.Rasb.ResolvedAttributeSet.AttributeContext = under;

            if (this.Attributes != null)
            {
                int l = this.Attributes.Count;
                for (int i = 0; i < l; i++)
                {
                    dynamic                    att      = this.Attributes.AllItems[i];
                    CdmAttributeContext        attUnder = under;
                    AttributeContextParameters acpAtt   = null;
                    if (under != null)
                    {
                        acpAtt = new AttributeContextParameters
                        {
                            under         = under,
                            type          = CdmAttributeContextType.AttributeDefinition,
                            Name          = att.FetchObjectDefinitionName(),
                            Regarding     = att,
                            IncludeTraits = false
                        };
                    }
                    this.Rasb.MergeAttributes(att.FetchResolvedAttributes(resOpt, acpAtt));

                    if (!resOpt.CheckAttributeCount(this.Rasb.ResolvedAttributeSet.ResolvedAttributeCount))
                    {
                        Logger.Error(nameof(CdmEntityDefinition), this.Ctx, $"Maximum number of resolved attributes reached for the entity: {this.EntityName}.");
                        return(null);
                    }
                }
            }
            this.Rasb.MarkOrder();
            this.Rasb.ResolvedAttributeSet.AttributeContext = under;

            // things that need to go away
            this.Rasb.RemoveRequestedAtts();

            return(this.Rasb);
        }
Example #11
0
        internal override ResolvedTraitSet FetchResolvedTraits(ResolveOptions resOpt = null)
        {
            if (resOpt == null)
            {
                resOpt = new ResolveOptions(this);
            }

            if (this.NamedReference != null && this.AppliedTraits == null)
            {
                const string   kind             = "rts";
                ResolveContext ctx              = this.Ctx as ResolveContext;
                string         objDefName       = this.FetchObjectDefinitionName();
                string         cacheTag         = ((CdmCorpusDefinition)ctx.Corpus).CreateDefinitionCacheTag(resOpt, this, kind, "", true);
                dynamic        rtsResultDynamic = null;
                if (cacheTag != null)
                {
                    ctx.Cache.TryGetValue(cacheTag, out rtsResultDynamic);
                }
                ResolvedTraitSet rtsResult = rtsResultDynamic as ResolvedTraitSet;

                // store the previous document set, we will need to add it with
                // children found from the constructResolvedTraits call
                SymbolSet currSymRefSet = resOpt.SymbolRefSet;
                if (currSymRefSet == null)
                {
                    currSymRefSet = new SymbolSet();
                }
                resOpt.SymbolRefSet = new SymbolSet();

                if (rtsResult == null)
                {
                    CdmObjectDefinition objDef = this.FetchObjectDefinition <CdmObjectDefinition>(resOpt);
                    if (objDef != null)
                    {
                        rtsResult = (objDef as CdmObjectDefinitionBase).FetchResolvedTraits(resOpt);
                        if (rtsResult != null)
                        {
                            rtsResult = rtsResult.DeepCopy();
                        }

                        // register set of possible docs
                        ((CdmCorpusDefinition)ctx.Corpus).RegisterDefinitionReferenceSymbols(objDef, kind, resOpt.SymbolRefSet);

                        // get the new cache tag now that we have the list of docs
                        cacheTag = ((CdmCorpusDefinition)ctx.Corpus).CreateDefinitionCacheTag(resOpt, this, kind, "", true);
                        if (!string.IsNullOrWhiteSpace(cacheTag))
                        {
                            ctx.Cache[cacheTag] = rtsResult;
                        }
                    }
                }
                else
                {
                    // cache was found
                    // get the SymbolSet for this cached object
                    string key = CdmCorpusDefinition.CreateCacheKeyFromObject(this, kind);
                    ((CdmCorpusDefinition)ctx.Corpus).DefinitionReferenceSymbols.TryGetValue(key, out SymbolSet tempDocRefSet);
                    resOpt.SymbolRefSet = tempDocRefSet;
                }

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

                return(rtsResult);
            }
            else
            {
                return(base.FetchResolvedTraits(resOpt));
            }
        }
Example #12
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 #13
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);
        }