예제 #1
0
        public OpenEhrToFhirAdapterBase ProcessMessage(string message)
        {
            // get all classes which inherit OpenEhrToFhirAdapterBase
            // (this gets all adapters and passes the message into the adapter constructor which automatically processes the message using that adapter)
            var adapters = ReflectionHelper.GetEnumerableOfType <OpenEhrToFhirAdapterBase>(message);

            // set default highest confidence
            var highestConfidence = 0.0;

            // set default chosenOpenEhrToFhirAdapter
            OpenEhrToFhirAdapterBase chosenOpenEhrToFhirAdapter = null;

            // loop through all adapters
            foreach (var adapter in adapters)
            {
                // check if the confidence score of this adapter is higher than the current
                if (adapter.ConfidenceScore > highestConfidence || chosenOpenEhrToFhirAdapter == null)
                {
                    // set the current highest confidence score
                    highestConfidence = adapter.ConfidenceScore;
                    // set the current adapter
                    chosenOpenEhrToFhirAdapter = adapter;
                }
            }

            // log some info
            //Log.Info($"Received message and selected adapter: {chosenOpenEhrToFhirAdapter?.AdapterName} with confidence of {chosenOpenEhrToFhirAdapter?.ConfidenceScore}%.\n");

            // return the chosen adapter
            return(chosenOpenEhrToFhirAdapter);
        }
예제 #2
0
        public override OpenEhrToFhirAdapterBase ProcessMappings(OpenEhrToFhirAdapterBase adapter)
        {
            foreach (var mapping in adapter.Mappings.Where(x => x.MappingType == MappingType.Resource))
            {
                // calculate number of resources of this type are required
                var number = adapter.OpenEhrRecord.FindMany(mapping, new List <Component>()).Count;

                for (var i = 0; i < number; i++)
                {
                    var resource = (Resource)Activator.CreateInstance("Hl7.Fhir.STU3.Core", "Hl7.Fhir.Model." + ((ResourceMapping)mapping).ResourceTargetType).Unwrap();
                    adapter.ResourceList.Add(resource);
                    //Log.Info($"Added resource of type {resource.GetType().Name} to  ResourceList[{adapter.ResourceList.Count - 1}].");
                }
            }
            return(adapter);
        }
예제 #3
0
        public override OpenEhrToFhirAdapterBase ProcessMappings(OpenEhrToFhirAdapterBase adapter)
        {
            foreach (var mapping in adapter.Mappings.Where(x => x.MappingType == MappingType.Extension))
            {
                var nodes = adapter.OpenEhrRecord.FindMany(mapping, new List <Component>());

                // 2.2 Work out destination of this mapping item
                foreach (var node in nodes)
                {
                    // check if the current node has been processed already
                    if (adapter.ProcessedNodes.Contains(node))
                    {
                        continue;
                    }

                    // get the resource that this node should be mapped to
                    var rootResourceIndex = node.ParentResourceIndex(adapter.Mappings);

                    // if this node has no parent resource index then we skip it
                    if (rootResourceIndex == int.MinValue)
                    {
                        continue;
                    }

                    // Get parent object of attribute
                    var resourceRoot = adapter.ResourceList[rootResourceIndex];

                    // gets the reference to a fhir field and also returns the index of the field if the field is a list item
                    // if val is not null here then it means the field has been instantiated by a list node mapping operation and must be part of a list
                    // if val is null then it means the field has not been instantiated previously.
                    var oldValue = GetFhirObject(resourceRoot, adapter, node, out _);

                    // constructs the value to place at the target field location
                    var newValue = ConstructNewTargetValue(adapter, node, mapping, oldValue);

                    // updates the target field in the fhir resource and returns the updated adapter
                    adapter = SetFhirValue(resourceRoot, adapter, node, newValue, oldValue);
                }
            }

            return(adapter);
        }
예제 #4
0
        public override OpenEhrToFhirAdapterBase ProcessMappings(OpenEhrToFhirAdapterBase adapter)
        {
            foreach (var mapping in adapter.Mappings.Where(x => x.MappingType == MappingType.Conditional))
            {
                var nodes = adapter.OpenEhrRecord.FindMany(mapping, new List <Component>());

                // 2.2 Work out destination of this mapping item
                foreach (var node in nodes)
                {
                    // check if the current node has been processed already
                    if (adapter.ProcessedNodes.Contains(node))
                    {
                        continue;
                    }

                    // get the resource that this node should be mapped to
                    var rootResourceIndex = node.ParentResourceIndex(adapter.Mappings);

                    // if this node has no parent resource index then we skip it
                    if (rootResourceIndex == int.MinValue)
                    {
                        continue;
                    }

                    // Get parent object of attribute
                    var resourceRoot = adapter.ResourceList[rootResourceIndex];

                    var oldValue = GetFhirObject(resourceRoot, adapter, node, out var index);

                    // constructs the value to place at the target field location
                    var newValue = ConstructNewTargetValue(adapter, node, mapping, oldValue);

                    adapter = SetFhirValue(resourceRoot, adapter, node, newValue, oldValue, index);
                }
            }

            return(adapter);
        }
