Пример #1
0
 public static SyncState GetSyncState(CorrelatedResSyncInfo corelation)
 {
     SyncState result = new SyncState();
     result.Endpoint = corelation.ResSyncInfo.Endpoint;
     result.Stamp = corelation.ResSyncInfo.ModifiedStamp;
     result.Tick = corelation.ResSyncInfo.Tick;
     return result;
 }
        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 Add(string resourceKind, CorrelatedResSyncInfo info)
        {
            if (null == resourceKind)
                throw new ArgumentNullException("resourceKind");
            if (resourceKind == String.Empty)
                throw new ArgumentException("Parameter value is empty.", "resourceKind");

            if (null == info)
                throw new ArgumentNullException("info");

            lock (lockObj)
            {
                _provider.Add(resourceKind, info);
            }
        }
        public void Add(string resourceKind, CorrelatedResSyncInfo info)
        {
            ICorrelatedResSyncTableAdapter correlatedResSyncTableAdapter = this.GetAdapter(resourceKind);

            using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false))
            {
                try
                {
                    correlatedResSyncTableAdapter.Insert(info, jetTransaction);
                }
                catch (OleDbException exception)
                {
                    if (exception.Errors.Count == 1 && exception.Errors[0].SQLState == "3022")
                        throw new StoreException(string.Format("An error occured while adding a new correlated ResSync. A correlated ResSync already exists for the uuid '{0}' and local id '{1}.", info.ResSyncInfo.Uuid, info.LocalId), exception);

                    throw;
                }
                jetTransaction.Commit();
            }
        }
        public void Put(string resourceKind, CorrelatedResSyncInfo info)
        {
            if (null == resourceKind)
                throw new ArgumentNullException("resourceKind");
            if (resourceKind == String.Empty)
                throw new ArgumentException("Parameter value is empty.", "resourceKind");

            if (null == info)
                throw new ArgumentNullException("info");

            // We set the priority on 'update'.
            lock (lockObj)
            {
                try
                {
                    _provider.Update(resourceKind, info);
                }
                catch (StoreException)
                {
                    _provider.Add(resourceKind, info);
                }
            }
        }
        public CorrelatedResSyncInfo[] GetPaged(string resourceKind, int pageNumber, int itemsPerPage, out int totalResult)
        {
            CorrelatedResSyncInfo[] resultInfos;

            ICorrelatedResSyncTableAdapter correlatedResSyncTableAdapter = this.GetAdapter(resourceKind);

            using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false))
            {
                resultInfos = correlatedResSyncTableAdapter.GetAll(jetTransaction);

                jetTransaction.Commit();
            }

            // TODO: TO BE REVIEWED!!!
            totalResult = resultInfos.Length;
            if (totalResult == 0)
                return new CorrelatedResSyncInfo[0];

            int startIndex = ((pageNumber-1) * itemsPerPage) + 1;
            if (totalResult < startIndex)
                return new CorrelatedResSyncInfo[0];

            int realItemsPerPage;
            if ((totalResult - startIndex) > itemsPerPage)
                realItemsPerPage = itemsPerPage;
            else
                realItemsPerPage = totalResult - startIndex;

            CorrelatedResSyncInfo[] destinationArray = new CorrelatedResSyncInfo[realItemsPerPage];

            Array.Copy(resultInfos, startIndex-1, destinationArray, 0, realItemsPerPage);

            return destinationArray;
        }
 internal CorrelatedResSyncInfoEnumerator(CorrelatedResSyncInfo[] infos)
 {
     _infos = infos;
 }
            // Asynchronous called method
            private void Execute(NorthwindConfig config, SyncFeedDigest syncDigestInfo)
            {
                #region Declaration

                SdataContext sdataContext;
                SupportedResourceKinds resource;
                IAppBookmarkInfoStore appBookmarkInfoStore;
                ICorrelatedResSyncInfoStore correlatedResSyncInfoStore;
                ISyncSyncDigestInfoStore syncDigestStore;
                ISyncTickProvider tickProvider;
                string resourceKind;
                string endpoint;
                int nextTick = 0;
                Token lastToken;
                Token nextToken;
                Identity[] changedIdentites;
                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);
                tickProvider = RequestReceiver.NorthwindAdapter.StoreLocator.GetTickProvider(sdataContext);

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

                #endregion

                #region get last token or create a new one

                if (!appBookmarkInfoStore.Get<Token>(resourceKind, out lastToken))
                {
                    lastToken = new Token();
                    lastToken.InitRequest = true;
                }

                #endregion

                #region Get local identities of changed entries since last synchronisation

                changedIdentites = wrapper.Entity.GetLastChanges(lastToken, config, out nextToken);

                #endregion

                if (resource == SupportedResourceKinds.phoneNumbers)
                {
                    #region workaround for phones
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        string phoneid = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.PhoneIdPostfix;
                        string faxId = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.FaxIdPostfix;

                        // receive the feed entry for local identity
                        SyncFeedEntry phoneentry = wrapper.GetFeedEntry(phoneid);
                        SyncFeedEntry faxentry = wrapper.GetFeedEntry(faxId);
                        if (phoneentry == null && faxentry == null)
                            continue;
                        // receive the correlation for the local identity

                        if (phoneentry != null)
                        {
                            CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { phoneid });

                            string etag = EtagServices.ComputeEtag(phoneentry.Payload, true);   // new etag
                            if (correlatedResSyncInfos.Length == 0)
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                                ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(phoneid, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);

                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick;
                                correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }
                        if (faxentry != null)
                        {
                            CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { faxId });

                            string etag = EtagServices.ComputeEtag(faxentry.Payload, true);   // new etag
                            if (correlatedResSyncInfos.Length == 0)
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                                ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(faxId, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);

                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nextTick = tickProvider.CreateNextTick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick;
                                correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }

                    }
                    #endregion
                }
                else
                {
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        string id = changedIdentites[index].Id;
                        // receive the feed entry for local identity
                        SyncFeedEntry entry = wrapper.GetFeedEntry(id);
                        if (entry == null)
                            continue;
                        // receive the correlation for the local identity

                        CorrelatedResSyncInfo[] correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { id });

                        string etag = EtagServices.ComputeEtag(entry.Payload, true);   // new etag
                        if (correlatedResSyncInfos.Length == 0)
                        {
                            nextTick = tickProvider.CreateNextTick(resourceKind); // create next tick

                            ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), endpoint, nextTick, etag, DateTime.Now);
                            CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(id, resyncInfo);

                            correlatedResSyncInfoStore.Put(resourceKind, info);

                            syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);

                        }
                        else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                        {
                            nextTick = tickProvider.CreateNextTick(resourceKind);
                            correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                            correlatedResSyncInfos[0].ResSyncInfo.Tick = nextTick;
                            correlatedResSyncInfos[0].ResSyncInfo.Endpoint = endpoint;
                            correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                            correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                            syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                        }
                    }

                }

                #region store next token

                appBookmarkInfoStore.Put(resourceKind, nextToken);

                #endregion

                // set tracking phase
                lock (_parentPerformer._asyncStateObj)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.GETCHANGESBYTICK;
                }

                // Receive syncDigestInfo
                if (null != syncDigestInfo)
                {
                    ICorrelatedResSyncInfoEnumerator enumerator;
                    List<string> endpoints = new List<string>();

                    foreach (SyncFeedDigestEntry digestEntry in syncDigestInfo.Entries)
                    {
                        endpoints.Add(digestEntry.Endpoint);
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, digestEntry.Tick-2);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }

                    SyncDigestInfo sourceSyncDigestInfo = syncDigestStore.Get(resourceKind);
                    foreach (SyncDigestEntryInfo digestEntry in sourceSyncDigestInfo)
                    {
                        if (endpoints.Contains(digestEntry.Endpoint))
                            continue;
                        endpoints.Add(digestEntry.Endpoint);
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, digestEntry.Endpoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                    if (!endpoints.Contains(endpoint))
                    {
                        enumerator = correlatedResSyncInfoStore.GetSinceTick(resourceKind, endpoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                }

                // Set tracking phase
                lock (_parentPerformer._asyncStateObj.Tracking)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH;
                }
            }
