예제 #1
0
        public void DoWork(IRequest request)
        {
            // only atom entry supported!!!
            if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
            {
                throw new RequestException("Atom entry content type expected");
            }

            // deserialize the request stream to a SyncFeedEntry
            SyncFeedEntry entry  = new SyncFeedEntry();
            XmlReader     reader = XmlReader.Create(request.Stream);

            reader.MoveToContent();
            entry.ReadXml(reader, typeof(SyncDigestPayload));

            if (null == entry.Linked)
            {
                throw new RequestException("Invalid content: element 'linked' missing");
            }

            // We check for equality of the urls of the request url and
            // in the linked element up to the resourceKind.

            string         requestEndpointUrl            = _requestContext.OriginEndPoint;
            RequestContext entryResourceAsRequestContext = new RequestContext(new Sage.Common.Syndication.SDataUri(entry.Linked.Resource));    // TODO: not really nice here.
            string         linkedResourceUrl             = entryResourceAsRequestContext.OriginEndPoint;

            if (!string.Equals(requestEndpointUrl, linkedResourceUrl, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new RequestException("Request url and linked entry resource not matching.");
            }

            string resourceKindName = _requestContext.ResourceKind.ToString();

            Guid   currentUuid = (Guid)TypeDescriptor.GetConverter(typeof(Guid)).ConvertFrom(_requestContext.ResourceKey);
            Guid   newUuid     = entry.Linked.Uuid;
            string newLocalId  = entryResourceAsRequestContext.SdataUri.CollectionPredicate;

            // update the correlation entry in the sync store.
            // if the uuid should be updated we have to remove the current correlation and then add a new one.
            // otherwise we update the current correlation.
            ICorrelatedResSyncInfoStore correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);
            // create the target correlation
            ResSyncInfo           targetResSyncInfo = new ResSyncInfo(newUuid, requestEndpointUrl, 0, string.Empty, DateTime.Now);
            CorrelatedResSyncInfo targetInfo        = new CorrelatedResSyncInfo(newLocalId, targetResSyncInfo);

            if (currentUuid == newUuid)
            {
                correlatedResSyncInfoStore.Update(resourceKindName, targetInfo);
            }
            else
            {
                correlatedResSyncInfoStore.Delete(resourceKindName, currentUuid);
                correlatedResSyncInfoStore.Add(resourceKindName, targetInfo);
            }

            // create response
            SyncFeed feed = new SyncFeed();

            feed.FeedType = FeedType.LinkedSingle;

            // create entry
            SyncFeedEntry responseEntry = new SyncFeedEntry();

            responseEntry.Id    = FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, targetInfo.ResSyncInfo.Uuid);
            responseEntry.Title = FeedMetadataHelpers.BuildLinkedEntryTitle(_requestContext, targetInfo.ResSyncInfo.Uuid);

            LinkedElement linkedElement = new LinkedElement();

            linkedElement.Resource = FeedMetadataHelpers.BuildEntryResourceUrl(_requestContext, targetInfo.LocalId);
            linkedElement.Uuid     = targetInfo.ResSyncInfo.Uuid;
            responseEntry.Linked   = linkedElement;

            feed.Entries.Add(responseEntry);

            request.Response.Serializer  = new SyncFeedSerializer();
            request.Response.Feed        = (IFeed)feed;
            request.Response.ContentType = MediaType.AtomEntry;
        }
        public void Update(FeedEntry entry)
        {
            // only atom entry supported!!!
            if (_request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
            {
                throw new RequestException("Atom entry content type expected");
            }

            // resource key must exist in url
            if (string.IsNullOrEmpty(_requestContext.ResourceKey))
            {
                throw new RequestException("ResourceKey missing in requested url.");
            }

            string         requestEndPointUrl;
            RequestContext entryResourceAsRequestContext;

            string url;             // The url that references an existing resource
            string localId;         // will be parsed from urlAttrValue and set to the key attribute of the result resource payload
            Guid   uuid;            // the new uuid

            // retrieve the feed entry
            //entry = FeedComponentFactory.Create<ILinkingResourceFeedEntry>(request.Stream);


            // Get the uuid from query
            uuid = (Guid)TypeDescriptor.GetConverter(typeof(Guid)).ConvertFrom(_requestContext.ResourceKey);


            if (null == entry)
            {
                throw new RequestException("sdata payload element missing");
            }

            // the consumer MUST provide an sdata:url attribute that references an existing resource.
            url = entry.Uri;
            if (string.IsNullOrEmpty(url))
            {
                throw new RequestException("sdata url attribute missing for resource payload element.");
            }


            // Parse the url of thew url attribute to get the local id.
            // Additionally we check for equality of the urls of the request url and
            // in the linked element up to the resourceKind.
            requestEndPointUrl            = _requestContext.OriginEndPoint;
            entryResourceAsRequestContext = new RequestContext(new Sage.Common.Syndication.SDataUri(url));    // TODO: not really nice here.
            string linkedResourceUrl = entryResourceAsRequestContext.OriginEndPoint;

            if (!string.Equals(requestEndPointUrl, linkedResourceUrl, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new RequestException("Request url and linked entry resource not matching.");
            }

            string resourceKindName = _requestContext.ResourceKind.ToString();

            localId = entryResourceAsRequestContext.ResourceKey;



            // The correlation store
            ICorrelatedResSyncInfoStore correlatedResSyncInfoStore = NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);


            // update the correlation entry in the sync store.
            // if uuid is not in use -> throw exception
            // if resource is already linked -> remove existing link, reassign link
            // if resource is not yet linked -> reassign link
            CorrelatedResSyncInfo[] correlations;
            CorrelatedResSyncInfo   correlationToModify = null;

            // retrieve the correlation we want to reassign by given uuid
            correlations = correlatedResSyncInfoStore.GetByUuid(resourceKindName, new Guid[] { uuid });
            if (correlations.Length > 0)
            {
                correlationToModify = correlations[0];
            }
            else
            {
                throw new RequestException("Uuid not in use");
            }

            //remember the old Correlation for the new localId, will be deleted after the update.
            CorrelatedResSyncInfo[] oldCorrelations = correlatedResSyncInfoStore.GetByLocalId(resourceKindName, new string[] { localId });

            // change the local ID to link to the new resource.
            // change the modification stamp and reset the tick
            correlationToModify.LocalId = localId;
            correlationToModify.ResSyncInfo.ModifiedStamp = DateTime.Now;
            correlationToModify.ResSyncInfo.Tick          = 1;

            // update the correlation
            correlatedResSyncInfoStore.Update(resourceKindName, correlationToModify);

            //If updating went OK, delete the old correlation for the new localId (should be only 1, for-loop just to be sure to catch em all)
            foreach (CorrelatedResSyncInfo oldCorrelation in oldCorrelations)
            {
                correlatedResSyncInfoStore.Delete(resourceKindName, oldCorrelation.ResSyncInfo.Uuid);
            }

            // If the service consumer only needs to retrieve the URL, not the actual payload,
            // it may do so by adding an empty select parameter to its request:
            // a) select parameter not exist -> return deep resource payload
            // b) select exists and empty -> return no resource payload
            // c) select exists and not empty -> return deep resource payload as we do not yet support payload filtering
            //    with select parameter.
            string tmpValue;
            // ?select
            bool includeResourcePayloads = true;    // default value, but check for select parameter now

            if (_requestContext.SdataUri.QueryArgs.TryGetValue("select", out tmpValue))
            {
                if (string.IsNullOrEmpty(_requestContext.SdataUri.QueryArgs["select"]))
                {
                    includeResourcePayloads = false;
                }
            }


            // Create an entity wrapper if resource data should be requested. Otherwise
            // leave wrapper null.
            IFeedEntryEntityWrapper wrapper = null;

            //if (includeResourcePayloads) //TODO: Comment this in as soon as there is a possibility to send empty payload objects
            wrapper = FeedEntryWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            /* Create the response entry */
            _request.Response.FeedEntry   = (FeedEntry)this.BuildFeedEntryForCorrelation(correlationToModify, wrapper);
            _request.Response.ContentType = MediaType.AtomEntry;
        }