private static MessageJournalFilter ConfigureFilter(IHttpResourceRequest request, ICollection <ErrorModel> errors) { var filter = new MessageJournalFilter(); var topic = request.QueryString["topic"]; if (!string.IsNullOrWhiteSpace(topic)) { filter.Topics = topic.Split(',') .Select(t => (TopicName)t) .ToList(); } var category = request.QueryString["category"]; if (!string.IsNullOrWhiteSpace(category)) { filter.Categories = category.Split(',') .Select(t => (MessageJournalCategory)t.Trim()) .ToList(); } filter.From = GetDateTime("from", request, errors); filter.To = GetDateTime("to", request, errors); filter.Origination = GetUri("origination", request, errors); filter.Destination = GetUri("destination", request, errors); filter.MessageName = request.QueryString["messageName"]; filter.RelatedTo = GetMessageId("relatedTo", request, errors); return(filter); }
protected void GivenFilter(Action <MessageJournalFilter> apply) { if (Filter == null) { Filter = new MessageJournalFilter(); } apply(Filter); }
private FilterDefinition <MessageJournalEntryDocument> BuildFilter(MessageJournalFilter filter, FilterDefinition <MessageJournalEntryDocument> filterDef, FilterDefinitionBuilder <MessageJournalEntryDocument> fb) { if (filter == null) { return(filterDef); } if (filter.Topics.Any()) { var topics = filter.Topics.Select(Normalize); filterDef = filterDef & fb.In(e => e.Topic, topics); } if (filter.Categories.Any()) { var categories = filter.Categories.Select(Normalize); filterDef = filterDef & fb.In(e => e.Category, categories); } if (filter.From != null) { filterDef = filterDef & fb.Gte(e => e.Timestamp, filter.From); } if (filter.To != null) { filterDef = filterDef & fb.Lte(e => e.Timestamp, filter.To); } if (filter.Origination != null) { var origination = Normalize(filter.Origination); filterDef = filterDef & fb.Eq(e => e.Origination, origination); } if (filter.Destination != null) { var destination = Normalize(filter.Destination); filterDef = filterDef & fb.Eq(e => e.Destination, destination); } if (!string.IsNullOrWhiteSpace(filter.MessageName)) { var partial = Normalize(filter.MessageName); var pattern = ".*" + Regex.Escape(partial) + ".*"; var regex = new BsonRegularExpression(pattern, "i"); filterDef = filterDef & fb.Regex(e => e.MessageName, regex); } if (filter.RelatedTo != null) { var relatedTo = Normalize(filter.RelatedTo); filterDef = filterDef & fb.Eq(e => e.RelatedTo, relatedTo); } return(filterDef); }
/// <summary> /// Reads messages from the journal /// </summary> /// <param name="start">The first position to read or <c>null</c> to begin reading from /// the beginning of the journal</param> /// <param name="count">The maximum number of messages to read</param> /// <param name="filter">(Optional) Constraints on which messages should be read</param> /// <param name="cancellationToken">(Optional) A token that the caller can use to /// request cancelation of the read operation</param> /// <returns>Returns a task whose result is the journal messages and meta data returned /// by the server</returns> public async Task <MessageJournalReadResult> Read(string start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = default(CancellationToken)) { var httpClient = await _httpClient; var relativeUri = new Uri("journal?" + BuildQuery(start, count, filter), UriKind.Relative); using (var responseMessage = await httpClient.GetAsync(relativeUri, cancellationToken)) { responseMessage.EnsureSuccessStatusCode(); return(await ParseResponseContent(responseMessage)); } }
private static string BuildQuery(string start, int count, MessageJournalFilter filter) { var queryParameters = new Dictionary <string, string>(); if (start != null) { queryParameters["start"] = start; } queryParameters["count"] = count.ToString(); if (filter != null) { if (filter.Topics.Count > 0) { queryParameters["topic"] = string.Join(",", filter.Topics); } if (filter.Categories.Count > 0) { queryParameters["category"] = string.Join(",", filter.Categories); } if (filter.From != null) { queryParameters["from"] = FormatDate(filter.From); } if (filter.To != null) { queryParameters["to"] = FormatDate(filter.To); } if (filter.Origination != null) { queryParameters["origination"] = filter.Origination.ToString(); } if (filter.Destination != null) { queryParameters["destination"] = filter.Destination.ToString(); } if (!string.IsNullOrWhiteSpace(filter.MessageName)) { queryParameters["messageName"] = filter.MessageName; } if (filter.RelatedTo != null) { queryParameters["relatedTo"] = filter.RelatedTo; } } return(string.Join("&", queryParameters .Select(p => p.Key + "=" + UrlEncoder.Encode(p.Value)))); }
private static bool IsExpectedFilter(MessageJournalFilter mf) { Assert.Equal(2, mf.Topics.Count); Assert.Equal(2, mf.Categories.Count); Assert.Contains((TopicName)"FooEvents", mf.Topics); Assert.Contains((TopicName)"BarEvents", mf.Topics); Assert.Contains((MessageJournalCategory)"Received", mf.Categories); Assert.Contains((MessageJournalCategory)"Received", mf.Categories); Assert.Equal(new DateTime(2017, 8, 9, 15, 31, 11, DateTimeKind.Utc).AddMilliseconds(12), mf.From); Assert.Equal(new DateTime(2017, 8, 10, 0, 0, 0, DateTimeKind.Utc), mf.To); Assert.Equal(new Uri("http://localhost:8089/platibus"), mf.Origination); Assert.Equal(new Uri("http://localhost:8090/platibus"), mf.Destination); Assert.Equal("event", mf.MessageName); Assert.Equal(new Guid("{637D88F6-48AC-4521-BD45-EA0965022AEC}"), mf.RelatedTo); return(true); }
public JournalingUpdateService(IMessageJournal messageJournal, ISerializationService serializationService, IJournalConsumerProgressTracker tracker, IMongoDatabase database, IMessageNamingService messageNamingService, IConfiguration configuration) { _messageJournal = messageJournal; _serializationService = serializationService; _tracker = tracker; _messageNamingService = messageNamingService; _eventProcessor = new CustomerJournalEventProcessor(database); // MessageJournalFilter does not work with mongo2 go if (configuration.GetValue <bool>("UseMongo2Go")) { Filter = null; } }
protected virtual async Task AssertSentMessageIsWrittenToJournal() { var beginningOfJournal = await MessageJournal.GetBeginningOfJournal(); var filter = new MessageJournalFilter { Categories = { MessageJournalCategory.Sent } }; var readResult = await MessageJournal.Read(beginningOfJournal, 100, filter); Assert.NotNull(readResult); var messages = readResult.Entries.Select(jm => jm.Data); Assert.Contains(Message, messages, new MessageEqualityComparer()); foreach (var entry in readResult.Entries) { Assert.Equal(entry.Category, MessageJournalCategory.Sent); Assert.Equal(entry.Data.Headers.Sent, entry.Timestamp, new WithinOneSecondDateTimeEqualityComparer()); } }
public async Task <ActionResult> Index(MessageJournalIndexModel model) { var updatedModel = await InitIndexModel(); updatedModel.Start = model.Start; updatedModel.Count = model.Count; updatedModel.FilterCategories = model.FilterCategories; updatedModel.FilterTopics = model.FilterTopics; updatedModel.FilterFrom = model.FilterFrom; updatedModel.FilterTo = model.FilterTo; updatedModel.FilterOrigination = model.FilterOrigination; updatedModel.FilterDestination = model.FilterDestination; updatedModel.FilterRelatedTo = model.FilterRelatedTo; updatedModel.FilterMessageName = model.FilterMessageName; updatedModel.ReadAttempted = true; var accessToken = GetAccessToken(); var credentials = new BearerCredentials(accessToken); using (var journalClient = new HttpMessageJournalClient(ApiBaseUri, credentials)) { var filter = new MessageJournalFilter { Topics = model.FilterTopics.Select(t => (TopicName)t).ToList(), Categories = model.FilterCategories.Select(c => (MessageJournalCategory)c).ToList(), From = model.FilterFrom, To = model.FilterTo, Origination = model.FilterOrigination, Destination = model.FilterDestination, MessageName = model.FilterMessageName, RelatedTo = model.FilterRelatedTo }; var readResult = await journalClient.Read(model.Start, model.Count, filter); updatedModel.Result = readResult; } return(View(updatedModel)); }
/// <inheritdoc /> public override Task <MessageJournalReadResult> Read(MessageJournalPosition start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = new CancellationToken()) { CheckDisposed(); return(_commandExecutor.ExecuteRead( () => base.Read(start, count, filter, cancellationToken), cancellationToken)); }
private static bool MatchesFilter(MessageJournalFilter filter, MessageJournalEntry entry) { if (filter == null) { return(true); } var headers = entry.Data.Headers; if (!string.IsNullOrWhiteSpace(filter.MessageName)) { var messageName = (string)headers.MessageName; if (!messageName.Contains(filter.MessageName)) { return(false); } } if (filter.Topics.Any()) { var topic = headers.Topic; if (!filter.Topics.Contains(topic)) { return(false); } } if (filter.Categories.Any()) { var category = entry.Category; if (!filter.Categories.Contains(category)) { return(false); } } var timestamp = entry.Timestamp; if (filter.From > timestamp) { return(false); } if (filter.To <= timestamp) { return(false); } if (filter.Origination != null) { var origination = headers.Origination; if (!origination.Equals(filter.Origination)) { return(false); } } if (filter.Destination != null) { var destination = headers.Destination; if (!destination.Equals(filter.Destination)) { return(false); } } if (filter.RelatedTo != null) { var relatedTo = headers.RelatedTo; if (!relatedTo.Equals(filter.RelatedTo)) { return(false); } } return(true); }
public virtual Task <MessageJournalReadResult> Read(MessageJournalPosition start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = default(CancellationToken)) { var myStart = (Position)start; IList <MessageJournalEntry> myEntries; lock (_syncRoot) { myEntries = _entries.Skip(myStart.Index) .Where(entry => MatchesFilter(filter, entry)) .Take(count + 1) .ToList(); } var next = myStart; var endOfJournal = myEntries.Count <= count; if (myEntries.Any()) { var lastIndex = myEntries.Select(e => e.Position).OfType <Position>().Max(p => p.Index); next = new Position(lastIndex + 1); } var readResult = new MessageJournalReadResult(start, next, endOfJournal, myEntries.Take(count)); return(Task.FromResult(readResult)); }
/// <inheritdoc /> public virtual async Task <MessageJournalReadResult> Read(MessageJournalPosition start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = default(CancellationToken)) { var myFilter = filter ?? new MessageJournalFilter(); var next = start; var journaledMessages = new List <MessageJournalEntry>(); var endOfJournal = true; var connection = ConnectionProvider.GetConnection(); try { var commandBuilder = CommandBuilders.NewSelectJournaledMessagesCommandBuilder(); commandBuilder.Categories = myFilter.Categories.Select(c => (string)c).ToList(); commandBuilder.Topics = myFilter.Topics.Select(t => (string)t).ToList(); commandBuilder.From = myFilter.From; commandBuilder.To = myFilter.To; commandBuilder.Origination = myFilter.Origination; commandBuilder.Destination = myFilter.Destination; commandBuilder.RelatedTo = myFilter.RelatedTo; commandBuilder.MessageName = myFilter.MessageName; commandBuilder.Start = ((SQLMessageJournalPosition)start).Id; commandBuilder.Count = count + 1; using (var scope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled)) { using (var command = commandBuilder.BuildDbCommand(connection)) { using (var reader = await command.ExecuteReaderAsync(cancellationToken)) { while (await reader.ReadAsync(cancellationToken)) { var record = commandBuilder.BuildJournaledMessageRecord(reader); next = new SQLMessageJournalPosition(record.Id); if (journaledMessages.Count < count) { var category = record.Category; var timestamp = record.Timestamp; var headers = DeserializeHeaders(record.Headers); var messageContent = record.Content; var offset = new SQLMessageJournalPosition(record.Id); var message = new Message(headers, messageContent); var journaledMessage = new MessageJournalEntry(category, offset, timestamp, message); journaledMessages.Add(journaledMessage); next = new SQLMessageJournalPosition(record.Id + 1); } else { endOfJournal = false; } } } } scope.Complete(); } } finally { ConnectionProvider.ReleaseConnection(connection); } return(new MessageJournalReadResult(start, next, endOfJournal, journaledMessages)); }
/// <inheritdoc /> public async Task <MessageJournalReadResult> Read(MessageJournalPosition start, int count, MessageJournalFilter filter = null, CancellationToken cancellationToken = new CancellationToken()) { var fb = Builders <MessageJournalEntryDocument> .Filter; var filterDef = fb.Gte(mje => mje.Id, ((MongoDBMessageJournalPosition)start).Id); filterDef = BuildFilter(filter, filterDef, fb); var options = new FindOptions(); if (_collationSupported) { options.Collation = _collation; } var entryDocuments = await _messageJournalEntries.Find(filterDef, options) .Limit(count + 1) .ToListAsync(cancellationToken); var endOfJournal = entryDocuments.Count <= count; var nextId = entryDocuments.Select(e => e.Id).LastOrDefault(); if (endOfJournal) { nextId = new ObjectId(nextId.Timestamp, nextId.Machine, nextId.Pid, nextId.Increment + 1); } var nextPosition = new MongoDBMessageJournalPosition(nextId); var entries = new List <MessageJournalEntry>(); foreach (var entryDocument in entryDocuments.Take(count)) { var position = new MongoDBMessageJournalPosition(entryDocument.Id); var timestamp = entryDocument.Timestamp; var category = entryDocument.Category; var headers = new MessageHeaders(entryDocument.Headers); var message = new Message(headers, entryDocument.Content); entries.Add(new MessageJournalEntry(category, position, timestamp, message)); } return(new MessageJournalReadResult(start, nextPosition, endOfJournal, entries)); }