Пример #9
0
        public void Create(FeedEntry entry)
        {
            // only atom entry supported!!!

            if (_request.ContentType != Sage.Common.Syndication.MediaType.AtomEntry)
                throw new RequestException("Atom entry content type expected");

            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

            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;

            ICorrelatedResSyncInfoStore correlatedResSyncInfoStore = NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(_requestContext.SdataContext);

            CheckExisting(correlatedResSyncInfoStore, localId);

            // try to get the new uuid from uuid attribute
            // if this attribute is not set a new one is created
            if (null == entry.UUID || entry.UUID == Guid.Empty)
                uuid = Guid.NewGuid();
            else
                uuid = entry.UUID;

            // store a new correlation entry to the sync store
            ResSyncInfo newResSyncInfo = new ResSyncInfo(uuid, requestEndPointUrl, 0, string.Empty, DateTime.Now);
            CorrelatedResSyncInfo newInfo = new CorrelatedResSyncInfo(localId, newResSyncInfo);
            correlatedResSyncInfoStore.Add(resourceKindName, newInfo);

            // 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(newInfo, wrapper);
            _request.Response.ContentType = MediaType.AtomEntry;

            _request.Response.StatusCode = System.Net.HttpStatusCode.Created;
            _request.Response.Protocol.SendUnknownResponseHeader("location", FeedMetadataHelpers.BuildLinkedEntryUrl(_requestContext, uuid));
        }
