private void ResolveResourceRelationship(IDomRelationship domRelationship,
                                                 IHypermediaContext hypermediaContext,
                                                 IHypermediaAssembler hypermediaAssembler,
                                                 IResourcePathContext resourcePathContext,
                                                 Type clrResourceType,
                                                 object clrResource,
                                                 DomReadWriteRelationships domReadWriteRelationships)
        {
            if (domRelationship.IsReadOnly)
            {
                return;
            }

            // Resolve read-write relationship
            var domReadWriteRelationship = (DomReadWriteRelationship)domRelationship;

            // .. Rel
            var apiRelationshipRel = domReadWriteRelationship.Rel;

            // .. Links
            var linkContexts         = new List <ILinkContext>();
            var domRelationshipLinks = (IDomLinks)domReadWriteRelationship.GetNode(DomNodeType.Links);

            if (domRelationshipLinks != null)
            {
                if (domRelationshipLinks.IsReadOnly)
                {
                    // A read-write relationship contains unexpected read-only relationship links.
                    var detail = ServerErrorStrings.DomExceptionDetailReadWriteNodeHasUnexpectedReadOnlyChildNode
                                 .FormatWith(DomNodeType.Relationship, DomNodeType.Links);
                    throw new DomException(detail);
                }

                var domReadWriteRelationshipLinks = (DomReadWriteLinks)domRelationshipLinks;
                foreach (var domLink in domReadWriteRelationshipLinks.Nodes().Cast <IDomLink>())
                {
                    if (domLink.IsReadOnly)
                    {
                        // A read-write relationship contains unexpected read-only relationship link.
                        var detail = ServerErrorStrings.DomExceptionDetailReadWriteNodeHasUnexpectedReadOnlyChildNode
                                     .FormatWith(DomNodeType.Relationship, DomNodeType.Link);
                        throw new DomException(detail);
                    }

                    // Resolve read-write relationship link
                    var domReadWriteLink = (DomReadWriteLink)domLink;
                    var apiLinkRel       = domReadWriteLink.Rel;

                    var apiLinkMeta = default(Meta);
                    var domMeta     = (IDomMeta)domReadWriteLink.GetNode(DomNodeType.Meta);
                    if (domMeta != null)
                    {
                        apiLinkMeta = domMeta.Meta;
                    }

                    var linkContext = new LinkContext(apiLinkRel, apiLinkMeta);
                    linkContexts.Add(linkContext);
                }
            }

            // .. Data
            var resourceType = this.ServiceModel.GetResourceType(clrResourceType);
            var fromApiResourceIdentifier = resourceType.GetApiResourceIdentifier(clrResource);

            var             resourceLinkageKey = new ResourceLinkageKey(fromApiResourceIdentifier, apiRelationshipRel);
            ResourceLinkage resourceLinkage;
            var             hasResourceLinkage = this.DocumentBuilderContext.TryGetResourceLinkage(resourceLinkageKey, out resourceLinkage);

            // .. Meta
            var apiRelationshipMeta = default(Meta);
            var domRelationshipMeta = (IDomMeta)domReadWriteRelationship.GetNode(DomNodeType.Meta);

            if (domRelationshipMeta != null)
            {
                apiRelationshipMeta = domRelationshipMeta.Meta;
            }

            // Create the correct relationship context based on resource linkage (if any).
            RelationshipContext relationshipContext;

            if (hasResourceLinkage)
            {
                var resourceLinkageType = resourceLinkage.Type;
                switch (resourceLinkageType)
                {
                case ResourceLinkageType.ToOneResourceLinkage:
                {
                    var toOneResourceLinkage = resourceLinkage.ToOneResourceLinkage;
                    relationshipContext = new ToOneRelationshipContext(apiRelationshipRel, linkContexts, toOneResourceLinkage, apiRelationshipMeta);
                }
                break;

                case ResourceLinkageType.ToManyResourceLinkage:
                {
                    var toManyResourceLinkage = resourceLinkage.ToManyResourceLinkage;
                    relationshipContext = new ToManyRelationshipContext(apiRelationshipRel, linkContexts, toManyResourceLinkage, apiRelationshipMeta);
                }
                break;

                default:
                {
                    var detail = InfrastructureErrorStrings.InternalErrorExceptionDetailUnknownEnumerationValue
                                 .FormatWith(typeof(ResourceLinkageType).Name, resourceLinkageType);
                    throw new InternalErrorException(detail);
                }
                }
            }
            else
            {
                relationshipContext = new RelationshipContext(apiRelationshipRel, linkContexts, apiRelationshipMeta);
            }

            // Create relationship.
            var apiResourceRelationship = hypermediaAssembler.CreateResourceRelationship(hypermediaContext, resourcePathContext, clrResourceType, clrResource, relationshipContext);

            // Replace the old DOM read-write relationship node with a new DOM read-only relationship created by the framework.
            var domReadOnlyRelationship = DomReadOnlyRelationship.Create(apiRelationshipRel, apiResourceRelationship);

            domReadWriteRelationships.ReplaceNode(domReadWriteRelationship, domReadOnlyRelationship);
        }
        internal void TestIDomRelationshipAbstraction(string name, string expectedRel, Relationship expectedRelationship, IDomRelationship domRelationship)
        {
            // Arrange

            // Act
            this.Output.WriteLine("Test Name: {0}", name);
            this.Output.WriteLine(String.Empty);
            this.Output.WriteLine("Expected Rel:          {0}", expectedRel);
            this.Output.WriteLine("Expected Relationship: {0}", expectedRelationship);

            this.Output.WriteLine(String.Empty);

            var actualRel          = domRelationship.Rel;
            var actualRelationship = domRelationship.Relationship;

            this.Output.WriteLine("Actual Rel:            {0}", actualRel);
            this.Output.WriteLine("Actual Relationship:   {0}", actualRelationship);

            // Assert
            Assert.Equal(expectedRel, actualRel);
            RelationshipAssert.Equal(expectedRelationship, actualRelationship);
        }