예제 #5
0
        /// <summary>
        /// gets the reference to a fhir field and also returns the index of the field if the field is a list item
        /// if oldValue is not null here then it means the field has been instantiated by a list node mapping operation and must be part of a list
        /// if oldValue is null then it means the field has not been instantiated previously.
        /// </summary>
        /// <param name="resourceRoot">The root resource to be searched i.e. AllergyIntolerance, Patient etc.</param>
        /// <param name="adapter">The adapter currently being used.</param>
        /// <param name="node">The current node being used in the process mapping method.</param>
        /// <param name="index">If the value of the field is inside a list then it's index in the list will be returned.</param>
        /// <returns>Returns the object found at the search location, also returns the index of the field if the field is a list item.</returns>
        public object GetFhirObject(Resource resourceRoot, OpenEhrToFhirAdapterBase adapter, Component node, out int index)
        {
            // get the path inside the resource where this property should be set
            var finalRoute = node.InnerNetPath(adapter.Mappings);

            if (string.IsNullOrEmpty(finalRoute))
            {
                finalRoute = node.NetPath(adapter.Mappings);
            }

            // get the index of the parent list to put the property inside
            var start = finalRoute.LastIndexOf('[') + 1;
            var end   = finalRoute.LastIndexOf(']');

            index = int.MinValue;
            if (start != -1 && end != -1)
            {
                var indexStr = finalRoute.Substring(start, end - start);
                if (!int.TryParse(indexStr, out index))
                {
                    throw new Exception("Failed to parse index.");
                }
            }

            if (finalRoute.Split('.').Last().EndsWith("]"))
            {
                finalRoute = finalRoute.Remove(finalRoute.LastIndexOf('['));
            }

            var value = resourceRoot.GetPropertyValue(finalRoute);

            if (value == null)
            {
                // recursively check through all properties for one matching the end node of the mapping
            }

            return(value);
        }
예제 #6
0
        public override OpenEhrToFhirAdapterBase ProcessMappings(OpenEhrToFhirAdapterBase adapter)
        {
            foreach (var mapping in adapter.Mappings.Where(x => x.MappingType == MappingType.List))
            {
                var listNodes = adapter.OpenEhrRecord.FindMany(mapping, new List <Component>());

                foreach (var node in listNodes)
                {
                    var netPath      = node.NetPath(adapter.Mappings);
                    var innerNetPath = node.InnerNetPath(adapter.Mappings);

                    var pi = adapter.GetPropertyInfo(netPath);

                    var componentType       = pi.PropertyType.GetGenericArguments()[0];
                    var constructedListType = typeof(List <>).MakeGenericType(componentType);
                    var listInstance        = (IList)Activator.CreateInstance(constructedListType);

                    var subNodes = ((Composite)node.Parent).FindMany(mapping, new List <Component>()).ToList();

                    var counter = 0;
                    while (counter < subNodes.Count)
                    {
                        var subNode = subNodes[counter];

                        if (Regex.Match(subNode.Name, ":\\d+\\|+").Success)
                        {
                            var regex = $"{subNode.Name.Split(':')[0]}:{subNode.ListIndex}+\\|+";

                            var siblings = subNodes.Where(x =>
                                                          Regex.Match(x.Name, regex).Success &&
                                                          x.ParentResourceIndex(adapter.Mappings) == subNode.ParentResourceIndex(adapter.Mappings)).ToList();

                            var passes = siblings.DistinctBy(x => x.Parent.NetPath(adapter.Mappings)).Count();

                            for (var i = 0; i < passes; i++)
                            {
                                var system = (Composite)siblings.Where(x => x.Name.Contains("terminology")).ToList()[i];
                                var code   = (Composite)siblings.Where(x => x.Name.Contains("code")).ToList()[i];
                                var text   = (Composite)siblings.Where(x => x.Name.Contains("value")).ToList()[i];

                                if (system != null)
                                {
                                    counter++;
                                }
                                if (code != null)
                                {
                                    counter++;
                                }
                                if (text != null)
                                {
                                    counter++;
                                }

                                listInstance.Add(Activator.CreateInstance(componentType, null));
                            }
                        }
                        else
                        {
                            counter++;
                            listInstance.Add(Activator.CreateInstance(componentType, null));
                        }
                    }

                    var obj = adapter.GetPropertyValue(netPath);
                    if (!ReflectionHelper.SetValue(obj, innerNetPath, listInstance))
                    {
                        var innerPi = adapter.GetPropertyInfo(netPath);
                        obj = adapter.GetPropertyValue(netPath.Remove(netPath.LastIndexOf('.')));
                        try
                        {
                            innerPi.SetValue(obj, listInstance);
                        }
                        catch
                        {
                            //Log.Error($"Failed to map list {mapping.OpenEhrFieldPath} to {mapping.FhirFieldPath}.");
                        }
                    }
                }
            }

            return(adapter);
        }