Пример #10
0
        protected FeedEntry BuildFeedEntryForCorrelation(CorrelatedResSyncInfo corrResSyncInfo, IFeedEntryEntityWrapper wrapper)
        {
            FeedEntry feedEntry;

            #region Payload

            if (null != wrapper)
            {
                // Get resource data
                feedEntry = wrapper.GetFeedEntry(corrResSyncInfo.LocalId);
            }
            else
            {
                // Create an empty payload container
                feedEntry = new FeedEntry();
                feedEntry.IsDeleted = false;

                feedEntry.Key = corrResSyncInfo.LocalId;
            }
            if (feedEntry != null)
            {
                // modify url and set uuid as we are requesting linked resources here.
                feedEntry.Uri = string.Format("{0}{1}('{2}')", _requestContext.DatasetLink, _requestContext.ResourceKind.ToString() , corrResSyncInfo.LocalId);
                feedEntry.UUID = corrResSyncInfo.ResSyncInfo.Uuid;

            #endregion

                // set id tag
                feedEntry.Id = feedEntry.Uri;

                // set title tag
                feedEntry.Title = string.Format("{0}('{1}') : {2}", _requestContext.ResourceKind.ToString(), corrResSyncInfo.LocalId, corrResSyncInfo.ResSyncInfo.Uuid);
                feedEntry.Updated = corrResSyncInfo.ResSyncInfo.ModifiedStamp.ToLocalTime();

                // set resource dependent  links (self, edit, schema, template, post, service)
                feedEntry.Links.AddRange(LinkFactory.CreateEntryLinks(_requestContext, feedEntry));

            }
            return feedEntry;
        }
Пример #11
0
        public virtual FeedEntry GetSyncSourceFeedEntry(CorrelatedResSyncInfo resSyncInfo)
        {
            FeedEntry result = GetFeedEntry(resSyncInfo.LocalId);
            if (result == null)
                return null;

            result.UUID = resSyncInfo.ResSyncInfo.Uuid;
            result.Key = resSyncInfo.LocalId;

            return result;
        }
