public void Put(string resourceKind, SyncDigestInfo 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"); } // TODO: Validate entry property values // We set the priority on 'update'. lock (lockObj) { try { _provider.Update(resourceKind, info); } catch (StoreException) { _provider.Add(resourceKind, info); } } }
public SyncDigestInfo Get(int resourceKindId, IJetTransaction jetTransaction) { SyncDigestInfo resultInfo = new SyncDigestInfo(); OleDbCommand oleDbCommand = jetTransaction.CreateOleCommand(); string sqlQuery = string.Empty; sqlQuery = "SELECT {0}.Tick, {0}.ConflictPriority, {0}.Stamp, {1}.EndPoint FROM {1} INNER JOIN {0} ON {1}.ID={0}.FKEndPointId WHERE ((({0}.FKResourceKindId)=@ResourceKindId));"; oleDbCommand.CommandText = string.Format(sqlQuery, _syncDigestTable.TableName, _syncDigestTable.EndPointTable.TableName); oleDbCommand.Parameters.AddWithValue("@ResourceKindId", resourceKindId); using (OleDbDataReader reader = oleDbCommand.ExecuteReader(CommandBehavior.Default)) { while (reader.Read()) { string EndPoint; int tick; int conflictPriority; DateTime stamp; EndPoint = Convert.ToString(reader["EndPoint"]); tick = Convert.ToInt32(reader["tick"]); conflictPriority = Convert.ToInt32(reader["ConflictPriority"]); stamp = Convert.ToDateTime(reader["Stamp"]); resultInfo.Add(new SyncDigestEntryInfo(EndPoint, tick, conflictPriority, stamp)); } } return(resultInfo); }
public static string ToXml(SyncDigestInfo info, string endpoint) { StringBuilder sbDigest = new StringBuilder(); sbDigest.Append(@"<?xml version=""1.0"" encoding=""utf-8"" ?>"); sbDigest.Append(string.Format(@"<digest xmlns=""{0}"" mark=""current"">", Namespaces.syncNamespace)); sbDigest.Append(@"<origin>"); sbDigest.Append(endpoint); sbDigest.Append(@"</origin>"); foreach (SyncDigestEntryInfo digestEntry in info) { sbDigest.Append(@"<digestEntry>"); sbDigest.Append(@"<endpoint>"); sbDigest.Append(digestEntry.Endpoint); sbDigest.Append(@"</endpoint>"); sbDigest.Append(@"<tick>"); sbDigest.Append(digestEntry.Tick.ToString()); sbDigest.Append(@"</tick>"); sbDigest.Append(@"<conflictPriority>"); sbDigest.Append(digestEntry.ConflictPriority); sbDigest.Append(@"</conflictPriority>"); sbDigest.Append(@"</digestEntry>"); } sbDigest.Append(@"</digest>"); return sbDigest.ToString(); }
public void Put(string resourceKind, SyncDigestInfo 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"); // TODO: Validate entry property values // We set the priority on 'update'. lock (lockObj) { try { _provider.Update(resourceKind, info); } catch (StoreException) { _provider.Add(resourceKind, info); } } }
public static string ToXml(SyncDigestInfo info, string endpoint) { StringBuilder sbDigest = new StringBuilder(); sbDigest.Append(@"<?xml version=""1.0"" encoding=""utf-8"" ?>"); sbDigest.Append(string.Format(@"<digest xmlns=""{0}"" mark=""current"">", Namespaces.syncNamespace)); sbDigest.Append(@"<origin>"); sbDigest.Append(endpoint); sbDigest.Append(@"</origin>"); foreach (SyncDigestEntryInfo digestEntry in info) { sbDigest.Append(@"<digestEntry>"); sbDigest.Append(@"<endpoint>"); sbDigest.Append(digestEntry.Endpoint); sbDigest.Append(@"</endpoint>"); sbDigest.Append(@"<tick>"); sbDigest.Append(digestEntry.Tick.ToString()); sbDigest.Append(@"</tick>"); sbDigest.Append(@"<conflictPriority>"); sbDigest.Append(digestEntry.ConflictPriority); sbDigest.Append(@"</conflictPriority>"); sbDigest.Append(@"</digestEntry>"); } sbDigest.Append(@"</digest>"); return(sbDigest.ToString()); }
public static int GetConflictPriority(SyncDigestInfo digest, string EndPoint) { foreach (SyncDigestEntryInfo entry in digest) if ((entry.EndPoint != null) && (entry.EndPoint.Equals(EndPoint, StringComparison.InvariantCultureIgnoreCase))) return entry.ConflictPriority; return 10000; }
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 static int GetConflictPriority(SyncDigestInfo digest, string endpoint) { foreach (SyncDigestEntryInfo entry in digest) { if ((entry.Endpoint != null) && (entry.Endpoint.Equals(endpoint, StringComparison.InvariantCultureIgnoreCase))) { return(entry.ConflictPriority); } } return(10000); }
public static SyncState GetSyncState(SyncDigestInfo digest, string endpoint) { foreach (SyncDigestEntryInfo entry in digest) { if ((entry.Endpoint != null) && (entry.Endpoint.Equals(endpoint, StringComparison.InvariantCultureIgnoreCase))) { SyncState result = new SyncState(); result.Endpoint = entry.Endpoint; //result.Stamp = entry.Stamp; result.Tick = entry.Tick; return(result); } } return(null); }
public SyncDigestInfo Get(string resourceKind) { SyncDigestInfo resultInfo = null; ISyncDigestTableAdapter syncDigestTableAdapter = StoreEnvironment.Resolve <ISyncDigestTableAdapter>(_context); IResourceKindTableAdapter resourceKindTableAdapter = StoreEnvironment.Resolve <IResourceKindTableAdapter>(_context); using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false)) { ResourceKindInfo resourceKindInfo = resourceKindTableAdapter.GetOrCreate(resourceKind, jetTransaction); resultInfo = syncDigestTableAdapter.Get(resourceKindInfo.Id, jetTransaction); jetTransaction.Commit(); } return(resultInfo); }
public void Add(string resourceKind, SyncDigestInfo info) { ISyncDigestTableAdapter syncDigestTableAdapter = StoreEnvironment.Resolve<ISyncDigestTableAdapter>(_context); IResourceKindTableAdapter resourceKindTableAdapter = StoreEnvironment.Resolve<IResourceKindTableAdapter>(_context); using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false)) { ResourceKindInfo resourceKindInfo = resourceKindTableAdapter.GetOrCreate(resourceKind, jetTransaction); try { syncDigestTableAdapter.Insert(resourceKindInfo.Id, info.ToArray(), 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 syncDigest. A syncDigest already exists for the resourceKind '{0}'.", resourceKind), exception); throw; } jetTransaction.Commit(); } }
public void Add(string resourceKind, SyncDigestInfo info) { ISyncDigestTableAdapter syncDigestTableAdapter = StoreEnvironment.Resolve <ISyncDigestTableAdapter>(_context); IResourceKindTableAdapter resourceKindTableAdapter = StoreEnvironment.Resolve <IResourceKindTableAdapter>(_context); using (IJetTransaction jetTransaction = _jetConnectionProvider.GetTransaction(false)) { ResourceKindInfo resourceKindInfo = resourceKindTableAdapter.GetOrCreate(resourceKind, jetTransaction); try { syncDigestTableAdapter.Insert(resourceKindInfo.Id, info.ToArray(), 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 syncDigest. A syncDigest already exists for the resourceKind '{0}'.", resourceKind), exception); } throw; } jetTransaction.Commit(); } }
// 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; } }
// 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; } }
public SyncDigestInfo Get(int resourceKindId, IJetTransaction jetTransaction) { SyncDigestInfo resultInfo = new SyncDigestInfo(); OleDbCommand oleDbCommand = jetTransaction.CreateOleCommand(); string sqlQuery = string.Empty; sqlQuery = "SELECT {0}.Tick, {0}.ConflictPriority, {0}.Stamp, {1}.EndPoint FROM {1} INNER JOIN {0} ON {1}.ID={0}.FKEndPointId WHERE ((({0}.FKResourceKindId)=@ResourceKindId));"; oleDbCommand.CommandText = string.Format(sqlQuery, _syncDigestTable.TableName, _syncDigestTable.EndPointTable.TableName); oleDbCommand.Parameters.AddWithValue("@ResourceKindId", resourceKindId); using (OleDbDataReader reader = oleDbCommand.ExecuteReader(CommandBehavior.Default)) { while (reader.Read()) { string EndPoint; int tick; int conflictPriority; DateTime stamp; EndPoint = Convert.ToString(reader["EndPoint"]); tick = Convert.ToInt32(reader["tick"]); conflictPriority = Convert.ToInt32(reader["ConflictPriority"]); stamp = Convert.ToDateTime(reader["Stamp"]); resultInfo.Add(new SyncDigestEntryInfo(EndPoint, tick, conflictPriority, stamp)); } } return resultInfo; }
public static SyncState GetSyncState(SyncDigestInfo digest, string EndPoint) { foreach (SyncDigestEntryInfo entry in digest) { if ((entry.EndPoint != null) && (entry.EndPoint.Equals(EndPoint, StringComparison.InvariantCultureIgnoreCase))) { SyncState result = new SyncState(); result.EndPoint = entry.EndPoint; //result.Stamp = entry.Stamp; result.Tick = (entry.Tick>0)?entry.Tick:1; return result; } } return null; }
/// <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); }
/// <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 Feed <FeedEntry> GetFeed(NorthwindConfig config, PageInfo normalizedPageInfo) { Feed <FeedEntry> syncSourceFeed; 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); ISyncSyncDigestInfoStore syncDigestStore = NorthwindAdapter.StoreLocator.GetSyncDigestStore(sdataContext); SyncDigestInfo syncDigestInfo = syncDigestStore.Get(resourceKind); // Create a new Feed instance syncSourceFeed = new Feed <FeedEntry>();//FeedComponentFactory.Create<ISyncSourceFeed>(); syncSourceFeed.Author = new FeedAuthor(); syncSourceFeed.Author.Name = "Northwind Adapter"; syncSourceFeed.Category = new FeedCategory("http://schemas.sage.com/sdata/categories", "collection", "Resource Collection"); #region Digest syncSourceFeed.Digest = new Digest(); syncSourceFeed.Digest.Entries = (syncDigestInfo == null) ? new DigestEntry[0] : new DigestEntry[syncDigestInfo.Count]; // set digest origin syncSourceFeed.Digest.Origin = _parentPerformer._requestContext.OriginEndPoint; if (syncDigestInfo != null) { // convert and set digest entries from synch store object to feed object for (int i = 0; i < syncDigestInfo.Count; i++) { syncSourceFeed.Digest.Entries[i] = new DigestEntry(); syncSourceFeed.Digest.Entries[i].ConflictPriority = syncDigestInfo[i].ConflictPriority; syncSourceFeed.Digest.Entries[i].EndPoint = syncDigestInfo[i].EndPoint; syncSourceFeed.Digest.Entries[i].Tick = (int)syncDigestInfo[i].Tick; syncSourceFeed.Digest.Entries[i].Stamp = DateTime.Now; } } #endregion #region Entries // retrieve the data connection wrapper IFeedEntryEntityWrapper wrapper = FeedEntryWrapperFactory.Create(resource, _parentPerformer._requestContext); IEnumerator <CorrelatedResSyncInfo> correlationEnumerator = PagingHelpers.GetPagedEnumerator <CorrelatedResSyncInfo>(normalizedPageInfo, correlatedResSyncInfos.ToArray()); while (correlationEnumerator.MoveNext()) { syncSourceFeed.Entries.Add(this.BuildFeedEntry(correlationEnumerator.Current, wrapper)); } #endregion // initialize the feed string feedUrl = string.Format("{0}/$syncSource('{1}')", EndPoint, trackingId); string feedUrlWithoutQuery = (new Uri(feedUrl)).GetLeftPart(UriPartial.Path); // the url without query // set id tag syncSourceFeed.Id = feedUrl; // set title tag syncSourceFeed.Title = string.Format("{0} synchronization source feed {1}", resourceKind.ToString(), trackingId); // set update // syncSourceFeed.Updated = DateTime.Now; // set syncMode syncSourceFeed.SyncMode = SyncMode.catchUp;// syncModeenum.catchUp; // add links (general) syncSourceFeed.Links.AddRange(LinkFactory.CreateFeedLinks(_parentPerformer._requestContext, feedUrl)); #region PAGING & OPENSEARCH // add links (paging) syncSourceFeed.Links.AddRange(LinkFactory.CreatePagingLinks(normalizedPageInfo, correlatedResSyncInfos.Count, feedUrlWithoutQuery)); /* OPENSEARCH */ syncSourceFeed.ItemsPerPage = normalizedPageInfo.Count; syncSourceFeed.StartIndex = normalizedPageInfo.StartIndex; syncSourceFeed.TotalResults = correlatedResSyncInfos.Count; #endregion return(syncSourceFeed); }