Наследование: Sage.Common.Syndication.IFeed
        public void DoWork(IRequest request)
        {
            string resourceKind = _requestContext.ResourceKind.ToString();
            string endpoint = _requestContext.DatasetLink + resourceKind;
            SdataContext sdataContext = _requestContext.SdataContext;

            ISyncSyncDigestInfoStore syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);

            SyncDigestInfo syncDigestInfo = syncDigestStore.Get(resourceKind);

            SyncDigestPayload syncDigestPayload = new SyncDigestPayload();
            syncDigestPayload.Digest.Origin = endpoint;
            // create a new initial syncDigest and store it.
            if ((null == syncDigestInfo) || (syncDigestInfo.Count == 0))
            {
                SyncFeedDigestEntry entry = new SyncFeedDigestEntry();
                entry.ConflictPriority = 0;
                entry.Endpoint = endpoint;
                entry.Stamp = DateTime.Now;
                entry.Tick = -1;
                syncDigestPayload.Digest.Entries.Add(entry);
            }
            else
            {
                foreach (SyncDigestEntryInfo digestEntry in syncDigestInfo)
                {
                    SyncFeedDigestEntry entry = new SyncFeedDigestEntry();
                    entry.ConflictPriority = digestEntry.ConflictPriority;
                    entry.Endpoint = digestEntry.Endpoint;
                    //entry.Stamp = digestEntry.;
                    entry.Tick = digestEntry.Tick;
                    syncDigestPayload.Digest.Entries.Add(entry);

                }

            }
            SyncFeed feed = new SyncFeed();
            string url = endpoint + "/$syncDigest";
            FeedLink link = new FeedLink(url, LinkType.Self, MediaType.AtomEntry);
            feed.Links = new FeedLinkCollection();
            feed.Links.Add(link);
            feed.Id = url;
            feed.FeedType = FeedType.ResourceEntry;
            SyncFeedEntry syncFeedEntry = new SyncFeedEntry();
            syncFeedEntry.Payload = syncDigestPayload;
            syncFeedEntry.Title = "Synchronization digest";
            syncFeedEntry.Id = url;

            syncFeedEntry.Links.Add(link);
            feed.Entries.Add(syncFeedEntry);

            feed.Id = url;

            request.Response.Serializer = new SyncFeedSerializer();
            request.Response.Feed = feed;
            request.Response.ContentType = MediaType.AtomEntry;
        }
        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");

            // Parse the resource url 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.

            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();
            string localId = entryResourceAsRequestContext.SdataUri.CollectionPredicate;
            Guid uuid = entry.Linked.Uuid;

            // store a new correlation entry to the sync store
            ICorrelatedResSyncInfoStore correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);

            ResSyncInfo newResSyncInfo = new ResSyncInfo(uuid, requestEndpointUrl, 0, string.Empty, DateTime.Now);
            CorrelatedResSyncInfo newInfo = new CorrelatedResSyncInfo(localId, newResSyncInfo);
            correlatedResSyncInfoStore.Add(resourceKindName, newInfo);

            // Set the response values
            SyncFeed feed = new SyncFeed();
            feed.FeedType = FeedType.LinkedSingle;

            SyncFeedEntry feedEntry = new SyncFeedEntry();
            feedEntry.Title = FeedMetadataHelpers.BuildLinkedEntryTitle(_requestContext, uuid);
            feedEntry.Id = FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, uuid);
            feedEntry.Updated = newInfo.ResSyncInfo.ModifiedStamp;
            feedEntry.Published = newInfo.ResSyncInfo.ModifiedStamp;
            feedEntry.Linked = entry.Linked;

            feed.Entries.Add(feedEntry);

            request.Response.Serializer = new SyncFeedSerializer();
            request.Response.Feed = (IFeed)feed;
            request.Response.ContentType = MediaType.AtomEntry;

            request.Response.StatusCode = System.Net.HttpStatusCode.Created;
            request.Response.Protocol.SendUnknownResponseHeader("location", FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, uuid));
        }
        public void DoWork(IRequest request)
        {
            if (request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
                throw new RequestException("Atom entry content type expected");

            if (!String.IsNullOrEmpty(_requestContext.ResourceKey))
                throw new RequestException("Please use resource url");

            // read entry from stream
            SyncFeedEntry entry = new SyncFeedEntry();
            XmlReader reader = XmlReader.Create(request.Stream);
            reader.MoveToContent();

            entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            Document document = wrapper.GetTransformedDocument(entry.Payload, entry.SyncLinks);
            if (!String.IsNullOrEmpty(document.Id))
                throw new RequestException("Entity alredy exists");

            // Add Document

            SdataTransactionResult sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks );

            if (sdTrResult == null)
                throw new RequestException("Entity does not exists"); //?????

            if ((sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK) ||
                (sdTrResult.HttpStatus == System.Net.HttpStatusCode.Created))
            {

                // store correlation
                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(sdTrResult.LocalId);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.StatusCode = System.Net.HttpStatusCode.Created;
                request.Response.Serializer = new SyncFeedSerializer();
                request.Response.Feed = feed;
                request.Response.Protocol.SendUnknownResponseHeader("Location", responseEntry.Id);
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
            }
            else
            {

                throw new RequestException(sdTrResult.HttpMessage);
            }
        }
        public void DoWork(IRequest request)
        {
            // If an asyncState object already exists, an exception is thrown as the performer only accepts
            // one call after each other. The Request receiver has to manage a queued execution.

            // Before calling the performers execution implementation method a new AsyncState object is created
            // and set to an initial tracking state.

            lock (_asyncStateObj)
            {
                if (null != _asyncStateObj.Tracking)
                    throw new InvalidOperationException("The performer cannot be executed because it is already running.");

                SyncTracking tracking = new SyncTracking();
                tracking.ElapsedSeconds = 1;
                tracking.Phase = TrackingPhase.INIT;
                tracking.PhaseDetail = "Tracking Id was: " + _requestContext.TrackingId.ToString();
                tracking.PollingMillis = 100;
                tracking.RemainingSeconds = 100;

                _asyncStateObj.Tracking = tracking;
            }

            // *** Initialization for the async execution ***
            // - Read Feed from request stream.
            // - Read trackingId from request URL

            // convert tracking ID from request to type Guid
            string strTrackingId = request.Uri.TrackingID;
            if (String.IsNullOrEmpty(strTrackingId))
                throw new RequestException("TrackingId is missing");

            GuidConverter converter = new GuidConverter();
            this.TrackingId = (Guid)converter.ConvertFrom(strTrackingId);

            //read feed
            SyncFeed feed = new SyncFeed();
            XmlReader reader = XmlReader.Create(request.Stream);
            feed.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            // *** Do work asynchronously ***
            _asyncPerformer = new InternalAsyncPerformer(this);
            _asyncPerformer.DoWork(_requestContext.Config, feed);

            // *** set the tracking to the request response ***
            this.GetTrackingState(request);
        }
        public void DoWork(IRequest request)
        {
            if (request.ContentType != Sage.Common.Syndication.MediaType.Atom)
                throw new RequestException("Atom content type expected");

            //read feed
            string resourceKindName = _requestContext.ResourceKind.ToString();
            SyncFeed feed = new SyncFeed();
            XmlReader reader = XmlReader.Create(request.Stream);
            feed.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            /* iterate through all entries and store result information */
            ISyncResultInfoStore syncResultInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncResultStore(_requestContext.SdataContext);

            int noOfEntries = feed.Entries.Count;
            string endpoint = string.Empty;
            try
            {
                endpoint = new RequestContext(new Sage.Common.Syndication.SDataUri(feed.Id)).OriginEndPoint;
            }
            catch { }

            SyncResultEntryInfo[] syncResultEntries = new SyncResultEntryInfo[noOfEntries];
            for (int i = 0; i < noOfEntries; i++)
            {
                SyncFeedEntry entry = (SyncFeedEntry)feed.Entries[i];
                string httpMethod = entry.HttpMethod;
                int httpStatus = -1;
                if (Enum.IsDefined(typeof(HttpStatusCode), entry.HttpStatusCode.ToString()))
                    httpStatus = (int)Enum.Parse(typeof(HttpStatusCode), entry.HttpStatusCode.ToString(), true);
                string httpLocation = entry.HttpLocation;
                string httpMessage = entry.HttpMessage;
                string diagnosisXml = XmlSerializationHelpers.SerializeObjectToXml(entry.Diagnoses);
                string payloadXml = XmlSerializationHelpers.SerializeObjectToXml(entry.Payload);

                syncResultEntries[i] = new SyncResultEntryInfo(httpMethod, httpStatus, httpLocation, httpMessage, diagnosisXml, payloadXml, DateTime.Now, endpoint);
            }

            syncResultInfoStore.Add(resourceKindName, syncResultEntries);
        }
            // Asynchronous called method
            private void Execute(NorthwindConfig config, SyncFeed feed)
            {
                #region Declarations

                SdataContext sdataContext;
                SupportedResourceKinds resource;
                IAppBookmarkInfoStore appBookmarkInfoStore;
                ICorrelatedResSyncInfoStore correlatedResSyncInfoStore;
                ISyncSyncDigestInfoStore syncDigestStore;

                GuidConverter guidConverter = new GuidConverter();
                string resourceKind;
                string endpoint;
                SyncFeedDigest sourceDigest;
                SyncDigestInfo targetDigest;

                IEntityWrapper wrapper;

                #endregion

                #region init

                sdataContext = _parentPerformer._requestContext.SdataContext;
                resource = _parentPerformer._requestContext.ResourceKind;
                resourceKind = resource.ToString();
                endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind;
                appBookmarkInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext);
                correlatedResSyncInfoStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext);
                syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                sourceDigest = feed.Digest;
                targetDigest = syncDigestStore.Get(resourceKind);
                wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);

                #endregion

                #region process entries

                bool sourceIsDeleteMode;
                SdataTransactionResult sdTrResult;
                SyncState sourceState;
                SyncState targetState;

                foreach (SyncFeedEntry entry in feed.Entries)
                {
                    sdTrResult = null;

                    try
                    {
                        // Check whether the source entry had been deleted.
                        // if not we expect a payload!
                        // The variable 'sourceIsDeleteMode' holds the result of this check for later calls.
                        if (entry.HttpMethod.Equals("DELETE", StringComparison.InvariantCultureIgnoreCase))
                            sourceIsDeleteMode = true;
                        else if (null == entry.Payload)
                            throw new Exception("Payload missing.");
                        else
                            sourceIsDeleteMode = false;

                        // set the uuid to the payload.SyncUuid property
                        if (!sourceIsDeleteMode) { entry.Payload.SyncUuid = entry.Uuid; }

                        // get the source syncstate
                        sourceState = entry.SyncState;

                        // Look into the store to get all correlations of the uuid received from source
                        CorrelatedResSyncInfo[] corelations = correlatedResSyncInfoStore.GetByUuid(resourceKind, new Guid[] { entry.Uuid });

                        if (corelations.Length == 0)
                        {
                            if (sourceIsDeleteMode)
                            {
                                // the source entry had been deleted and no correlation exists for this
                                // entry in the target.
                                // So we do nothing here.
                                sdTrResult = new SdataTransactionResult();
                                sdTrResult.HttpStatus = HttpStatusCode.OK;
                                sdTrResult.HttpMessage = "OK";
                                sdTrResult.HttpMethod = "DELETE";
                                sdTrResult.ResourceKind = resource;
                                sdTrResult.Uuid = entry.Uuid;
                            }
                            else
                            {
                                // no target entry exists for the updated or added source entry.
                                // So we add the source entry to the application and add a new correlation to the sync store.
                                // If this operation fails we will have to set the result state to conflict.
                                try
                                {
                                    // add the entry to application
                                    sdTrResult = wrapper.Add(entry.Payload, entry.SyncLinks);

                                    if ((sdTrResult != null) && ((sdTrResult.HttpStatus == HttpStatusCode.OK) || (sdTrResult.HttpStatus == HttpStatusCode.Created)))
                                    {
                                        string etag = EtagServices.ComputeEtag(entry.Payload, true);

                                        ResSyncInfo resSyncInfo =
                                            new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                entry.SyncState.Tick, etag, entry.SyncState.Stamp);

                                        CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo);

                                        // store the new correlation to the sync store
                                        correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo);
                                        // update the sync digest entry if the tick of the source entry is newer than the actual tick of the target.
                                        syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfo.ResSyncInfo);
                                    }
                                }
                                catch (Exception e)
                                {
                                    // in case of an unexpected error while adding a new entry to target
                                    // we create a transaction result with the state 'Conflict'
                                    sdTrResult = new SdataTransactionResult();
                                    sdTrResult.HttpStatus = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMethod = "POST";
                                    sdTrResult.HttpMessage = e.ToString();
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid = entry.Uuid;
                                }
                            }
                        }
                        else
                        {
                            // a correlation was found for the source entry.

                            #region update or delete

                            try
                            {
                                bool doUpdate = false;
                                //bool doDelete = false;
                                bool isConflict = true;

                                // set the LocalID from correlation to the entry.Payload.LocalID property
                                // only if source had not been deleted.
                                if (!sourceIsDeleteMode) { entry.Payload.LocalID = corelations[0].LocalId; }

                                targetState = Helper.GetSyncState( corelations[0]);

                                //If sourceState.endpoint = targetState.endpoint,
                                //there is no conflict and the update must be applied
                                //if sourceState.tick > targetState.tick.
                                if (targetState.Endpoint.Equals(sourceState.Endpoint, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    isConflict = false;
                                    if (sourceState.Tick > targetState.Tick)
                                    {
                                        //if (!sourceIsDeleteMode)
                                            doUpdate = true;
                                        //else
                                        //    doDelete = true;
                                    }
                                }
                                else
                                {
                                    SyncState sourceDigestSyncState = Helper.GetSyncState(sourceDigest, targetState.Endpoint); ;
                                    SyncState targetDigestSyncState = Helper.GetSyncState(targetDigest, sourceState.Endpoint);

                                    //If targetState is contained in sourceDigest,
                                    //i.e. if sourceDigest has a digest entry E such that E.endpoint = targetState.endpoint
                                    //and E.tick >= targetState.tick, there is no conflict and the update must be applied.
                                    if (sourceDigestSyncState != null)
                                    {
                                        if (sourceDigestSyncState.Tick > targetState.Tick)
                                        {
                                            doUpdate = true;
                                            isConflict = false;
                                        }
                                    }

                                    //If sourceState is contained in targetDigest,
                                    //i.e. if targetDigest has a digest entry E such that E.endpoint = sourceState.endpoint
                                    //and E.tick >= sourceState.tick, there is no conflict and the update must be ignored
                                    //(target has the most recent version).
                                    if (targetDigestSyncState != null)
                                    {
                                        if (targetDigestSyncState.Tick > sourceState.Tick)
                                        {
                                            doUpdate = false;
                                            isConflict = false;
                                        }
                                    }

                                    //Otherwise (targetState not contained in sourceDigest, sourceState not contained in targetDigest),
                                    //there is a conflict.
                                    if ((sourceDigestSyncState == null) && (targetDigestSyncState == null))
                                        isConflict = true;
                                }

                                //****************** Conflict ****************
                                //In case of conflict, the target endpoint uses the following algorithm to resolve the conflict:
                               //Let sourceEntry be the sourceDigest digest entry such that sourceEntry.endpoint = sourceState.endpoint.
                                //Let targetEntry be the targetDigest digest entry such that targetEntry.endpoint = targetState.endpoint.
                                //If sourceEntry .conflictPriority <> targetEntry .conflictPriority, the side with lowest priority wins.
                                if(isConflict)
                                {
                                    int sourceConflictPriority = Helper.GetConflictPriority(sourceDigest, sourceState.Endpoint);
                                    int targetConflictPriority = Helper.GetConflictPriority(targetDigest, targetState.Endpoint);

                                    if (sourceConflictPriority > targetConflictPriority)
                                    {
                                        doUpdate = true;
                                    }
                                    else if (sourceConflictPriority < targetConflictPriority)
                                    {
                                        doUpdate = false;
                                    }
                                    else
                                    {
                                        //Otherwise (sourceEntry .conflictPriority = targetEntry .conflictPriority),
                                        //then sourceState.stamp and targetState.stamp are compared
                                        //and the entry with the most recent timestamp wins.
                                        if (sourceState.Stamp > targetState.Stamp)
                                        {
                                            doUpdate = true;
                                        }
                                    }

                                }
                                ResSyncInfo resSyncInfo =
                                            new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                entry.SyncState.Tick, "", entry.SyncState.Stamp);

                                if (doUpdate && !sourceIsDeleteMode)
                                {
                                    // update the entry in the application and update the sync store
                                    sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks);

                                    if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK))
                                    {
                                        string etag = EtagServices.ComputeEtag(entry.Payload, true);

                                        resSyncInfo =
                                            new ResSyncInfo(entry.Uuid, entry.SyncState.Endpoint,
                                                entry.SyncState.Tick, etag, entry.SyncState.Stamp);

                                        CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(sdTrResult.LocalId, resSyncInfo);

                                        correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfo);
                                    }
                                }
                                else if (!doUpdate && !sourceIsDeleteMode)
                                {
                                    sdTrResult = new SdataTransactionResult();
                                    sdTrResult.HttpStatus = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMethod = "PUT";
                                    sdTrResult.HttpMessage = "";
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid = entry.Uuid;
                                }
                                else if (doUpdate && sourceIsDeleteMode)
                                {
                                    // delete the entry in the application and update the sync store
                                    // we do not support nested deletion. So only TradingAccounts and SalesOrders can be deleted.
                                    if (resource == SupportedResourceKinds.tradingAccounts
                                        || resource == SupportedResourceKinds.salesOrders)
                                    {
                                        sdTrResult = wrapper.Delete(corelations[0].LocalId);

                                        if ((sdTrResult != null) && (sdTrResult.HttpStatus == HttpStatusCode.OK))
                                        {
                                            correlatedResSyncInfoStore.Delete(resource.ToString(), corelations[0].ResSyncInfo.Uuid);
                                        }
                                    }
                                    else
                                    {
                                        // this  does not correspond to real fact, what we did at target side!
                                        sdTrResult = new SdataTransactionResult();
                                        sdTrResult.HttpStatus = HttpStatusCode.OK;
                                        sdTrResult.HttpMessage = "OK";
                                        sdTrResult.HttpMethod = "DELETE";
                                        sdTrResult.ResourceKind = resource;
                                        sdTrResult.Uuid = entry.Uuid;
                                    }
                                }
                                else
                                {
                                    sdTrResult = new SdataTransactionResult();
                                    sdTrResult.HttpStatus = HttpStatusCode.Conflict;
                                    sdTrResult.HttpMessage = "";
                                    sdTrResult.HttpMethod = "DELETE";
                                    sdTrResult.ResourceKind = resource;
                                    sdTrResult.Uuid = entry.Uuid;
                                }

                                syncDigestStore.PersistNewer(resourceKind, resSyncInfo);

                            }
                            catch (Exception e)
                            {
                                sdTrResult = new SdataTransactionResult();
                                sdTrResult.HttpStatus = HttpStatusCode.Conflict;
                                sdTrResult.HttpMethod = "PUT";
                                sdTrResult.HttpMessage = e.ToString();
                                sdTrResult.ResourceKind = resource;
                                sdTrResult.Uuid = entry.Uuid;
                            }
                            #endregion
                        }
                    }
                    catch (Exception e)
                    {
                        sdTrResult = new SdataTransactionResult();
                        sdTrResult.HttpStatus = HttpStatusCode.Conflict;
                        sdTrResult.HttpMessage = e.ToString();
                        sdTrResult.ResourceKind = resource;
                        sdTrResult.Uuid = entry.Uuid;
                    }

                    #region store transaction result

                    if (sdTrResult != null)
                    {
                        lock (_parentPerformer._asyncStateObj)
                        {
                            this._parentPerformer._asyncStateObj.TransactionResults.Add(sdTrResult);
                        }
                    }

                    #endregion

                }
                #endregion

                // Set tracking phase
                lock (_parentPerformer._asyncStateObj.Tracking)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH;
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="config"></param>
            /// <returns></returns>
            /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks>
            public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count)
            {
                SyncFeed feed;
                SdataContext sdataContext;
                SupportedResourceKinds resource;
                string resourceKind;
                string endpoint;
                Guid trackingId;

                List<SdataTransactionResult> transactinResults;

                sdataContext = _parentPerformer._requestContext.SdataContext;
                resource = _parentPerformer._requestContext.ResourceKind;
                resourceKind = resource.ToString();
                transactinResults = _parentPerformer._asyncStateObj.TransactionResults;
                endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind; ;
                trackingId = _parentPerformer._requestContext.TrackingId;

                if (count == 0)
                    count = 10;

                feed = new SyncFeed();
                Token emptyToken = new Token();

                IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);

                for (int index = startIndex;
                index < ((startIndex + count > transactinResults.Count) ? transactinResults.Count : startIndex + count);
                index++)
                {
                    SdataTransactionResult transactionResult = (SdataTransactionResult)transactinResults[index];

                    SyncFeedEntry entry = wrapper.GetFeedEntry(transactionResult);

                    if (entry != null)
                        feed.Entries.Add(entry);
                    else
                    {
                        entry = new SyncFeedEntry();
                        entry.Uuid = transactionResult.Uuid;
                        entry.HttpStatusCode = transactionResult.HttpStatus;
                        entry.HttpMessage = transactionResult.HttpMessage; ;
                        entry.HttpMethod = transactionResult.HttpMethod;
                        entry.HttpLocation = transactionResult.Location;
                        entry.HttpETag = transactionResult.Etag;
                        feed.Entries.Add(entry);
                    }
                }

                // initialize the feed
                string url = string.Format("{0}/$syncTarget('{1}')", endpoint, trackingId);

                feed.Title = resourceKind;
                feed.Id = url;

                #region PAGING & OPENSEARCH

                int totalResults = transactinResults.Count;

                PageController pageController = new PageController(startIndex+1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url);

                /* PAGING */
                FeedLinkCollection feedLinks = new FeedLinkCollection();
                feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page"));

                string linkUrl;
                if (pageController.GetLinkNext(out linkUrl))
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page"));
                if (pageController.GetLinkPrevious(out linkUrl))
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page"));

                feed.Links = feedLinks;

                /* OPENSEARCH */
                feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement();
                feed.Opensearch_StartIndexElement = pageController.GetOpensearch_StartIndexElement();
                feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement();

                #endregion

                //if (startIndex + count < transactinResults.Count)
                //{
                //    FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next);
                //    feed.Links.Add(linkNext);
                //}

                //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First);
                //feed.Links.Add(linkFirst);

                //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self);
                //feed.Links.Add(linkSelf);

                return feed;
            }
            public void DoWork(NorthwindConfig config, SyncFeed feed)
            {
                ExecuteDelegate worker = new ExecuteDelegate(Execute);
                AsyncCallback completedCallback = new AsyncCallback(ExecuteCompletedCallback);

                AsyncOperation async = AsyncOperationManager.CreateOperation(null);

                // Begin asynchronous method call
                worker.BeginInvoke(config, feed, completedCallback, async);
            }
        public override SyncFeed GetFeed()
        {
            bool includeUuid;

            string whereClause = string.Empty;
            OleDbParameter[] oleDbParameters = null;

            if (this is IEntityQueryWrapper)
            {
                QueryFilterBuilder queryFilterBuilder = new QueryFilterBuilder((IEntityQueryWrapper)this);

                queryFilterBuilder.BuildSqlStatement(_context, out whereClause, out oleDbParameters);
            }

            SyncFeed feed = new SyncFeed();

            feed.Title = _resourceKind.ToString() + ": " + DateTime.Now.ToString();

            Token emptyToken = new Token();

            List<Identity> identities = new List<Identity>();

            if (String.IsNullOrEmpty(_context.ResourceKey))
                identities = _entity.GetAll(_context.Config, whereClause, oleDbParameters);
            else
                identities.Add(new Identity(_entity.EntityName, _context.ResourceKey));

            int totalResult = identities.Count;

            #region PAGING & OPENSEARCH

            /* PAGING */
            feed.Links = FeedMetadataHelpers.CreatePageFeedLinks(_context, totalResult, FeedMetadataHelpers.RequestKeywordType.none);

            /* OPENSEARCH */
            PageController pageController = FeedMetadataHelpers.GetPageLinkBuilder(_context, totalResult, FeedMetadataHelpers.RequestKeywordType.none);

            feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement();
            feed.Opensearch_StartIndexElement = pageController.GetOpensearch_StartIndexElement();
            feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement();

            #endregion

            feed.Id = _context.SdataUri.ToString();

            string tmpValue;
            // ?includeUuid
            includeUuid = false;    // default value, but check for settings now
            if (_context.SdataUri.QueryArgs.TryGetValue("includeUuid", out tmpValue))
                includeUuid = System.Xml.XmlConvert.ToBoolean(tmpValue);

            ICorrelatedResSyncInfoStore correlatedResSyncStore = null;
            if (includeUuid)
                // get store to request the correlations
                correlatedResSyncStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_context.SdataContext);

            for (int pageIndex = pageController.StartIndex; pageIndex <= pageController.LastIndex; pageIndex++)
            //for (int index = startIndex; index < startIndex + count; index++)
            {
                int zeroBasedIndex = pageIndex - 1;
                Identity identity = identities[zeroBasedIndex];
                AccountDocument accountDocument = (AccountDocument)_entity.GetDocument(identity, emptyToken, _context.Config);
                if (accountDocument.LogState == LogState.Deleted)
                    continue;

                SyncFeedEntry entry = new SyncFeedEntry();
                if (accountDocument.addresses.documents.Count == 0)
                    return null;

                entry.Id = String.Format("{0}{1}('{2}')", _context.DatasetLink, _resourceKind.ToString(), identity.Id);

                entry.Title = String.Format("{0}: {1}", _resourceKind.ToString(), identity.Id);
                entry.Updated = DateTime.Now;

                if (_context.SdataUri.Precedence == null)
                {
                    List<SyncFeedEntryLink> links;
                    Document document = accountDocument.addresses.documents[0];
                    entry.Payload = GetTransformedPayload(document, out links);
                    string taUuid = GetTradingAccountUuid(accountDocument.Id);
                    if (!String.IsNullOrEmpty(taUuid))
                    {
                        SyncFeedEntryLink tradingAccountLink = SyncFeedEntryLink.CreateRelatedLink(
                            String.Format("{0}{1}('{2}')", _context.DatasetLink, SupportedResourceKinds.tradingAccounts.ToString(), accountDocument.Id),
                            SupportedResourceKinds.tradingAccounts.ToString(),
                             _tradingAccountUuidPayloadPath, taUuid);
                        links.Add(tradingAccountLink);

                    }

                    entry.SyncLinks = links;
                }

                if (includeUuid)
                {
                    CorrelatedResSyncInfo[] infos = correlatedResSyncStore.GetByLocalId(_context.ResourceKind.ToString(), new string[] { identity.Id });
                    entry.Uuid = (infos.Length > 0) ? infos[0].ResSyncInfo.Uuid : Guid.Empty;
                }

                if (entry != null)
                    feed.Entries.Add(entry);
            }

            return feed;
        }
        public void DoWork(IRequest request)
        {
            if (request.ContentType!= Sage.Common.Syndication.MediaType.AtomEntry)
                throw new RequestException("Atom entry content type expected");

            if (String.IsNullOrEmpty(_requestContext.ResourceKey))
                throw new RequestException("Please use single resource url");
            //SupportedResourceKinds resKind = _requestContext.ResourceKind;
            //switch (resKind)
            //{
            //    case SupportedResourceKinds.tradingAccounts:
            //    case SupportedResourceKinds.contacts:
            //    case SupportedResourceKinds.phoneNumbers:
            //    case SupportedResourceKinds.postalAddresses:
            //        break;
            //    default:
            //        throw new RequestException("Put is not Supported for requested resource");
            //}

            // read entry from stream
            SyncFeedEntry entry = new SyncFeedEntry();
            XmlReader reader = XmlReader.Create(request.Stream);
            reader.MoveToContent();

            entry.ReadXml(reader, ResourceKindHelpers.GetPayloadType(_requestContext.ResourceKind));

            IEntityWrapper wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            Token emptyToken = new Token();
            Identity identity = wrapper.GetIdentity(_requestContext.ResourceKey);

            Document originalDocument = wrapper.Entity.GetDocument(identity, emptyToken, _requestContext.Config);

            if (originalDocument.LogState == LogState.Deleted)
                throw new RequestException("Entity does not exists");

            entry.Payload.LocalID = _requestContext.ResourceKey;
            SdataTransactionResult sdTrResult = wrapper.Update(entry.Payload, entry.SyncLinks);

            if (sdTrResult == null)
            {

                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.Serializer = new SyncFeedSerializer();
                request.Response.Feed = feed;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;

            }
            else if (sdTrResult.HttpStatus == System.Net.HttpStatusCode.OK)
            {
                SyncFeedEntry responseEntry = wrapper.GetFeedEntry(_requestContext.ResourceKey);

                SyncFeed feed = new SyncFeed();
                feed.FeedType = FeedType.ResourceEntry;
                feed.Entries.Add(responseEntry);
                request.Response.Serializer = new SyncFeedSerializer();
                request.Response.Feed = feed;
                request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;

            }
            else
            {

                throw new RequestException(sdTrResult.HttpMessage);
            }
        }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="config"></param>
            /// <returns></returns>
            /// <remarks>This method is not threadsafe as the performer must be finished when calling this method.</remarks>
            public SyncFeed GetFeed(NorthwindConfig config, int startIndex, int count)
            {
                SyncFeed feed;
                SdataContext sdataContext;
                SupportedResourceKinds resource;
                string resourceKind;
                string endpoint;
                Guid trackingId;

                List<CorrelatedResSyncInfo> correlatedResSyncInfos;

                sdataContext = _parentPerformer._requestContext.SdataContext;
                resource = _parentPerformer._requestContext.ResourceKind;
                resourceKind = resource.ToString();
                correlatedResSyncInfos = _parentPerformer._asyncStateObj.CorrelatedResSyncInfos;
                endpoint = _parentPerformer._requestContext.DatasetLink + resourceKind;
                trackingId = _parentPerformer._requestContext.TrackingId;

                ISyncSyncDigestInfoStore syncDigestStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                SyncDigestInfo syncDigestInfo = syncDigestStore.Get(resourceKind);

                if (count == 0)
                    count = 10;

                feed = new SyncFeed();
                Token emptyToken = new Token();

                feed.Digest = new SyncFeedDigest();
                feed.Digest.Origin = _parentPerformer._requestContext.OriginEndPoint;
                feed.Digest.Entries = new List<SyncFeedDigestEntry>();

                if (syncDigestInfo != null)
                {
                    foreach (SyncDigestEntryInfo entryinfo in syncDigestInfo)
                    {
                        SyncFeedDigestEntry entry = new SyncFeedDigestEntry();
                        entry.ConflictPriority = entryinfo.ConflictPriority;
                        entry.Endpoint = entryinfo.Endpoint;
                        entry.Tick = entryinfo.Tick;
                        entry.Stamp = DateTime.Now;
                        feed.Digest.Entries.Add(entry);
                    }
                }

                IEntityWrapper wrapper = EntityWrapperFactory.Create(resource, _parentPerformer._requestContext);

                for (int index = startIndex;
                index < ((startIndex + count > correlatedResSyncInfos.Count) ? correlatedResSyncInfos.Count : startIndex + count);
                index++)
                {
                    CorrelatedResSyncInfo resSyncInfo = (CorrelatedResSyncInfo)correlatedResSyncInfos[index];
                    SyncFeedEntry entry = wrapper.GetFeedEntry(resSyncInfo);
                    if (entry != null)
                        feed.Entries.Add(entry);
                    else
                    {
                        entry = new SyncFeedEntry();
                        entry.HttpMethod = "DELETE";
                        entry.Uuid = resSyncInfo.ResSyncInfo.Uuid;
                        feed.Entries.Add(entry);
                    }

                }

                // initialize the feed
                string url = string.Format("{0}/$syncSource('{1}')", endpoint, trackingId);

                feed.Id = url;
                feed.Title = resourceKind;

                #region PAGING & OPENSEARCH

                int totalResults = correlatedResSyncInfos.Count;

                PageController pageController = new PageController(startIndex+1, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, totalResults, count, url);

                /* PAGING */
                FeedLinkCollection feedLinks = new FeedLinkCollection();
                feedLinks.Add(new FeedLink(pageController.GetLinkSelf(), LinkType.Self, MediaType.Atom, "Current Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkFirst(), LinkType.First, MediaType.Atom, "First Page"));
                feedLinks.Add(new FeedLink(pageController.GetLinkLast(), LinkType.Last, MediaType.Atom, "Last Page"));

                string linkUrl;
                if (pageController.GetLinkNext(out linkUrl))
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Next, MediaType.Atom, "Next Page"));
                if (pageController.GetLinkPrevious(out linkUrl))
                    feedLinks.Add(new FeedLink(linkUrl, LinkType.Previous, MediaType.Atom, "Previous Page"));

                feed.Links = feedLinks;

                /* OPENSEARCH */
                feed.Opensearch_ItemsPerPageElement = pageController.GetOpensearch_ItemsPerPageElement();
                feed.Opensearch_StartIndexElement = pageController.GetOpensearch_StartIndexElement();
                feed.Opensearch_TotalResultsElement = pageController.GetOpensearch_TotalResultsElement();

                #endregion

                //feed.Id = url;
                //if (startIndex + count < correlatedResSyncInfos.Count)
                //{
                //    FeedLink linkNext = new FeedLink(string.Format("{0}?startIndex={1}&count=10", url, startIndex + count), LinkType.Next);
                //    feed.Links.Add(linkNext);
                //}

                //FeedLink linkFirst = new FeedLink(String.Format("{0}?startIndex=0&count=10", url), LinkType.First);
                //feed.Links.Add(linkFirst);

                //FeedLink linkSelf = new FeedLink(String.Format("{0}?startIndex={1}&count=10", url, startIndex), LinkType.Self);
                //feed.Links.Add(linkSelf);

                return feed;
            }
        public void DoWork(IRequest request)
        {
            EntryRequestType entryRequestType;
            string resourceKindName;
            ICorrelatedResSyncInfoStore correlatedResSyncStore;
            bool includeDataPayloads;   //?includePayloads value

            CorrelatedResSyncInfo[] correlatedResSyncInfos;
            int totalResult;

            #region initialization

            // multi or single entry request?
            entryRequestType = (String.IsNullOrEmpty(_requestContext.ResourceKey)) ? EntryRequestType.Multi : EntryRequestType.Single;

            resourceKindName = _requestContext.ResourceKind.ToString();

            string tmpValue;
            // ?includePayloads
            includeDataPayloads = false;    // default value, but check for settings now
            if (_requestContext.SdataUri.QueryArgs.TryGetValue("includePayload", out tmpValue))
                includeDataPayloads = System.Xml.XmlConvert.ToBoolean(tmpValue);

            // get store to request the correlations
            correlatedResSyncStore = RequestReceiver.NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);

            #endregion

            // receive correlated resource synchronization entries
            if (entryRequestType == EntryRequestType.Multi)
            {
                int pageNumber = FeedMetadataHelpers.GetPageNumber(_requestContext);

                correlatedResSyncInfos = correlatedResSyncStore.GetPaged(resourceKindName, pageNumber, FeedMetadataHelpers.DEFAULT_ITEMS_PER_PAGE, out totalResult);
            }
            else
            {
                Guid uuid = (Guid)TypeDescriptor.GetConverter(typeof(Guid)).ConvertFrom(_requestContext.ResourceKey);
                correlatedResSyncInfos = correlatedResSyncStore.GetByUuid(resourceKindName, new Guid[]{uuid});
                totalResult = correlatedResSyncInfos.Length;
            }

            // Create the feed
            SyncFeed feed = new SyncFeed();

            // initialize the feed
            feed.Id = FeedMetadataHelpers.BuildBaseUrl(_requestContext, FeedMetadataHelpers.RequestKeywordType.linked);
            feed.Title = string.Format("{0} Linking Feed", resourceKindName);

            #region PAGING & OPENSEARCH

            /* PAGING */
            feed.Links = FeedMetadataHelpers.CreatePageFeedLinks(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked);

            /* OPENSEARCH */
            PageController pageLinkBuilder = FeedMetadataHelpers.GetPageLinkBuilder(_requestContext, totalResult, FeedMetadataHelpers.RequestKeywordType.linked);

            feed.Opensearch_ItemsPerPageElement = pageLinkBuilder.GetOpensearch_ItemsPerPageElement();
            feed.Opensearch_StartIndexElement = pageLinkBuilder.GetOpensearch_StartIndexElement();
            feed.Opensearch_TotalResultsElement = pageLinkBuilder.GetOpensearch_TotalResultsElement();

            #endregion

            feed.FeedType = (entryRequestType == EntryRequestType.Multi) ? FeedType.Linked : FeedType.LinkedSingle;

            IEntityWrapper wrapper = null;
            if (includeDataPayloads)
                wrapper = EntityWrapperFactory.Create(_requestContext.ResourceKind, _requestContext);

            for (int i=0; i<correlatedResSyncInfos.Length; i++)
            {
                SyncFeedEntry entry = null;

                if (includeDataPayloads)
                {
                    entry = wrapper.GetFeedEntry(correlatedResSyncInfos[i].LocalId);
                }
                else
                {
                    entry = new SyncFeedEntry();
                }

                entry.Id = FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid);
                entry.Title = FeedMetadataHelpers.BuildLinkedEntryTitle(_requestContext, correlatedResSyncInfos[i].ResSyncInfo.Uuid);

                #region LINKED ELEMENT

                LinkedElement linkedElement = new LinkedElement();
                linkedElement.Resource = FeedMetadataHelpers.BuildEntryResourceUrl(_requestContext, correlatedResSyncInfos[i].LocalId);
                linkedElement.Uuid = correlatedResSyncInfos[i].ResSyncInfo.Uuid;
                entry.Linked = linkedElement;

                #endregion

                feed.Entries.Add(entry);
            }

            request.Response.Serializer = new SyncFeedSerializer();
            request.Response.Feed = (IFeed)feed;
            request.Response.ContentType = (entryRequestType == EntryRequestType.Multi) ? MediaType.Atom : MediaType.AtomEntry;
        }
        private void BuildResponseFeed(ref IRequest request, computePriceResponsetype computePriceResponse)
        {
            ComputePriceResponsePayload computePriceResponsePayload = new ComputePriceResponsePayload();

            computePriceResponsePayload.ComputePriceResponse = computePriceResponse;

            SyncFeedEntry entry = new SyncFeedEntry();
            entry.Payload = computePriceResponsePayload;

            entry.Id = _requestContext.SdataUri.Uri.ToString();
            entry.Title = "computePrice";
            entry.Updated = DateTime.Now;

            //entry.Links
            //entry.Categories

            SyncFeed feed = new SyncFeed();
            feed.FeedType = FeedType.ResourceEntry;
            feed.Entries.Add(entry);
            request.Response.Serializer = new SyncFeedSerializer();
            request.Response.Feed = feed;
            request.Response.ContentType = Sage.Common.Syndication.MediaType.AtomEntry;
        }
        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;
        }