Пример #12
0
        private Guid GetUuid(string localId, string uuidString, SupportedResourceKinds resKind)
        {
            if (String.IsNullOrEmpty(localId))
            {
                return Guid.Empty;
            }

            CorrelatedResSyncInfo[] results = _correlatedResSyncInfoStore.GetByLocalId(resKind.ToString(),
                new string[] { localId });
            if (results.Length > 0)
                return results[0].ResSyncInfo.Uuid;
            Guid result;
            if (string.IsNullOrEmpty(uuidString))
                result = Guid.NewGuid();
            else
                try
                {
                    GuidConverter converter = new GuidConverter();
                    result = (Guid)converter.ConvertFromString(uuidString);
                    if (Guid.Empty.Equals(result))
                        result = Guid.NewGuid();
                }
                catch (Exception)
                {
                    result = Guid.NewGuid();
                }

            ResSyncInfo newResSyncInfo = new ResSyncInfo(result, _context.DatasetLink + resKind.ToString(), 0, string.Empty, DateTime.Now);
            CorrelatedResSyncInfo newCorrelation = new CorrelatedResSyncInfo(localId, newResSyncInfo);
            _correlatedResSyncInfoStore.Put(resKind.ToString(), newCorrelation);
            return result;
        }
            private FeedEntry BuildFeedEntry(CorrelatedResSyncInfo correlation, IFeedEntryEntityWrapper wrapper)
            {
                // create a new empty Feed Entry
                //ISyncSourceResourceFeedEntry feedEntry = FeedComponentFactory.Create<ISyncSourceResourceFeedEntry>();
                // get resource payload container from data store
                FeedEntry feedEntry = wrapper.GetSyncSourceFeedEntry(correlation);

                // create and set SyncState
                feedEntry.SyncState = new SyncState();
                feedEntry.SyncState.EndPoint = correlation.ResSyncInfo.EndPoint;
                feedEntry.SyncState.Tick = (correlation.ResSyncInfo.Tick > 0) ? correlation.ResSyncInfo.Tick : 1;
                feedEntry.SyncState.Stamp = correlation.ResSyncInfo.ModifiedStamp;

                // set the id tag
                feedEntry.Id = feedEntry.Uri;
                // set the title tag
                feedEntry.Title = String.Format("{0}: {1}", _parentPerformer._requestContext.ResourceKind.ToString(), feedEntry.Key);
                // set the updated tag
                feedEntry.Updated = correlation.ResSyncInfo.ModifiedStamp.ToLocalTime();

                // set resource dependent  links (self, edit, schema, template, post, service)
                feedEntry.Links.AddRange(LinkFactory.CreateEntryLinks(_parentPerformer._requestContext, feedEntry));

                return feedEntry;
            }
        public bool Update(CorrelatedResSyncInfo info, IJetTransaction jetTransaction)
        {
            IEndpointTableAdapter endpointTableAdapter = StoreEnvironment.Resolve<IEndpointTableAdapter>(this.Context);
            EndpointInfo endpointInfo = endpointTableAdapter.GetOrCreate(info.ResSyncInfo.Endpoint, jetTransaction);

            OleDbCommand oleDbCommand = jetTransaction.CreateOleCommand();

            string sqlQuery = string.Empty;
            sqlQuery = "UPDATE [{0}] SET [Tick]=@Tick, [ModifiedStamp]=@ModifiedStamp, [Etag]=@Etag, [LocalId]=@LocalId , [FKEndpointId]=@EndpointId  WHERE (Uuid=@Uuid);";

            oleDbCommand.CommandText = string.Format(sqlQuery, _correlatedResSyncTable.TableName);

            oleDbCommand.Parameters.AddWithValue("@Tick", info.ResSyncInfo.Tick);
            oleDbCommand.Parameters.AddWithValue("@ModifiedStamp", info.ResSyncInfo.ModifiedStamp.ToString());
            oleDbCommand.Parameters.AddWithValue("@Etag", info.ResSyncInfo.Etag);
            oleDbCommand.Parameters.AddWithValue("@LocalId", info.LocalId);
            oleDbCommand.Parameters.AddWithValue("@EndpointId", endpointInfo.Id);
            oleDbCommand.Parameters.AddWithValue("@Uuid", info.ResSyncInfo.Uuid);

            return (0 != oleDbCommand.ExecuteNonQuery());
        }
        public void Insert(CorrelatedResSyncInfo info, IJetTransaction jetTransaction)
        {
            IEndpointTableAdapter endpointTableAdapter = StoreEnvironment.Resolve<IEndpointTableAdapter>(this.Context);
            EndpointInfo endpointInfo = endpointTableAdapter.GetOrCreate(info.ResSyncInfo.Endpoint, jetTransaction);

            OleDbCommand oleDbCommand = jetTransaction.CreateOleCommand();

            string sqlQuery = string.Empty;
            sqlQuery = "INSERT INTO {0} ([Uuid], [Tick], [ModifiedStamp], [Etag], [LocalId], [FKEndpointId], [FKResourceKindId]) VALUES (@Uuid, @Tick, @ModifiedStamp, @Etag, @LocalId, @EndpointId, @ResourceKindId);";
            oleDbCommand.CommandText = string.Format(sqlQuery, _correlatedResSyncTable.TableName);

            oleDbCommand.Parameters.AddWithValue("@Uuid", info.ResSyncInfo.Uuid);
            oleDbCommand.Parameters.AddWithValue("@Tick", info.ResSyncInfo.Tick);
            oleDbCommand.Parameters.AddWithValue("@ModifiedStamp", info.ResSyncInfo.ModifiedStamp.ToString());
            oleDbCommand.Parameters.AddWithValue("@Etag", info.ResSyncInfo.Etag);
            oleDbCommand.Parameters.AddWithValue("@LocalId", info.LocalId);
            oleDbCommand.Parameters.AddWithValue("@EndpointId", endpointInfo.Id);
            oleDbCommand.Parameters.AddWithValue("@ResourceKindId", _correlatedResSyncTable.ResourceKindId);

            oleDbCommand.ExecuteNonQuery();
        }