예제 #7
0
        /// <summary>
        /// Constructs the object which will be placed at the target FHIR location according the mapping rules and openEHR message values.
        /// </summary>
        /// <param name="adapter">The current adapter being processed.</param>
        /// <param name="node">The current node being processed.</param>
        /// <returns>Returns the constructed value to be placed at the target FHIR location.</returns>
        public object ConstructNewTargetValue(OpenEhrToFhirAdapterBase adapter, Component node, BaseMapping mapping, object oldValue = null)
        {
            object newTargetValue = null;

            // fhir resource destination
            var destination = node.NetPath(adapter.Mappings);

            // list + CodeableConcept combined logic i.e. substance:0|code or substance|code
            if (Regex.Match(node.Name, ":\\d+\\|+").Success ||
                Regex.Match(node.Name, $"{mapping.OpenEhrFieldPath}\\|+").Success ||
                Regex.Match(node.Name, $"{mapping.OpenEhrFieldPath}:\\d+").Success)
            {
                // Get all components of this codeable concept
                var siblingNodes = ((Composite)node.Parent).FindMany(mapping, new List <Component>()).Where(x => x.NetPath(adapter.Mappings) == destination).ToList();

                var system = ((Composite)siblingNodes.FirstOrDefault(x => x.Name.Contains("terminology")))?.Children[0].Name;
                var code   = ((Composite)siblingNodes.FirstOrDefault(x => x.Name.Contains("code")))?.Children[0].Name;
                var text   = ((Composite)siblingNodes.FirstOrDefault(x => x.Name.Contains("value")))?.Children[0].Name;

                if (system == null && code == null && text == null)
                {
                    newTargetValue = StringHelper.ParseOpenEhrCcString(((Composite)node).Children.First().Name);
                }
                else
                {
                    newTargetValue = new CodeableConcept(system, code, text);
                }

                if (GetType() == typeof(ConditionalMapping))
                {
                    // the type of codeable concept type to search for i.e. Terminology/Code/Value
                    var conditionalSearchType = ((ConditionalMapping)mapping).Conditions.First().Item1;

                    // the actual value to search for in order to match the conditional mapping
                    var conditionalSearchValue = string.Empty;

                    switch (conditionalSearchType)
                    {
                    case "code":
                    {
                        conditionalSearchValue = code;
                        break;
                    }

                    case "terminology":
                    {
                        conditionalSearchValue = system;
                        break;
                    }

                    case "value":
                    {
                        conditionalSearchValue = text;
                        break;
                    }
                    }

                    var metConditions = ((ConditionalMapping)mapping).Conditions.Where(x =>
                                                                                       string.Equals(x.Item2, conditionalSearchValue, StringComparison.InvariantCultureIgnoreCase))
                                        .ToList();

                    var destinationIsCollection = oldValue is IEnumerable;
                    if (destinationIsCollection)
                    {
                        if (((IList)oldValue).Count == 0)
                        {
                            var listGenericType = oldValue.GetType().GenericTypeArguments[0];
                            var codeGenericType = metConditions[0].Item3.GetType();
                            var list            = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(listGenericType), null);
                            foreach (var metCondition in metConditions)
                            {
                                var obj = Activator.CreateInstance(typeof(Code <>).MakeGenericType(codeGenericType), metCondition.Item3);
                                list.Add(obj);
                            }

                            newTargetValue = list;
                        }
                    }
                    else
                    {
                        newTargetValue = metConditions[0].Item3;
                    }
                }
                else if (GetType() == typeof(ExtensionMapping))
                {
                    if (oldValue != null)
                    {
                        ((List <Extension>)oldValue).Add(new Extension(
                                                             ((ExtensionMapping)mapping).ExtensionFhirStructureDefinitionUrl,
                                                             new CodeableConcept(system, code, text)));
                        newTargetValue = oldValue;
                    }
                }

                // mark these nodes as processed so skip duplicate processing
                adapter.ProcessedNodes.AddRange(siblingNodes);
            }
            else
            {
                var siblingNodes = ((Composite)node.Parent).FindMany(mapping, new List <Component>()).Where(x => x.NetPath(adapter.Mappings) == destination).ToList();

                if (GetType() == typeof(ExtensionMapping))
                {
                    var childLeafValue = ((Composite)node).Children[0] as Composite;
                    ((List <Extension>)oldValue).Add(new Extension(((ExtensionMapping)mapping).ExtensionFhirStructureDefinitionUrl, new FhirString(childLeafValue?.Children[0].Name)));
                    newTargetValue = oldValue;
                }
                else
                {
                    if (siblingNodes.Count == 1)
                    {
                        newTargetValue = StringHelper.ParseOpenEhrCcString(((Composite)siblingNodes[0]).Children[0].Name);
                    }
                    else
                    {
                        var index  = node.ParentResourceIndex(adapter.Mappings);
                        var t_node = (Composite)siblingNodes.Where(x => x.NetPath(adapter.Mappings) == destination).ToList()[index];
                        newTargetValue = StringHelper.ParseOpenEhrCcString(t_node.Children[0].Name);
                    }
                }

                adapter.ProcessedNodes.AddRange(siblingNodes);
            }

            return(newTargetValue);
        }
