/// <summary> /// Send audit for querying /// </summary> protected virtual void SendAuditQuery(OutcomeIndicator success, IMessage message, IEnumerable <IdentifiedData> results) { AuditUtil.AuditQuery(Core.Auditing.OutcomeIndicator.Success, PipeParser.Encode(message.GetStructure("QPD") as ISegment, new EncodingCharacters('|', "^~\\&")), results?.OfType <IdentifiedData>().ToArray()); }
/// <summary> /// Handle message internally /// </summary> protected override IMessage HandleMessageInternal(Hl7MessageReceivedEventArgs e, Bundle parsed) { // First we want to get the map var msh = e.Message.GetStructure("MSH") as MSH; var trigger = msh.MessageType.TriggerEvent.Value; var map = this.GetMapping(trigger); var qpd = e.Message.GetStructure("QPD") as QPD; try { if (map.ResponseType == null) { throw new NotSupportedException($"Response type not found"); } // First, process the query parameters var query = map.QueryHandler.ParseQuery(qpd, map); if (query.Count == 0) { throw new InvalidOperationException("Query must provide at least one understood filter"); } // Control? var rcp = e.Message.GetStructure("RCP") as RCP; int? count = null, offset = 0; Guid queryId = Guid.NewGuid(); if (!String.IsNullOrEmpty(rcp.QuantityLimitedRequest.Quantity.Value)) { count = Int32.Parse(rcp.QuantityLimitedRequest.Quantity.Value); } // Continuation? var dsc = e.Message.GetStructure("DSC") as DSC; if (!String.IsNullOrEmpty(dsc.ContinuationPointer.Value)) { if (!Guid.TryParse(dsc.ContinuationPointer.Value, out queryId)) { throw new InvalidOperationException($"DSC^1 must be UUID provided by this service."); } } // Get the query tag which is the current offset if (ApplicationServiceContext.Current.GetService <Core.Services.IQueryPersistenceService>()?.IsRegistered(queryId) == true) { var tag = ApplicationServiceContext.Current.GetService <Core.Services.IQueryPersistenceService>().GetQueryTag(queryId); if (tag is int) { offset = (int)tag; } } // Next, we want to get the repository for the bound type var repoService = ApplicationServiceContext.Current.GetService(typeof(IRepositoryService <>).MakeGenericType(map.QueryTarget)); if (repoService == null) { throw new InvalidOperationException($"Cannot find repository service for {map.QueryTargetXml}"); } // Build query int totalResults = 0; IEnumerable results = null; Expression filterQuery = null; if (query.ContainsKey("_id")) { Guid id = Guid.Parse(query["_id"][0]); object result = repoService.GetType().GetMethod("Get", new Type[] { typeof(Guid) }).Invoke(repoService, new object[] { id }); results = new List <IdentifiedData>(); if (result != null) { (results as IList).Add(result); totalResults = 1; } } else { var queryMethod = typeof(QueryExpressionParser).GetGenericMethod(nameof(QueryExpressionParser.BuildLinqExpression), new Type[] { map.QueryTarget }, new Type[] { typeof(NameValueCollection) }); filterQuery = queryMethod.Invoke(null, new object[] { query }) as Expression; // Now we want to query object[] parameters = { filterQuery, offset.Value, (int?)count ?? 100, null, queryId, null }; var findMethod = repoService.GetType().GetMethod("Find", new Type[] { filterQuery.GetType(), typeof(int), typeof(int?), typeof(int).MakeByRefType(), typeof(Guid), typeof(ModelSort <>).MakeGenericType(map.QueryTarget).MakeArrayType() }); results = findMethod.Invoke(repoService, parameters) as IEnumerable; totalResults = (int)parameters[3]; } // Save the tag if (dsc.ContinuationPointer.Value != queryId.ToString() && offset.Value + count.GetValueOrDefault() < totalResults) { ApplicationServiceContext.Current.GetService <Core.Services.IQueryPersistenceService>()?.SetQueryTag(queryId, count); } AuditUtil.AuditQuery(Core.Auditing.OutcomeIndicator.Success, PipeParser.Encode(qpd, new EncodingCharacters('|', "^~\\&")), results.OfType <IdentifiedData>().ToArray()); // Query basics return(this.CreateQueryResponse(e, filterQuery, map, results, queryId, offset.GetValueOrDefault(), count ?? 100, totalResults)); } catch (Exception ex) { this.m_traceSource.TraceEvent(EventLevel.Error, "Error executing query: {0}", ex); AuditUtil.AuditQuery <IdentifiedData>(Core.Auditing.OutcomeIndicator.MinorFail, PipeParser.Encode(qpd, new EncodingCharacters('|', "^~\\&"))); // Now we construct the response return(this.CreateNACK(map.ResponseType, e.Message, ex, e)); } }
public virtual IEnumerable <Object> Query(NameValueCollection queryParameters, int offset, int count, out int totalCount) { if ((this.Capabilities & ResourceCapabilityType.Search) == 0) { throw new NotSupportedException(this.m_localizationService.GetString("error.type.NotSupportedException")); } try { IEnumerable <TResource> retVal = null; // IS this a freetext search? if (queryParameters.ContainsKey("_any")) { var fts = ApplicationServiceContext.Current.GetService <IFreetextSearchService>(); if (fts == null) { this.m_tracer.TraceError("Attempting to run a freetext search in a context which does not support freetext searches"); throw new InvalidOperationException(this.m_localizationService.GetString("error.rest.common.freetextNotSupported")); } // Order by ModelSort <TResource>[] sortParameters = null; if (queryParameters.TryGetValue("_orderBy", out List <String> orderBy)) { sortParameters = QueryExpressionParser.BuildSort <TResource>(orderBy); } Guid queryId = Guid.Empty; if (queryParameters.TryGetValue("_queryId", out List <String> query)) { queryId = Guid.Parse(query.First()); } retVal = fts.Search <TResource>(queryParameters["_any"].ToArray(), queryId, offset, count, out totalCount, sortParameters); } else { var queryExpression = QueryExpressionParser.BuildLinqExpression <TResource>(queryParameters, null, false); List <String> query = null, id = null, orderBy = null; // Order by ModelSort <TResource>[] sortParameters = null; if (queryParameters.TryGetValue("_orderBy", out orderBy)) { sortParameters = QueryExpressionParser.BuildSort <TResource>(orderBy); } if (queryParameters.TryGetValue("_id", out id)) { var obj = id.Select(o => this.GetRepository().Get(Guid.Parse(o))); if (obj != null) { retVal = new List <TResource>(obj); } else { retVal = new List <TResource>(); } totalCount = retVal.Count(); } else if (queryParameters.TryGetValue("_queryId", out query) && this.GetRepository() is IPersistableQueryRepositoryService <TResource> ) { Guid queryId = Guid.Parse(query[0]); List <String> data = null; if (queryParameters.TryGetValue("_subscription", out data)) { // subscription based query totalCount = 0; retVal = ApplicationServiceContext.Current.GetService <ISubscriptionExecutor>()?.Execute(Guid.Parse(data.First()), queryParameters, offset, count, out totalCount, queryId).OfType <TResource>(); } else if (queryParameters.TryGetValue("_lean", out data) && data[0] == "true" && this.GetRepository() is IFastQueryRepositoryService <TResource> ) { retVal = (this.GetRepository() as IFastQueryRepositoryService <TResource>).FindFast(queryExpression, offset, count, out totalCount, queryId); } else { retVal = (this.GetRepository() as IPersistableQueryRepositoryService <TResource>).Find(queryExpression, offset, count, out totalCount, queryId, sortParameters); } } else { List <String> lean = null; if (queryParameters.TryGetValue("_lean", out lean) && lean[0] == "true" && this.GetRepository() is IFastQueryRepositoryService <TResource> ) { retVal = (this.GetRepository() as IFastQueryRepositoryService <TResource>).FindFast(queryExpression, offset, count, out totalCount, Guid.Empty); } else { retVal = this.GetRepository().Find(queryExpression, offset, count, out totalCount, sortParameters); } } } if (typeof(Act).IsAssignableFrom(typeof(TResource)) || typeof(Entity).IsAssignableFrom(typeof(TResource))) { AuditUtil.AuditQuery(Core.Auditing.OutcomeIndicator.Success, queryParameters.ToString(), retVal.ToArray()); } return(retVal); } catch (Exception e) { AuditUtil.AuditQuery <TResource>(Core.Auditing.OutcomeIndicator.MinorFail, queryParameters.ToString()); this.m_tracer.TraceError("Error querying underlying repository"); throw new Exception(this.m_localizationService.GetString("error.rest.common.queryingRepository"), e); } }