Пример #16
0
        protected CorrelatedResSyncInfo GetUuidAsGuid(string localId, string uuidString)
        {
            if (String.IsNullOrEmpty(localId))
            {
                return null;
            }

               CorrelatedResSyncInfo[] results =  _correlatedResSyncInfoStore.GetByLocalId(_resourceKindString, new string[]{localId});
               if (results.Length > 0)
               return results[0];
            Guid result;
            if (string.IsNullOrEmpty(uuidString))
                   result = Guid.NewGuid();
            else
                try
                {
                    GuidConverter converter = new GuidConverter();
                    result = (Guid)converter.ConvertFromString(uuidString);
                    if (Guid.Empty.Equals(result))
                        result = Guid.NewGuid();
                }
                catch (Exception)
                {
                    result = Guid.NewGuid();
                }
                ResSyncInfo newResSyncInfo = new ResSyncInfo(result, _originApplication, 0, string.Empty, DateTime.Now);
                CorrelatedResSyncInfo syncInfo = new CorrelatedResSyncInfo(localId, newResSyncInfo);
                _correlatedResSyncInfoStore.Put(_resourceKindString, syncInfo);
                return syncInfo;
        }
Пример #17
0
        private void PersistRelations(List<TransactionResult> transactions)
        {
            GuidConverter guidConverter = new GuidConverter();
            foreach (TransactionResult transaction in transactions)
            {
                if (transaction.Status == TransactionStatus.Success)
                {
                    SupportedResourceKinds resourceKind = GetSupportedResourceKind(transaction.EntityName);
                    if (resourceKind == SupportedResourceKinds.None)
                        continue;

                    string uuidString = transaction.CRMID;
                    Guid uuid = Guid.Empty;
                    try
                    {
                        uuid = (Guid)guidConverter.ConvertFromString(uuidString);
                    }
                    catch
                    {
                        continue;
                    }
                    if (uuid == Guid.Empty)
                        continue;

                    string localId = transaction.ID;
                    ResSyncInfo resSyncInfo = new ResSyncInfo(uuid, _context.DatasetLink + resourceKind.ToString(), -1, "", DateTime.Now);

                    CorrelatedResSyncInfo correlatedResSyncInfo = new CorrelatedResSyncInfo(localId, resSyncInfo);

                    // store the new correlation to the sync store
                    _correlatedResSyncInfoStore.Put(resourceKind.ToString(), correlatedResSyncInfo);

                }
            }
        }
        public void Update(string resourceKind, CorrelatedResSyncInfo info)
        {
            ICorrelatedResSyncTableAdapter correlatedResSyncTableAdapter = this.GetAdapter(resourceKind);

            using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false))
            {
                if (!correlatedResSyncTableAdapter.Update(info, jetTransaction))
                    throw new StoreException(string.Format("No correlated ResSync exists for the resource kind '{0}' that can be updated.", resourceKind));

                jetTransaction.Commit();
            }
        }
        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;
        }
            // Asynchronous called method
            private void Execute(NorthwindConfig config, Digest targetDigest)
            {
                #region Declaration

                SdataContext sdataContext;
                SupportedResourceKinds resource;
                IAppBookmarkInfoStore appBookmarkInfoStore;
                ICorrelatedResSyncInfoStore correlatedResSyncInfoStore;
                ISyncSyncDigestInfoStore syncDigestStore;
                ISynctickProvider tickProvider;
                string resourceKind;
                string EndPoint;
                int nexttick = 1;
                Token lastToken;
                Token nextToken;
                Identity[] changedIdentites;
                IFeedEntryEntityWrapper wrapper;

                #endregion

                #region init

                sdataContext = _parentPerformer._requestContext.SdataContext;
                resource = _parentPerformer._requestContext.ResourceKind;
                resourceKind = resource.ToString();
                EndPoint = _parentPerformer._requestContext.DatasetLink + resourceKind;
                appBookmarkInfoStore = NorthwindAdapter.StoreLocator.GetAppBookmarkStore(sdataContext);
                correlatedResSyncInfoStore = NorthwindAdapter.StoreLocator.GetCorrelatedResSyncStore(sdataContext);
                syncDigestStore = NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext);
                tickProvider = NorthwindAdapter.StoreLocator.GettickProvider(sdataContext);

                wrapper = FeedEntryWrapperFactory.Create(resource, _parentPerformer._requestContext);

                #endregion

                #region get last token or create a new one

                if (!appBookmarkInfoStore.Get<Token>(resourceKind, out lastToken))
                {
                    lastToken = new Token();
                    lastToken.InitRequest = true;
                }

                #endregion

                #region Get local identities of changed entries since last synchronisation

                changedIdentites = wrapper.Entity.GetLastChanges(lastToken, config, out nextToken);

                #endregion

                if (resource == SupportedResourceKinds.phoneNumbers)
                {
                    #region workaround for phones
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        string phoneid = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.PhoneIdPostfix;
                        string faxId = changedIdentites[index].Id + Sage.Integration.Northwind.Application.API.Constants.FaxIdPostfix;

                        // receive the resource payloads for the phone id and for the fax id
                        // so that we can calculate their current etags.
                        FeedEntry phoneResourcePayloadContainer = wrapper.GetFeedEntry(phoneid);
                        FeedEntry faxResourcePayloadConatainer = wrapper.GetFeedEntry(faxId);

                        string etag;
                        CorrelatedResSyncInfo[] correlatedResSyncInfos;

                        #region Phone
                        if (phoneResourcePayloadContainer != null)
                        {
                            // calculate etag of the resource
                            etag = EtagServices.ComputeEtag(phoneResourcePayloadContainer, true);   // new etag

                            // retrieve correlations for the current identity from synch storage
                            correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { phoneid });

                            // if no correlation exists AND resource has been deleted:
                            // -> continue with next id
                            // else if no correlation exists:
                            // -> get next tick, create new correlation and add correlation to synch store
                            // otherwise and if the etag stored in synch store is different than etag previously calculated:
                            // -> get next tick, modify existing correlation and update it in synch store.
                            if (correlatedResSyncInfos.Length == 0 && phoneResourcePayloadContainer.IsDeleted)
                            {
                                continue;
                            }
                            else if (correlatedResSyncInfos.Length == 0)
                            {
                                nexttick = tickProvider.CreateNexttick(resourceKind); // create next tick

                                ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), EndPoint, nexttick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(phoneid, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);

                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nexttick = tickProvider.CreateNexttick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick = nexttick;
                                correlatedResSyncInfos[0].ResSyncInfo.EndPoint = EndPoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }

                        #endregion

                        #region Fax
                        if (faxResourcePayloadConatainer != null)
                        {
                            // calculate etag of the resource
                            etag = EtagServices.ComputeEtag(faxResourcePayloadConatainer, true);   // new etag

                            // retrieve correlations for the current identity from synch storage
                            correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { faxId });

                            // if no correlation exists AND resource has been deleted:
                            // -> continue with next id
                            // else if no correlation exists:
                            // -> get next tick, create new correlation and add correlation to synch store
                            // otherwise and if the etag stored in synch store is different than etag previously calculated:
                            // -> get next tick, modify existing correlation and update it in synch store.
                            if (correlatedResSyncInfos.Length == 0 && faxResourcePayloadConatainer.IsDeleted)
                            {
                                continue;
                            }
                            else if (correlatedResSyncInfos.Length == 0)
                            {
                                nexttick = tickProvider.CreateNexttick(resourceKind); // create next tick

                                ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), EndPoint, nexttick, etag, DateTime.Now);
                                CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(faxId, resyncInfo);

                                correlatedResSyncInfoStore.Put(resourceKind, info);

                                syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);
                            }
                            else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                            {
                                nexttick = tickProvider.CreateNexttick(resourceKind);
                                correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                                correlatedResSyncInfos[0].ResSyncInfo.Tick = nexttick;
                                correlatedResSyncInfos[0].ResSyncInfo.EndPoint = EndPoint;
                                correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                                correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                                syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                            }
                        }

                        #endregion

                    }
                    #endregion
                }
                else
                {
                    string id;
                    FeedEntry resourcePayloadContainer;
                    CorrelatedResSyncInfo[] correlatedResSyncInfos;
                    string etag;

                    // iterate through the collection of ids of all changed resources.
                    for (int index = 0; index < changedIdentites.Length; index++)
                    {
                        // current id from iterated collection
                        id = changedIdentites[index].Id;

                        // get resource payload container for the current identity so that we can calculated the
                        // etag.
                        // continue with next identity if no resource was found.
                        resourcePayloadContainer = wrapper.GetFeedEntry(id);

                        // calculate etag of the current resource payload
                        etag = EtagServices.ComputeEtag(resourcePayloadContainer, true);

                        // retrieve correlations for the current identity from synch storage
                        correlatedResSyncInfos = correlatedResSyncInfoStore.GetByLocalId(resourceKind, new string[] { id });

                        // if no correlation exists AND resource has been deleted:
                        // -> continue with next id
                        // else if no correlation exists:
                        // -> get next tick, create new correlation and add correlation to synch store
                        // otherwise and if the etag stored in synch store is different than etag previously calculated:
                        // -> get next tick, modify existing correlation and update it in synch store.
                        if (resourcePayloadContainer == null || (correlatedResSyncInfos.Length == 0 && resourcePayloadContainer.IsDeleted))
                        {
                            continue;
                        }
                        else if (correlatedResSyncInfos.Length == 0)
                        {
                            nexttick = tickProvider.CreateNexttick(resourceKind); // create next tick

                            ResSyncInfo resyncInfo = new ResSyncInfo(Guid.NewGuid(), EndPoint, nexttick, etag, DateTime.Now);
                            CorrelatedResSyncInfo info = new CorrelatedResSyncInfo(id, resyncInfo);

                            correlatedResSyncInfoStore.Put(resourceKind, info);

                            syncDigestStore.PersistNewer(resourceKind, info.ResSyncInfo);
                        }
                        else if (!correlatedResSyncInfos[0].ResSyncInfo.Etag.Equals(etag))
                        {
                            nexttick = tickProvider.CreateNexttick(resourceKind);
                            correlatedResSyncInfos[0].ResSyncInfo.Etag = etag;
                            correlatedResSyncInfos[0].ResSyncInfo.Tick = nexttick;
                            correlatedResSyncInfos[0].ResSyncInfo.EndPoint = EndPoint;
                            correlatedResSyncInfos[0].ResSyncInfo.ModifiedStamp = DateTime.Now;
                            correlatedResSyncInfoStore.Put(resourceKind, correlatedResSyncInfos[0]);

                            syncDigestStore.PersistNewer(resourceKind, correlatedResSyncInfos[0].ResSyncInfo);
                        }
                    }
                }

                #region store next token

                appBookmarkInfoStore.Put(resourceKind, nextToken);

                #endregion

                // set tracking phase
                lock (_parentPerformer._asyncStateObj)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.GETCHANGESBYtick;
                }

                if (null != targetDigest)
                {
                    ICorrelatedResSyncInfoEnumerator enumerator;
                    List<string> EndPoints = new List<string>();
                #warning remove this workaround
                    if (targetDigest.Entries != null)
                    {
                        foreach (DigestEntry targetDigestEntry in targetDigest.Entries)
                        {
                            EndPoints.Add(targetDigestEntry.EndPoint);
                            enumerator = correlatedResSyncInfoStore.GetSincetick(resourceKind, targetDigestEntry.EndPoint, ((int)targetDigestEntry.Tick) - 1);
                            while (enumerator.MoveNext())
                            {
                                // No lock needed, as we expect that CorrelatedResSyncInfos list is
                                // only acceeded anywhere else when Tracking phase is 'finish'.
                                //lock(_parentPerformer._asyncStateObj)
                                //{
                                _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                                //}
                            }
                        }
                    }

                    SyncDigestInfo sourceSyncDigestInfo = syncDigestStore.Get(resourceKind);
                    foreach (SyncDigestEntryInfo digestEntry in sourceSyncDigestInfo)
                    {
                        if (EndPoints.Contains(digestEntry.EndPoint))
                            continue;
                        EndPoints.Add(digestEntry.EndPoint);
                        enumerator = correlatedResSyncInfoStore.GetSincetick(resourceKind, digestEntry.EndPoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                    if (!EndPoints.Contains(EndPoint))
                    {
                        enumerator = correlatedResSyncInfoStore.GetSincetick(resourceKind, EndPoint, -1);
                        while (enumerator.MoveNext())
                        {
                            // No lock needed, as we expect that CorrelatedResSyncInfos list is
                            // only acceeded anywhere else when Tracking phase is 'finish'.
                            //lock(_parentPerformer._asyncStateObj)
                            //{
                            _parentPerformer._asyncStateObj.CorrelatedResSyncInfos.Add(enumerator.Current);
                            //}
                        }
                    }
                }

                // Set tracking phase to FINISH
                lock (_parentPerformer._asyncStateObj.Tracking)
                {
                    _parentPerformer._asyncStateObj.Tracking.Phase = TrackingPhase.FINISH;
                }
            }
            // 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;
                }
            }
Пример #22
0
        public virtual SyncFeedEntry GetFeedEntry(CorrelatedResSyncInfo resSyncInfo)
        {
            SyncFeedEntry result = GetFeedEntry(resSyncInfo.LocalId);
            if (result == null)
                return null;

            result.Uuid = resSyncInfo.ResSyncInfo.Uuid;
            result.HttpETag = resSyncInfo.ResSyncInfo.Etag;
            result.HttpMethod = "PUT";
            result.SyncState.Endpoint = resSyncInfo.ResSyncInfo.Endpoint;
            result.SyncState.Tick = resSyncInfo.ResSyncInfo.Tick;
            result.SyncState.Stamp = resSyncInfo.ResSyncInfo.ModifiedStamp;

            return result;
        }