예제 #8
0
 /// <summary>
 /// Execute the processing of this mapping type.
 /// </summary>
 /// <param name="adapter">The adapter adapter which contains the mappings you want to execute.</param>
 /// <returns>An updated version of the adapter containing the results of the executed mappings.</returns>
 public abstract OpenEhrToFhirAdapterBase ProcessMappings(OpenEhrToFhirAdapterBase adapter);
예제 #9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="resourceRoot"></param>
        /// <param name="adapter"></param>
        /// <param name="node"></param>
        /// <param name="newValue"></param>
        /// <param name="oldValue"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public OpenEhrToFhirAdapterBase SetFhirValue(Resource resourceRoot, OpenEhrToFhirAdapterBase adapter, Component node, object newValue, object oldValue = null, int index = int.MinValue)
        {
            var points = 1;

            // setting a not null property which is inside a list
            if (oldValue != null && index != int.MinValue)
            {
                var setListItemMethod = oldValue.GetType().GetMethod("set_Item");

                if (setListItemMethod != null)
                {
                    setListItemMethod.Invoke(oldValue, new[] { index, newValue });

                    adapter.SuccessfulMappingCount += points;

                    //Log.Info($"Mapped {GetType().Name} from {OpenEhrFieldPath} to {node.InnerNetPath(adapter.Mappings)} & yielded +{points} for total of {adapter.SuccessfulMappingCount} successes for this adapter.");
                }
            }
            // setting a null property which is not in a list
            else
            {
                var childPathFromParent = node.InnerNetPath(adapter.Mappings);

                object parentObject;

                if (childPathFromParent.LastIndexOf('.') < 0)
                {
                    parentObject = resourceRoot;
                }
                else
                {
                    var parentObjectPath = childPathFromParent.Remove(childPathFromParent.LastIndexOf('.'));
                    parentObject = resourceRoot.GetPropertyValue(parentObjectPath);
                }

                // get the property name that we want to set
                var childProperty = childPathFromParent.Split('.').Last();

                // set codeable concept in parent object which isn't at the root resource i.e. Resource.Property[0].AnotherProperty[1]
                if (ReflectionHelper.SetValue(parentObject, childProperty, newValue))
                {
                    adapter.SuccessfulMappingCount += points;
                }
                // set primitive data type in parent object which isn't at the root resource i.e. Resource.Property[0].AnotherProperty
                else if (ReflectionHelper.SetValue(parentObject, childProperty, ((Composite)node).Children[0].Name))
                {
                    adapter.SuccessfulMappingCount += points;
                }
                // set primitive data type in parent object which is at the root resource i.e. Resource.Property
                else
                {
                    if (ReflectionHelper.SetValue(resourceRoot, childProperty, ((Composite)node).Children[0].Name))
                    {
                        adapter.SuccessfulMappingCount += points;
                    }
                    else
                    {
                        //Log.Error($"Failed to map attribute with mapping {OpenEhrFieldPath} to {FhirFieldPath}.");
                    }
                }

                //Log.Info($"Mapped {GetType().Name} from {OpenEhrFieldPath} to {childPathFromParent} & yielded +{points} for total of {adapter.SuccessfulMappingCount} successes for this adapter.");
            }

            return(adapter);
        }