/// <summary> /// Get discrete records by id /// </summary> public RegistryQueryResult Get(VersionedDomainIdentifier[] regEvtIds, RegistryQueryRequest qd) { RegistryQueryResult retVal = new RegistryQueryResult(); try { List <VersionedDomainIdentifier> retRecordId = new List <VersionedDomainIdentifier>(100); // Query continuation if (this.m_queryPersistence != null && this.m_queryPersistence.IsRegistered(qd.QueryId.ToLower())) { throw new Exception(String.Format("The query '{0}' has already been registered. To continue this query use the QUQI_IN000003CA interaction", qd.QueryId)); } else { retVal.Results = this.GetRecordsAsync(regEvtIds, retRecordId, qd, retVal.Details); // Get the count of not-included records retVal.Results.RemoveAll(o => o == null); // Persist the query if (this.m_queryPersistence != null) { this.m_queryPersistence.RegisterQuerySet(qd.QueryId.ToLower(), regEvtIds, qd); } // Return query data retVal.TotalResults = retRecordId.Count(o => o != null); } } catch (TimeoutException ex) { Trace.TraceError(ex.ToString()); retVal.Details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); } catch (DbException ex) { Trace.TraceError(ex.ToString()); retVal.Details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); } catch (DataException ex) { Trace.TraceError(ex.ToString()); retVal.Details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); } catch (Exception ex) { Trace.TraceError(ex.ToString()); retVal.Details.Add(new ResultDetail(ResultDetailType.Error, ex.Message, ex)); } return(retVal); }
/// <summary> /// Create filter data /// </summary> public RegistryQueryRequest CreateFilterData(MARC.Everest.Interfaces.IInteraction request, List <MARC.Everest.Connectors.IResultDetail> dtls) { ILocalizationService locale = Context.GetService(typeof(ILocalizationService)) as ILocalizationService; ISystemConfigurationService config = Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; // Componentize the message into the data model UvComponentUtil compUtil = new UvComponentUtil(); compUtil.Context = this.Context; PRPA_IN201309UV02 rqst = request as PRPA_IN201309UV02; List <DomainIdentifier> ids = new List <DomainIdentifier>(); var queryData = compUtil.CreateQueryMatch(rqst.controlActProcess, dtls, ref ids); if (ids == null || queryData == null) { throw new MessageValidationException(locale.GetString("MSGE00A"), request); } var filter = new RegistryQueryRequest() { QueryId = String.Format("{1}^^^&{0}&ISO", rqst.controlActProcess.queryByParameter.QueryId.Root, rqst.controlActProcess.queryByParameter.QueryId.Extension), Limit = 100, Originator = String.Format("{1}^^^&{0}&ISO", rqst.Sender.Device.Id.First.Root, rqst.Sender.Device.Id.First.Extension), QueryRequest = queryData, TargetDomain = ids, IsSummary = true, ResponseMessageType = this.CreateType.AssemblyQualifiedName }; // Ensure that the target domains are understood by this service if (filter.TargetDomain != null) { foreach (var id in filter.TargetDomain) { if (String.IsNullOrEmpty(id.Domain) || config.OidRegistrar.FindData(id.Domain) == null || !config.OidRegistrar.FindData(id.Domain).Attributes.Exists(p => p.Key.Equals("AssigningAuthorityName"))) { dtls.Add(new UnrecognizedTargetDomainResultDetail(locale, String.Format("//urn:hl7-org:v3#controlActProcess/urn:hl7-org:v3#queryByParameter/urn:hl7-org:v3#parameterList/urn:hl7-org:v3#patientIdentifier/urn:hl7-org:v3#value[@root='{0}']", id.Domain))); } } } return(filter); }
/// <summary> /// Query the data store /// </summary> public static FhirQueryResult Query(ClientRegistryFhirQuery querySpec, List <IResultDetail> details) { // Get the services IClientRegistryDataService dataService = ApplicationContext.CurrentContext.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService; IQueryPersistenceService queryService = ApplicationContext.CurrentContext.GetService(typeof(IQueryPersistenceService)) as IQueryPersistenceService; try { if (querySpec.Quantity > 100) { throw new ConstraintException("Query limit must not exceed 100"); } if (dataService == null) { throw new InvalidOperationException("No persistence service has been configured, queries cannot continue without this service"); } FhirQueryResult result = new FhirQueryResult(); result.Query = querySpec; result.Issues = new List <DetectedIssue>(); result.Details = details; result.Results = new List <SVC.Messaging.FHIR.Resources.ResourceBase>(querySpec.Quantity); VersionedDomainIdentifier[] identifiers; RegistryQueryRequest queryRequest = new RegistryQueryRequest() { QueryRequest = querySpec.Filter, QueryId = querySpec.QueryId != Guid.Empty ? querySpec.QueryId.ToString() : null, QueryTag = querySpec.QueryId != Guid.Empty ? querySpec.QueryId.ToString(): null, IsSummary = !querySpec.IncludeHistory, Offset = querySpec.Start, Limit = querySpec.Quantity }; // Is this a continue? queryRequest.IsContinue = (!String.IsNullOrEmpty(queryRequest.QueryId) && queryRequest.Offset > 0); var dataResults = dataService.Query(queryRequest); details.AddRange(dataResults.Details); result.TotalResults = dataResults.TotalResults; // Fetch the results foreach (HealthServiceRecordContainer res in dataResults.Results) { if (res == null) { continue; } var resultSubject = res.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as HealthServiceRecordContainer ?? res; var processor = FhirMessageProcessorUtil.GetComponentProcessor(resultSubject.GetType()); if (processor == null) { result.Details.Add(new NotImplementedResultDetail(ResultDetailType.Error, String.Format("Will not include {1}^^^&{2}&ISO in result set, cannot find converter for {0}", resultSubject.GetType().Name, resultSubject.Id, ApplicationContext.ConfigurationService.OidRegistrar.GetOid("CR_CID").Oid), null, null)); } else { result.Results.Add(processor.ProcessComponent(resultSubject, details)); } } // Sort control? // TODO: Support sort control but for now just sort according to confidence then date //retVal.Sort((a, b) => b.Id.CompareTo(a.Id)); // Default sort by id //if (queryPersistence != null) // result.TotalResults = (int)queryPersistence.QueryResultTotalQuantity(querySpec.QueryId.ToString()); //else // result.TotalResults = retRecordId.Count(o => o != null); return(result); } catch (Exception ex) { Trace.TraceError(ex.ToString()); details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); throw; } }
/// <summary> /// Patient registry get identifiers query /// </summary> /// <param name="e"></param> /// <param name="receivedMessage"></param> /// <returns></returns> private IGraphable PatientRegistryGetIdentifiers(UnsolicitedDataEventArgs e, IReceiveResult receivedMessage) { // Setup the lists of details and issues List <IResultDetail> dtls = new List <IResultDetail>(receivedMessage.Details); // System configuration service ISystemConfigurationService configService = Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; // Localization service ILocalizationService locale = Context.GetService(typeof(ILocalizationService)) as ILocalizationService; // Data Service IClientRegistryDataService dataSvc = Context.GetService(typeof(IClientRegistryDataService)) as IClientRegistryDataService; // Do basic check and add common validation errors MessageUtil.ValidateTransportWrapperUv(receivedMessage.Structure as IInteraction, configService, dtls); // Check the request is valid var request = receivedMessage.Structure as PRPA_IN201309UV02; if (request == null) { return(null); } // Determine if the received message was interpreted properly bool isValid = MessageUtil.IsValid(receivedMessage); // set the URI if (request.controlActProcess != null) { request.controlActProcess.Code = request.controlActProcess.Code ?? Util.Convert <CD <String> >(PRPA_IN201302UV02.GetTriggerEvent()); } if (request.Receiver.Count > 0) { request.Receiver[0].Telecom = request.Receiver[0].Telecom ?? e.ReceiveEndpoint.ToString(); } // Construct the acknowledgment var response = new PRPA_IN201310UV02( new II(configService.OidRegistrar.GetOid("CR_MSGID").Oid, Guid.NewGuid().ToString()), DateTime.Now, PRPA_IN201310UV02.GetInteractionId(), request.ProcessingCode, request.ProcessingModeCode, AcknowledgementCondition.Never, MessageUtil.CreateReceiver(request.Sender), MessageUtil.CreateSenderUv(e.ReceiveEndpoint, configService), null ); // Create the support classes AuditData audit = null; IheAuditUtil dataUtil = new IheAuditUtil() { Context = this.Context }; // Try to execute the record try { // Determine if the message is valid if (!isValid) { throw new MessageValidationException(locale.GetString("MSGE00A"), receivedMessage.Structure); } // Construct the canonical data structure GetIdentifiersQueryResponseFactory fact = new GetIdentifiersQueryResponseFactory() { Context = this.Context }; RegistryQueryRequest filter = fact.CreateFilterData(request, dtls); if (filter.QueryRequest == null) { throw new MessageValidationException(locale.GetString("MSGE00A"), receivedMessage.Structure); } // Query var results = dataSvc.Query(filter); dtls.AddRange(results.Details); // Prepare for audit audit = dataUtil.CreateAuditData("ITI-45", ActionType.Execute, dtls.Exists(r => r.Type == ResultDetailType.Error) ? OutcomeIndicator.MinorFail : OutcomeIndicator.Success, e, receivedMessage, results, filter.QueryRequest.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.AuthorOf) as HealthcareParticipant ); response = fact.Create(request, results, dtls) as PRPA_IN201310UV02; } catch (Exception ex) { Trace.TraceError(ex.ToString()); // Prepare for audit audit = dataUtil.CreateAuditData("ITI-45", ActionType.Execute, OutcomeIndicator.EpicFail, e, receivedMessage, new List <VersionedDomainIdentifier>(), null ); dtls.Add(new ResultDetail(ResultDetailType.Error, ex.Message, ex)); response.Acknowledgement.Add(new MARC.Everest.RMIM.UV.NE2008.MCCI_MT100300UV01.Acknowledgement( AcknowledgementType.AcceptAcknowledgementCommitError, new MARC.Everest.RMIM.UV.NE2008.MCCI_MT100200UV01.TargetMessage(request.Id) )); } finally { IAuditorService auditService = Context.GetService(typeof(IAuditorService)) as IAuditorService; if (auditService != null) { auditService.SendAudit(audit); } } // Common response parameters response.ProfileId = new SET <II>(MCCI_IN000002UV01.GetProfileId()); response.VersionCode = HL7StandardVersionCode.Version3_Prerelease1; response.AcceptAckCode = AcknowledgementCondition.Never; response.Acknowledgement[0].AcknowledgementDetail.AddRange(MessageUtil.CreateAckDetailsUv(dtls.ToArray())); return(response); }
/// <summary> /// Create filter data /// </summary> public RegistryQueryRequest CreateFilterData(MARC.Everest.Interfaces.IInteraction request, List <MARC.Everest.Connectors.IResultDetail> dtls) { ILocalizationService locale = Context.GetService(typeof(ILocalizationService)) as ILocalizationService; ISystemConfigurationService config = Context.GetService(typeof(ISystemConfigurationService)) as ISystemConfigurationService; // Componentize the message into the data model UvComponentUtil compUtil = new UvComponentUtil(); compUtil.Context = this.Context; PRPA_IN201305UV02 rqst = request as PRPA_IN201305UV02; List <DomainIdentifier> ids = new List <DomainIdentifier>(); var queryData = compUtil.CreateQueryMatch(rqst.controlActProcess, dtls, ref ids); if (ids == null || queryData == null) { throw new MessageValidationException(locale.GetString("MSGE00A"), request); } var filter = new RegistryQueryRequest() { QueryId = String.Format("{1}^^^&{0}&ISO", rqst.controlActProcess.queryByParameter.QueryId.Root, rqst.controlActProcess.queryByParameter.QueryId.Extension), Limit = rqst.controlActProcess.queryByParameter.InitialQuantity == null ? 100 : (int)rqst.controlActProcess.queryByParameter.InitialQuantity, Originator = String.Format("{1}^^^&{0}&ISO", rqst.Sender.Device.Id.First.Root, rqst.Sender.Device.Id.First.Extension), ResponseMessageType = this.CreateType.AssemblyQualifiedName, QueryRequest = queryData, IsSummary = true, OriginalMessageQueryId = String.Format("{1}^^^&{0}&ISO", request.Id.Root, request.Id.Extension) }; // Filter parameters var qbp = rqst.controlActProcess.queryByParameter; if (qbp != null && qbp.MatchCriterionList != null && qbp.MatchCriterionList.NullFlavor == null) { if (qbp.MatchCriterionList.MatchAlgorithm != null && qbp.MatchCriterionList.MatchAlgorithm.NullFlavor == null && qbp.MatchCriterionList.MatchAlgorithm.Value is ST) { try { filter.MatchingAlgorithm = (MatchAlgorithm)Enum.Parse(typeof(MatchAlgorithm), qbp.MatchCriterionList.MatchAlgorithm.Value as ST); } catch { dtls.Add(new VocabularyIssueResultDetail(ResultDetailType.Warning, String.Format(locale.GetString("MSGE071"), qbp.MatchCriterionList.MatchAlgorithm.Value as ST), null)); } } else { filter.MatchingAlgorithm = MatchAlgorithm.Default; } // Match degree match if (qbp.MatchCriterionList.MinimumDegreeMatch != null && qbp.MatchCriterionList.MinimumDegreeMatch.NullFlavor == null && qbp.MatchCriterionList.MinimumDegreeMatch.Value != null && !qbp.MatchCriterionList.MinimumDegreeMatch.Value.IsNull) { var match = qbp.MatchCriterionList.MinimumDegreeMatch.Value as INT; if (match == null || match < 0 || match > 100) { dtls.Add(new NotSupportedChoiceResultDetail(ResultDetailType.Warning, locale.GetString("MSGE072"), null, null)); } else { filter.MinimumDegreeMatch = (float)((float)match / 100); } } } // Ensure that the target domains are understood by this service if (filter.TargetDomain != null) { foreach (var id in filter.TargetDomain) { if (String.IsNullOrEmpty(id.Domain) || config.OidRegistrar.FindData(id.Domain) == null || !config.OidRegistrar.FindData(id.Domain).Attributes.Exists(p => p.Key.Equals("AssigningAuthorityName"))) { dtls.Add(new UnrecognizedTargetDomainResultDetail(locale, String.Format("//urn:hl7-org:v3#controlActProcess/urn:hl7-org:v3#queryByParameter/urn:hl7-org:v3#parameterList/urn:hl7-org:v3#patientIdentifier/urn:hl7-org:v3#value[@root='{0}']", id.Domain))); } } } return(filter); }
/// <summary> /// Create RSP_K21 message /// </summary> internal NHapi.Base.Model.IMessage CreateRSP_K21(RegistryQueryResult result, RegistryQueryRequest filter, List <Everest.Connectors.IResultDetail> dtls) { // Return value var retVal = new NHapi.Model.V25.Message.RSP_K21(); retVal.MSH.MessageType.MessageStructure.Value = "RSP_K21"; var qak = retVal.QAK; var msa = retVal.MSA; var dsc = retVal.DSC; var qpd = retVal.QPD; qak.QueryTag.Value = result.QueryTag; msa.AcknowledgmentCode.Value = "AA"; if (dtls.Exists(o => o.Type == Everest.Connectors.ResultDetailType.Error)) { qak.QueryResponseStatus.Value = "AE"; msa.AcknowledgmentCode.Value = "AE"; foreach (var dtl in dtls) { var err = retVal.GetStructure("ERR", retVal.currentReps("ERR")) as NHapi.Model.V25.Segment.ERR; MessageUtil.UpdateERR(err, dtl, Context); } } else if (result.Results == null || result.Results.Count == 0) { qak.QueryResponseStatus.Value = "NF"; } else { // Create the pid qak.QueryResponseStatus.Value = "OK"; qak.HitCount.Value = result.TotalResults.ToString(); qak.ThisPayload.Value = result.Results.Count.ToString(); //qak.HitsRemaining.Value = (result.TotalResults - result.StartRecordNumber).ToString(); foreach (RegistrationEvent res in result.Results) { var pid = retVal.GetQUERY_RESPONSE(retVal.QUERY_RESPONSERepetitionsUsed); UpdatePID(res, pid.PID, false); UpdateQRI(res, pid.QRI); pid.PID.SetIDPID.Value = retVal.QUERY_RESPONSERepetitionsUsed.ToString(); } // DSC segment? if (result.TotalResults > result.Results.Count) { retVal.DSC.ContinuationPointer.Value = result.ContinuationPtr; retVal.DSC.ContinuationStyle.Value = "I"; } } // Actual query paramaeters var regFilter = filter.QueryRequest.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as RegistrationEvent; var personFilter = regFilter.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.SubjectOf) as Person; qpd.QueryTag.Value = filter.QueryTag; qpd.MessageQueryName.Identifier.Value = "IHE PDQ Query"; var terser = new Terser(retVal); int qpdRep = 0; if (personFilter.GenderCode != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.8"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), personFilter.GenderCode); } if (personFilter.AlternateIdentifiers != null && personFilter.AlternateIdentifiers.Count > 0) { var altId = personFilter.AlternateIdentifiers[0]; if (altId.Domain != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.2"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Domain); terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.3"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), "ISO"); } if (altId.Identifier != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.1"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Identifier); } if (altId.AssigningAuthority != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.3.4.1"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.AssigningAuthority); } } if (personFilter.Names != null && personFilter.Names.Count > 0) { var name = personFilter.Names[0]; foreach (var pt in name.Parts) { string pidNo = ComponentUtility.XPN_MAP.First(o => o.Value == pt.Type).Key; terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.5.{0}", pidNo)); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.Value); } if (name.Use != NameSet.NameSetUse.Search) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.5.7"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), ComponentUtility.XPN_USE_MAP.First(o => o.Value == name.Use).Key); } } if (personFilter.BirthTime != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.7"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), new TS(personFilter.BirthTime.Value).Value); } if (personFilter.Addresses != null && personFilter.Addresses.Count > 0) { var addr = personFilter.Addresses[0]; foreach (var pt in addr.Parts) { string pidNo = ComponentUtility.AD_MAP.First(o => o.Value == pt.PartType).Key; terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.11.{0}", pidNo)); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.AddressValue); } if (addr.Use != AddressSet.AddressSetUse.Search) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.11.7"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), ComponentUtility.AD_USE_MAP.First(o => o.Value == addr.Use).Key); } } var ma = personFilter.FindComponent(SVC.Core.ComponentModel.HealthServiceRecordSiteRoleType.RepresentitiveOf) as PersonalRelationship; if (ma != null) { if (ma.LegalName != null) { foreach (var pt in ma.LegalName.Parts) { string pidNo = ComponentUtility.XPN_MAP.First(o => o.Value == pt.Type).Key; terser.Set(String.Format("/QPD-3({0})-1", qpdRep), String.Format("@PID.6.{0}", pidNo)); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), pt.Value); } } if (ma.AlternateIdentifiers != null && ma.AlternateIdentifiers.Count > 0) { var altId = ma.AlternateIdentifiers[0]; if (altId.Domain != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.2"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Domain); terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.3"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), "ISO"); } if (altId.Identifier != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.1"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.Identifier); } if (altId.AssigningAuthority != null) { terser.Set(String.Format("/QPD-3({0})-1", qpdRep), "@PID.21.4.1"); terser.Set(String.Format("/QPD-3({0})-2", qpdRep++), altId.AssigningAuthority); } } } return(retVal); }
/// <summary> /// Get record /// </summary> private HealthServiceRecordContainer GetRecord(VersionedDomainIdentifier recordId, List <IResultDetail> dtls, RegistryQueryRequest qd) { try { // Can't find persistence if (this.m_persistenceService == null) { dtls.Add(new PersistenceResultDetail(ResultDetailType.Error, "Couldn't locate an implementation of a PersistenceService object, storage is aborted", null)); throw new Exception("Cannot de-persist records"); } // Read the record from the DB var result = this.m_persistenceService.GetContainer(recordId, qd.IsSummary) as HealthServiceRecordContainer; // Does this result match what we're looking for? if (result == null) { return(null); // next record } // Calculate the matching algorithm Person subject; if (result is Person) { subject = result as Person; } else { subject = result.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf) as Person; } // Remove all but the alternate identifiers specifed in the query if (qd.TargetDomain != null && subject != null) { subject.AlternateIdentifiers.RemoveAll(o => !qd.TargetDomain.Exists(t => t.Domain.Equals(o.Domain))); if (subject.AlternateIdentifiers.Count == 0) { return(null); } } if (subject != null && qd.QueryRequest != null) { var filter = qd.QueryRequest.FindComponent(HealthServiceRecordSiteRoleType.SubjectOf); while (!(filter is Person) && filter != null) { filter = (filter as HealthServiceRecordContainer).FindComponent(HealthServiceRecordSiteRoleType.SubjectOf); } var confidence = (subject as Person).Confidence(filter as Person); if (confidence.Confidence < qd.MinimumDegreeMatch) { return(null); } subject.Add(confidence, "CONF", HealthServiceRecordSiteRoleType.ComponentOf | HealthServiceRecordSiteRoleType.CommentOn, null); } // Mask if (this.m_policyService != null) { var dte = new List <SVC.Core.Issues.DetectedIssue>(); result = this.m_policyService.ApplyPolicies(qd.QueryRequest, result, dte) as HealthServiceRecordContainer; foreach (var itm in dte) { dtls.Add(new DetectedIssueResultDetail( ResultDetailType.Warning, itm.Text, (string)null, itm)); } } return(result); } catch (Exception ex) { dtls.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); return(null); } }
/// <summary> /// Query for a series of results which match the query parameter /// </summary> public RegistryQueryResult Query(RegistryQueryRequest query) { RegistryQueryResult retVal = new RegistryQueryResult(); try { List <VersionedDomainIdentifier> returnedRecordIdentifiers = new List <VersionedDomainIdentifier>(100); // Query continuation? if (this.m_registrationService == null) { throw new InvalidOperationException("No record registration service is registered. Querying for records cannot be done unless this service is configured"); } else if (query.IsContinue) // Continuation { // Sanity check, ensure the query exists! if (this.m_queryPersistence == null || !this.m_queryPersistence.IsRegistered(query.QueryId)) { retVal.Details.Add(new ValidationResultDetail(ResultDetailType.Error, String.Format("The query {0} has not been registered", query.QueryId), null, null)); throw new InvalidOperationException("Cannot conitnue query due to errors"); } // sanity check // Validate the sender RegistryQueryRequest queryTag = (RegistryQueryRequest)this.m_queryPersistence.GetQueryTag(query.QueryId); retVal.OriginalRequestId = queryTag.OriginalMessageQueryId; if (query.Originator != queryTag.Originator) { retVal.Details.Add(new UnrecognizedSenderResultDetail(new DomainIdentifier() { Domain = query.Originator })); throw new SecurityException("Sender mismatch"); } // Return value retVal.Results = this.GetRecordsAsync(this.m_queryPersistence.GetQueryResults(query.QueryId, query.Offset, query.Limit), returnedRecordIdentifiers, query, retVal.Details); // Return continued query retVal.TotalResults = (int)this.m_queryPersistence.QueryResultTotalQuantity(query.QueryId); } else if (this.m_queryPersistence != null && this.m_queryPersistence.IsRegistered(query.QueryId) && !query.IsContinue) { throw new Exception(String.Format("The query '{0}' has already been registered. To continue this query use the appropriate interaction", query.QueryId)); } else { VersionedDomainIdentifier[] recordIds = this.m_registrationService.QueryRecord(query.QueryRequest as QueryEvent); // Persist the query if (!String.IsNullOrEmpty(query.QueryId) && this.m_queryPersistence != null && recordIds.Length > query.Limit) { this.m_queryPersistence.RegisterQuerySet(query.QueryId, recordIds, query); this.m_queryPersistence.GetQueryResults(query.QueryId, query.Offset, query.Limit); } retVal.TotalResults = recordIds.Length; // Get the results recordIds = recordIds.Skip(query.Offset).Take(query.Limit).ToArray(); retVal.Results = this.GetRecordsAsync(recordIds, returnedRecordIdentifiers, query, retVal.Details); if (retVal.Results.Count == 0 && query.IsSummary) { retVal.Details.Add(new PatientNotFoundResultDetail(this.m_localeService)); } // Sort control? TODO: Support sort control } retVal.ContinuationPtr = query.QueryId; retVal.QueryTag = query.QueryTag; return(retVal); } catch (TimeoutException ex) { retVal.Details.Add(new PersistenceResultDetail(Everest.Connectors.ResultDetailType.Error, ex.Message, ex)); throw; } catch (DbException ex) { retVal.Details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); throw; } catch (DataException ex) { retVal.Details.Add(new PersistenceResultDetail(ResultDetailType.Error, ex.Message, ex)); throw; } catch (Exception ex) { retVal.Details.Add(new ResultDetail(ResultDetailType.Error, ex.Message, ex)); throw; } }
/// <summary> /// Get records asynchronously /// </summary> private List <HealthServiceRecordContainer> GetRecordsAsync(VersionedDomainIdentifier[] recordIds, List <VersionedDomainIdentifier> retRecordId, RegistryQueryRequest qd, List <IResultDetail> dtls) { // Decision Support service HealthServiceRecordContainer[] retVal = new HealthServiceRecordContainer[qd.Limit < recordIds.Length ? qd.Limit : recordIds.Length]; retRecordId.AddRange(recordIds); List <VersionedDomainIdentifier> recordFetch = new List <VersionedDomainIdentifier>(retVal.Length); // Get the number of records to include for (int i = 0; i < retVal.Length; i++) { recordFetch.Add(recordIds[i]); } int maxWorkerBees = recordFetch.Count < Environment.ProcessorCount * 2 ? recordFetch.Count : Environment.ProcessorCount * 2; //List<Thread> workerBees = new List<Thread>(maxWorkerBees); // Worker bees var wtp = new MARC.Everest.Threading.WaitThreadPool(maxWorkerBees); try { //// Get components foreach (var id in recordFetch) { wtp.QueueUserWorkItem((WaitCallback) delegate(object parm) { List <IResultDetail> mDtls = new List <IResultDetail>(10); // DSS Service if (this.m_decisionSupportService != null) { foreach (var itm in this.m_decisionSupportService.RetrievingRecord(id)) { dtls.Add(new DetectedIssueResultDetail( itm.Priority == SVC.Core.Issues.IssuePriorityType.Error ? ResultDetailType.Error : itm.Priority == SVC.Core.Issues.IssuePriorityType.Warning ? ResultDetailType.Warning : ResultDetailType.Information, itm.Text, (string)null, itm)); } } var result = this.GetRecord(parm as VersionedDomainIdentifier, mDtls, qd); // Process result if (result != null) { // DSS Service if (this.m_decisionSupportService != null) { foreach (var itm in this.m_decisionSupportService.RetrievedRecord(result)) { dtls.Add(new DetectedIssueResultDetail( itm.Priority == SVC.Core.Issues.IssuePriorityType.Error ? ResultDetailType.Error : itm.Priority == SVC.Core.Issues.IssuePriorityType.Warning ? ResultDetailType.Warning : ResultDetailType.Information, itm.Text, (String)null, itm)); } } // Add to the results lock (this.m_syncLock) { // Add return value if (retRecordId.IndexOf(parm as VersionedDomainIdentifier) < retVal.Length) { retVal[retRecordId.IndexOf(parm as VersionedDomainIdentifier)] = result; } } } else { dtls.Add(new DetectedIssueResultDetail( ResultDetailType.Warning, String.Format("Record '{1}^^^&{0}&ISO' will not be retrieved", id.Domain, (parm as VersionedDomainIdentifier).Identifier), (string)null, new DetectedIssue() { Priority = IssuePriorityType.Warning, Severity = IssueSeverityType.Moderate, Text = String.Format("Record '{1}^^^&{0}&ISO' will not be retrieved", id.Domain, (parm as VersionedDomainIdentifier).Identifier), Type = IssueType.DetectedIssue })); } // Are we disclosing this record? if (result == null || result.IsMasked) { lock (m_syncLock) retRecordId.Remove(parm as VersionedDomainIdentifier); } // Add issues and details lock (m_syncLock) { dtls.AddRange(mDtls); } }, id ); } // Wait for return // TODO: Move this to a configuration parameter bool didReturn = wtp.WaitOne(50000, true); if (!didReturn) { throw new TimeoutException("The query could not complete in the specified amount of time"); } } finally { wtp.Dispose(); } return(new List <HealthServiceRecordContainer>(retVal)); }