/// <summary> /// Find all entries in a Bundle that match the given reference. /// </summary> /// <param name="bundle">Bundle to search in</param> /// <param name="reference">An absolute reference to match against the fullUrl of the entries in the bundle</param> /// <param name="includeDeleted">Whether to include deleted entries in the search. Optional.</param> /// <returns>A list of Resources with the given identity, or an empty list if none were found.</returns> public static IEnumerable <Bundle.BundleEntryComponent> FindEntry(this Bundle bundle, string reference, bool includeDeleted = false) { if (reference == null) { throw Error.ArgumentNull("reference"); } if (bundle.Entry == null) { return(Enumerable.Empty <Bundle.BundleEntryComponent>()); } if (!new Uri(reference, UriKind.RelativeOrAbsolute).IsAbsoluteUri) { throw Error.Argument("reference", "uri should be absolute"); } string referencedVersion = ResourceIdentity.IsRestResourceIdentity(reference) ? (new ResourceIdentity(reference).VersionId) : null; reference = referencedVersion != null ? (new ResourceIdentity(reference).WithoutVersion().ToString()) : reference; var refRestUrl = new RestUrl(reference); var result = bundle.Entry.Where(be => new RestUrl(be.FullUrl).IsSameUrl(refRestUrl) && (includeDeleted == true || !be.IsDeleted())); if (referencedVersion != null) { result = result.Where(be => be.HasResource() && be.Resource.Meta.VersionId == referencedVersion); } return(result); }
public Hl7.Fhir.Model.Resource ResolveByUri(string uri) { if (uri == null) { throw Error.ArgumentNull(nameof(uri)); } if (!ResourceIdentity.IsRestResourceIdentity(uri)) { return(null); // Weakness in FhirClient, need to have the base :-( So return null if we cannot determine it. } var id = new ResourceIdentity(uri); // [WMR 20150810] Use custom FhirClient factory if specified var client = _clientFactory != null?_clientFactory(id.BaseUri) : new FhirClient(id.BaseUri) { Timeout = 5000 }; try { var resultResource = client.Read <Resource>(id); resultResource.SetOrigin(uri); return(resultResource); } catch (FhirOperationException) { return(null); } catch (WebException) { return(null); } }
public Hl7.Fhir.Model.Resource LoadConformanceResourceByUrl(string url) { if (url == null) { throw Error.ArgumentNull("identifier"); } if (!ResourceIdentity.IsRestResourceIdentity(url)) { return(null); // Weakness in FhirClient, need to have the base :-( So return null if we cannot determine it. } var id = new ResourceIdentity(url); // [WMR 20150810] Use custom FhirClient factory if specified var client = _clientFactory != null?_clientFactory(id.BaseUri) : new FhirClient(id.BaseUri) { Timeout = 5000 }; try { return(client.Read <Resource>(id)); } catch (FhirOperationException) { return(null); } catch (WebException) { return(null); } }
public void TestIsResourceId() { Assert.IsTrue(ResourceIdentity.IsRestResourceIdentity("Patient/4")); Assert.IsTrue(ResourceIdentity.IsRestResourceIdentity("Patient/4/_history/5")); Assert.IsTrue(ResourceIdentity.IsRestResourceIdentity("http://nu.nl/fhir/Patient/4")); Assert.IsFalse(ResourceIdentity.IsRestResourceIdentity("http://nu.nl/fhir/crap")); Assert.IsFalse(ResourceIdentity.IsRestResourceIdentity("x/y/z/4")); Assert.IsFalse(ResourceIdentity.IsRestResourceIdentity("urn:oid:1.2.3.4.5")); }
/// <summary> /// Scan all xml files found by prepareFiles and find conformance resources + their id /// </summary> private void prepareResources() { if (_resourcesPrepared) { return; } prepareFiles(); _resourceInformation = new List <ConformanceInformation>(); foreach (var file in _artifactFilePaths.Where(af => Path.GetExtension(af) == ".xml")) { if (file.EndsWith("dataelements.xml")) { continue; // buggy file } try { var conformanceResources = readInformationFromFile(file).Where(ci => ResourceIdentity.IsRestResourceIdentity(ci.Url) && ModelInfo.IsConformanceResource((new ResourceIdentity(ci.Url)).ResourceType)); _resourceInformation.AddRange(conformanceResources); } catch (XmlException) { throw; } } // Check for duplicate canonical urls, this is forbidden within a single source (and actually, universally, // but if another source has the same url, the order of polling in the MultiArtifactSource matters) var doubles = _resourceInformation.Where(ci => ci.Url != null).GroupBy(ci => ci.Url).Where(group => group.Count() > 1); if (doubles.Any()) { throw Error.InvalidOperation("The source has found multiple Conformance Resource artifacts with the same canonical url: {0} appears at {1}" .FormatWith(doubles.First().Key, String.Join(", ", doubles.First().Select(hit => hit.Origin)))); } _resourcesPrepared = true; }
public Resource ResolveByUri(string uri) { if (uri == null) { throw Error.ArgumentNull(nameof(uri)); } if (!ResourceIdentity.IsRestResourceIdentity(uri)) { // Weakness in FhirClient, need to have the base :-( So return null if we cannot determine it. return(null); } var id = new ResourceIdentity(uri); var client = _clientFactory?.Invoke(id.BaseUri) ?? new FhirClient(id.BaseUri) { Timeout = this.TimeOut }; client.ParserSettings = this.ParserSettings; try { var resultResource = client.Read <Resource>(id); resultResource.SetOrigin(uri); LastError = null; return(resultResource); } catch (FhirOperationException foe) { LastError = foe; return(null); } catch (WebException we) { LastError = we; return(null); } // Other runtime exceptions are fatal... }
public static bool IsTargetOf(this Bundle.BundleEntryComponent entry, string reference) { // From the spec: If the reference is version specific (either relative or absolute), then remove the version from the URL // before matching fullUrl, and then match the version based on Resource.meta.versionId. if (reference == null) { throw Error.ArgumentNull("reference"); } if (!new Uri(reference, UriKind.RelativeOrAbsolute).IsAbsoluteUri) { throw Error.Argument("reference", "uri should be absolute"); } string referencedVersion = ResourceIdentity.IsRestResourceIdentity(reference) ? (new ResourceIdentity(reference).VersionId) : null; reference = referencedVersion != null ? (new ResourceIdentity(reference).WithoutVersion().ToString()) : reference; var refRestUrl = new RestUrl(reference); return(refRestUrl.IsSameUrl(new RestUrl(entry.FullUrl)) && (referencedVersion == null || (entry.HasResource() && entry.Resource.VersionId == referencedVersion))); }
// Process request and craft response. public override CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback) { if (request.Method == "OPTIONS") { // This is the CORS request, and that's good base.StatusCode = 200; // base.Headers.Add("Access-Control-Allow-Origin", "*"); base.Headers.Add("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS"); base.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, authorization"); callback.Continue(); return(CefReturnValue.Continue); } var uri = new Uri(request.Url); Console.WriteLine($"-----------------\r\n{request.Url}"); // Check the bearer header if (!string.IsNullOrEmpty(_launchContext.Bearer)) { string bearer = request.GetHeaderByName("authorization"); if (bearer != "Bearer " + _launchContext.Bearer) { base.StatusCode = (int)HttpStatusCode.Unauthorized; callback.Continue(); return(CefReturnValue.Continue); } } try { // This is a regular request Hl7.Fhir.Rest.FhirClient server = new Hl7.Fhir.Rest.FhirClient("http://localhost:4178"); server.OnAfterResponse += (sender, args) => { base.Charset = args.RawResponse.CharacterSet; foreach (string header in args.RawResponse.Headers.AllKeys) { base.Headers.Add(header, args.RawResponse.Headers[header]); } }; server.PreferredFormat = Hl7.Fhir.Rest.ResourceFormat.Json; string redirectedUrl = server.Endpoint.OriginalString.TrimEnd('/') + uri.PathAndQuery; System.Diagnostics.Trace.WriteLine($"{redirectedUrl}"); var headers = new List <KeyValuePair <string, IEnumerable <string> > >(); ModelBaseInputs <IServiceProvider> requestDetails = new ModelBaseInputs <IServiceProvider>(null, null, request.Method, uri, new Uri($"https://{AuthProtocolSchemeHandlerFactory.FhirFacadeAddress(_launchContext)}"), null, headers, null); if (request.Method == "GET") { if (uri.LocalPath == "/metadata") { _facade.GetConformance(requestDetails, Rest.SummaryType.False).ContinueWith <CapabilityStatement>(r => { if (r.Exception != null) { System.Diagnostics.Trace.WriteLine($"Error: {r.Exception.Message}"); if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) { base.StatusCode = (int)fe.Status; if (fe.Outcome != null) { base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); base.MimeType = "application/fhir+json"; } callback.Continue(); System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); return(null); } } base.StatusCode = 200; // As per the documentation http://hl7.org/fhir/smart-app-launch/conformance/index.html CapabilityStatement cs = r.Result; // Update the security node with our internal security node if (cs.Rest[0].Security == null) { cs.Rest[0].Security = new Hl7.Fhir.Model.CapabilityStatement.SecurityComponent(); } Hl7.Fhir.Model.CapabilityStatement.SecurityComponent security = cs.Rest[0].Security; if (!security.Service.Any(cc => cc.Coding.Any(c => c.System == "http://hl7.org/fhir/restful-security-service" && c.Code == "SMART-on-FHIR"))) { security.Service.Add(new Hl7.Fhir.Model.CodeableConcept("http://hl7.org/fhir/restful-security-service", "SMART-on-FHIR")); } var extension = security.GetExtension("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"); if (extension == null) { extension = new Extension() { Url = "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris" }; security.Extension.Add(extension); } // remove the existing authentications, and put in our own extension.Extension.Clear(); extension.AddExtension("token", new FhirUri($"https://{AuthProtocolSchemeHandlerFactory.AuthAddress(_launchContext)}/token")); extension.AddExtension("authorize", new FhirUri($"https://{AuthProtocolSchemeHandlerFactory.AuthAddress(_launchContext)}/authorize")); base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(r.Result)); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = "application/fhir+json"; callback.Continue(); return(r.Result); }); return(CefReturnValue.ContinueAsync); } if (!uri.LocalPath.StartsWith("/$") && !uri.LocalPath.StartsWith("/_") && uri.LocalPath.Length > 2) { // This is not an operation or history, so it must be a resource type string resourceType = uri.LocalPath.Substring(1); if (resourceType.Contains("/")) { resourceType = resourceType.Substring(0, resourceType.IndexOf("/")); } var rs = _facade.GetResourceService(requestDetails, resourceType); if (rs == null) { System.Diagnostics.Trace.WriteLine($"Error: resource type not handled {resourceType}"); base.StatusCode = (int)HttpStatusCode.BadRequest; // base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); // base.MimeType = "application/fhir+json"; callback.Continue(); return(CefReturnValue.Continue); } // GET for a specific resource ResourceIdentity ri = new ResourceIdentity(uri); if (ri.IsRestResourceIdentity()) { rs.Get(ri.Id, ri.VersionId, SummaryType.False).ContinueWith(r => { if (r.Exception != null) { System.Diagnostics.Trace.WriteLine($"Error: {r.Exception.Message}"); if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) { base.StatusCode = (int)fe.Status; if (fe.Outcome != null) { base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); base.MimeType = "application/fhir+json"; } callback.Continue(); System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); return(null); } } if (r.Result.HasAnnotation <HttpStatusCode>()) { base.StatusCode = (int)r.Result.Annotation <HttpStatusCode>(); } else { base.StatusCode = 200; } base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(r.Result)); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = "application/fhir+json"; callback.Continue(); return(r.Result); }); return(CefReturnValue.ContinueAsync); } // Search for the resource type var parameters = TupledParameters(uri, SearchQueryParameterNames); int?pagesize = GetIntParameter(uri, FhirParameter.COUNT); var summary = GetSummaryParameter(uri); rs.Search(parameters, pagesize, summary).ContinueWith(r => { if (r.Exception != null) { System.Diagnostics.Trace.WriteLine($"Error: {r.Exception.Message}"); if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) { base.StatusCode = (int)fe.Status; if (fe.Outcome != null) { base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); base.MimeType = "application/fhir+json"; } callback.Continue(); System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); return(null); } } if (r.Result.HasAnnotation <HttpStatusCode>()) { base.StatusCode = (int)r.Result.Annotation <HttpStatusCode>(); } else { base.StatusCode = 200; } base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(r.Result)); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = "application/fhir+json"; callback.Continue(); return(r.Result); }); return(CefReturnValue.ContinueAsync); } System.Threading.Tasks.Task <Hl7.Fhir.Model.Resource> t = server.GetAsync(redirectedUrl).ContinueWith <Hl7.Fhir.Model.Resource>(r => { if (r.Exception != null) { System.Diagnostics.Trace.WriteLine($"Error: {r.Exception.Message}"); if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) { base.StatusCode = (int)fe.Status; if (fe.Outcome != null) { base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); base.MimeType = "application/fhir+json"; } callback.Continue(); System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); return(null); } } base.StatusCode = 200; if (r.Result is Hl7.Fhir.Model.CapabilityStatement cs) { // As per the documentation http://hl7.org/fhir/smart-app-launch/conformance/index.html // Update the security node with our internal security node if (cs.Rest[0].Security == null) { cs.Rest[0].Security = new Hl7.Fhir.Model.CapabilityStatement.SecurityComponent(); } Hl7.Fhir.Model.CapabilityStatement.SecurityComponent security = cs.Rest[0].Security; if (!security.Service.Any(cc => cc.Coding.Any(c => c.System == "http://hl7.org/fhir/restful-security-service" && c.Code == "SMART-on-FHIR"))) { security.Service.Add(new Hl7.Fhir.Model.CodeableConcept("http://hl7.org/fhir/restful-security-service", "SMART-on-FHIR")); } var extension = security.GetExtension("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"); if (extension == null) { extension = new Extension() { Url = "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris" }; security.Extension.Add(extension); } // remove the existing authentications, and put in our own extension.Extension.Clear(); extension.AddExtension("token", new FhirUri($"https://{AuthProtocolSchemeHandlerFactory.AuthAddress(_launchContext)}/token")); extension.AddExtension("authorize", new FhirUri($"https://{AuthProtocolSchemeHandlerFactory.AuthAddress(_launchContext)}/authorize")); } base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(r.Result)); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = "application/fhir+json"; callback.Continue(); return(r.Result); }); } if (request.Method == "POST") { if (uri.LocalPath == "/") { Bundle b = null; if (request.PostData != null) { var data = request.PostData.Elements.FirstOrDefault(); var body = data.GetBody(); if (request.GetHeaderByName("Content-Type").Contains("xml")) { b = new Hl7.Fhir.Serialization.FhirXmlParser().Parse <Bundle>(body); } else { b = new Hl7.Fhir.Serialization.FhirJsonParser().Parse <Bundle>(body); } } _facade.ProcessBatch(requestDetails, b).ContinueWith(r => { if (r.Exception != null) { System.Diagnostics.Trace.WriteLine($"Error: {r.Exception.Message}"); if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) { base.StatusCode = (int)fe.Status; if (fe.Outcome != null) { base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(fe.Outcome)); base.MimeType = "application/fhir+json"; } callback.Continue(); System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); return(null); } } if (r.Result.HasAnnotation <HttpStatusCode>()) { base.StatusCode = (int)r.Result.Annotation <HttpStatusCode>(); } else { base.StatusCode = 200; } base.Stream = new MemoryStream(new Hl7.Fhir.Serialization.FhirJsonSerializer(new Hl7.Fhir.Serialization.SerializerSettings() { Pretty = true }).SerializeToBytes(r.Result)); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = "application/fhir+json"; callback.Continue(); return(r.Result); }); return(CefReturnValue.ContinueAsync); } System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(); client.DefaultRequestHeaders.Add("Accept", request.GetHeaderByName("Accept")); // client.DefaultRequestHeaders.Add("Content-Type", request.GetHeaderByName("Content-Type")); HttpContent content = null; if (request.PostData != null) { var data = request.PostData.Elements.FirstOrDefault(); var body = data.GetBody(); content = new System.Net.Http.StringContent(body, System.Text.Encoding.UTF8, request.GetHeaderByName("Content-Type")); } else { content = new System.Net.Http.StreamContent(null); } client.PostAsync(redirectedUrl, content).ContinueWith((System.Threading.Tasks.Task <HttpResponseMessage> r) => { if (r.Exception != null) { Console.WriteLine($"Error: {r.Exception.Message}"); //if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) //{ // base.StatusCode = (int)fe.Status; // if (fe.Outcome != null) // base.Stream = new MemoryStream(r.Result.Content.ReadAsStringAsync().GetAwaiter().GetResult()); // callback.Continue(); // System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); // return; //} } base.StatusCode = (int)r.Result.StatusCode; base.Stream = r.Result.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = r.Result.Content.Headers.ContentType.MediaType; callback.Continue(); return; }); } if (request.Method == "PUT") { System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(); client.DefaultRequestHeaders.Add("Accept", request.GetHeaderByName("Accept")); // client.DefaultRequestHeaders.Add("Content-Type", request.GetHeaderByName("Content-Type")); HttpContent content = null; if (request.PostData != null) { var data = request.PostData.Elements.FirstOrDefault(); var body = data.GetBody(); content = new System.Net.Http.StringContent(body, System.Text.Encoding.UTF8, request.GetHeaderByName("Content-Type")); } else { content = new System.Net.Http.StreamContent(null); } client.PutAsync(redirectedUrl, content).ContinueWith((System.Threading.Tasks.Task <HttpResponseMessage> r) => { if (r.Exception != null) { Console.WriteLine($"Error: {r.Exception.Message}"); //if (r.Exception.InnerException is Hl7.Fhir.Rest.FhirOperationException fe) //{ // base.StatusCode = (int)fe.Status; // if (fe.Outcome != null) // base.Stream = new MemoryStream(r.Result.Content.ReadAsStringAsync().GetAwaiter().GetResult()); // callback.Continue(); // System.Diagnostics.Trace.WriteLine($"Error (inner): {fe.Message}"); // return; //} } base.StatusCode = (int)r.Result.StatusCode; base.Stream = r.Result.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); Console.WriteLine($"Success: {base.Stream.Length}"); base.MimeType = r.Result.Content.Headers.ContentType.MediaType; callback.Continue(); return; }); } return(CefReturnValue.ContinueAsync); } catch (Exception ex) { Console.WriteLine($"{ex.Message}"); callback.Dispose(); return(CefReturnValue.Cancel); } }