edu.harvard.i2b2.fhir.FhirUtil.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.i2b2.fhir.FhirUtil.java

Source

/*
 * Copyright (c) 2006-2007 Massachusetts General Hospital 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the i2b2 Software License v1.0 
 * which accompanies this distribution. 
 * 
 * Contributors:
 *       Kavishwar Wagholikar (kavi)
 *       July 4, 2015
 */

/*
 * Copyright (c) 2006-2007 Massachusetts General Hospital 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the i2b2 Software License v1.0 
 * which accompanies this distribution. 
 * 
 * Contributors:
 *       Kavishwar Wagholikar (kavi)
 *       July 4, 2015
 */

/*
 * Copyright (c) 2006-2007 Massachusetts General Hospital 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the i2b2 Software License v1.0 
 * which accompanies this distribution. 
 * 
 * Contributors:
 *       Kavishwar Wagholikar (kavi)
 */
package edu.harvard.i2b2.fhir;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import javax.tools.JavaFileManager.Location;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.commons.io.IOUtils;
import org.hl7.fhir.Bundle;
import org.hl7.fhir.BundleEntry;
import org.hl7.fhir.BundleLink;
import org.hl7.fhir.BundleType;
import org.hl7.fhir.BundleTypeList;
import org.hl7.fhir.Code;
import org.hl7.fhir.CodeableConcept;
import org.hl7.fhir.Coding;
import org.hl7.fhir.DiagnosticReport;
import org.hl7.fhir.Id;
import org.hl7.fhir.Instant;
import org.hl7.fhir.Medication;
import org.hl7.fhir.MedicationDispense;
import org.hl7.fhir.MedicationOrder;
import org.hl7.fhir.MedicationStatement;
import org.hl7.fhir.Meta;
import org.hl7.fhir.Observation;
import org.hl7.fhir.Patient;
import org.hl7.fhir.Condition;
import org.hl7.fhir.Reference;
import org.hl7.fhir.Resource;
import org.hl7.fhir.ResourceContainer;
import org.hl7.fhir.UnsignedInt;
import org.hl7.fhir.Uri;
import org.hl7.fhir.dstu21.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import wrapperHapi.WrapperHapi;
import edu.harvard.i2b2.fhir.core.FhirCoreException;
import edu.harvard.i2b2.fhir.query.SearchParameterMap;

public class FhirUtil {
    // public static boolean validateFhirResourceBeforeAddingFlag=false;

    static Logger logger = LoggerFactory.getLogger(FhirUtil.class);

    // final public static String RESOURCE_LIST_REGEX =
    // "("+FhirUtil.getResourceList().toString().replace(",", "|")
    // .replaceAll("[\\s\\[\\]]+", "")+")";

    final public static String RESOURCE_LIST_REGEX = "(Bundle|Condition|Medication|MedicationStatement|MedicationDispense|MedicationOrder|Observation|Patient|DiagnosticReport|DiagnosticOrder|DecisionSupportServiceModule|Parameters|Order|OperationOutcome|GuidanceResponse)";
    private static ArrayList<Class> resourceClassList = null;

    private static Validator v;

    public final static String namespaceDeclaration = "declare default element namespace \"http://hl7.org/fhir\";";

    // http://jboss-javassist.github.io/javassist/tutorial/tutorial.html#load
    public static void addJAXBAnnotationsToClasses() {
        try {
            String className = "org.hl7.fhir.Observation";// Observation.class.getName();
            ClassPool pool = ClassPool.getDefault();
            // extracting the class
            CtClass cc = pool.get(className);
            ClassFile cf = cc.getClassFile();
            ConstPool cp = cf.getConstPool();
            AnnotationsAttribute attr = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);

            Annotation a = new Annotation("javax.xml.bind.annotation.XmlRootElement", cp);
            a.addMemberValue("name",
                    new StringMemberValue(className.substring(className.lastIndexOf(".") + 1), cp));
            attr.setAnnotation(a);
            cf.addAttribute(attr);
            // cf.setVersionToJava5();

            // myClassReloadingFactory.newInstance("com.jenkov.MyObject");
            // print classAnnotations
            Class aClass = cc.toClass();
            /*
             * java.lang.annotation.Annotation[] annotations =
             * aClass.getAnnotations();
             * 
             * for(java.lang.annotation.Annotation annotation : annotations){
             * //if(annotation instanceof MyAnnotation){ logger.trace("annot: "
             * + annotation); //} }
             */

        } catch (CannotCompileException |
        // | IOException | IllegalConnectorArgumentsException|
                NotFoundException e) {
            logger.error(e.getMessage(), e);
        }
    }

    private static ArrayList<Class> getResourceClassList() {
        if (resourceClassList == null) {
            resourceClassList = new ArrayList<Class>();
            try {
                for (Class c : getAllFhirResourceClasses("org.hl7.fhir")) {

                    // logger.trace(c.getSimpleName());
                    resourceClassList.add(c);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return resourceClassList;
    }

    public static String getValidatorErrorMessageForProfile(String input, String profile) {
        String msg = "";
        logger.trace("running validator for input:" + input);
        try {
            if (v == null)
                init();

            File temp = File.createTempFile("tempFileForValidator", ".tmp");
            FileOutputStream outTemp = new FileOutputStream(temp);
            IOUtils.write(input, outTemp);
            outTemp.close();
            logger.trace("tmp file:" + new Scanner(temp).useDelimiter("\\Z").next());// temp.getAbsolutePath());

            v.setSource(temp.getPath());
            v.setProfile(profile);
            logger.trace("source" + v.getSource() + " \n profile:" + profile);
            v.process();

            temp.delete();
            return v.getOutcome().toString();

        } catch (Exception e) {
            msg = e.getMessage();
            logger.error(e.getMessage(), e);
        }
        return msg;

    }

    public static String getValidatorErrorMessage(String input) {
        return getValidatorErrorMessageForProfile(input, null);
    }

    public static boolean isValid(String xml) {
        try {
            if (v == null)
                init();
            // logger.trace("setting source:"+xml);
            v.setSource(xml);
            v.process();
        } catch (Exception e) {
            e.printStackTrace();

            return false;
        }
        return true;
    }

    private static void init() {
        if (v == null) {
            try {
                v = new Validator();
                // String path = Utils.getFilePath("validation-min.xml.zip");

                File temp = File.createTempFile("tempFileForDefinitions", ".tmp");
                FileOutputStream outTemp = new FileOutputStream(temp);

                IOUtils.copy(FhirUtil.class.getResourceAsStream("/validation-min.xml.zip"), outTemp);

                v.setDefinitions(temp.getAbsolutePath());

                logger.trace(v.getDefinitions());
                logger.trace("ready");
                temp.deleteOnExit();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

    }

    public List<Class> getResourceClasses() {
        List<Class> classList = new ArrayList<Class>();
        for (String x : RESOURCE_LIST_REGEX.split("|")) {
            x = x.replace("(", "").replace(")", "");
            Class y = getResourceClass(x);
            if (y != null)
                classList.add(y);
        }
        return classList;

    }

    public static List<Class> getAllFhirResourceClasses(String packageName) throws IOException {

        // logger.trace("Running getAllFhirResourceClasses for:" +
        // packageName);
        List<Class> commands = new ArrayList<Class>();

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

        Location location = StandardLocation.CLASS_PATH;

        Set<JavaFileObject.Kind> kinds = new HashSet<JavaFileObject.Kind>();
        kinds.add(JavaFileObject.Kind.CLASS);
        boolean recurse = false;

        Iterable<JavaFileObject> list = fileManager.list(location, packageName, kinds, recurse);

        for (JavaFileObject javaFileObject : list) {

            // commands.add(javaFileObject.getClass());
        }

        Class c = null;

        for (String x : Arrays.asList(RESOURCE_LIST_REGEX.replace("(", "").replace(")", "").split("\\|")))

        {
            x = "org.hl7.fhir." + x;
            // logger.trace("X:"+x);
            c = Utils.getClassFromClassPath(x);
            if (c != null)
                commands.add(c);
        }
        // logger.trace(commands.toString());
        return commands;
    }

    public static Class getResourceClass(String resourceName) {
        for (Class c : getResourceClassList()) {
            if (c.getSimpleName().toLowerCase().equals(resourceName.toLowerCase()))
                return c;
        }
        // logger.trace("Class Not Found for FHIR resource:" + resourceName);
        return null;

    }

    public static Class getResourceClass(Resource resource) {
        for (Class c : getResourceClassList()) {
            if (c.isInstance(resource))
                return c;
        }
        logger.trace("Class Not Found for FHIR resource:" + resource.getId());
        return null;

    }

    static public boolean isContained(List<Resource> outList, String idStr) {
        for (Resource r : outList) {
            if (r.getId().getValue().equals(idStr))
                return true;
        }
        return false;

    }

    public static List<Object> getChildrenThruChain(Resource r, String pathStr, List<Resource> s)
            // is dot separated path
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {

        List<Object> children = new ArrayList<Object>();
        List<Object> resolvedChildren = new ArrayList<Object>();
        logger.trace("got obj:" + r);
        Class c = FhirUtil.getResourceClass(r);

        String suffix = null;
        String prefix = pathStr;
        logger.trace("pathStr:" + pathStr);

        if (pathStr.indexOf('.') > -1) {
            suffix = pathStr.substring(pathStr.indexOf('.') + 1);
            prefix = pathStr.substring(0, pathStr.indexOf('.'));
        }

        String methodName = prefix.substring(0, 1).toUpperCase() + prefix.subSequence(1, prefix.length());
        Method method = c.getMethod("get" + methodName, null);
        Object o = method.invoke(c.cast(r));

        if (List.class.isInstance(o)) {
            children.addAll((List<Object>) o);
        } else {
            children.add(o);
        }

        if (suffix == null) {
            return children;

        } else {

            for (Object child : children) {
                if (Reference.class.isInstance(child)) {
                    Reference rr = Reference.class.cast(child);
                    logger.trace("gotc:" + child.getClass());

                    /*
                     * try { logger.trace("seek:" + JAXBUtil.toXml(rr));
                     * logger.trace("seek:" + rr.getReference().getValue()); }
                     * catch (JAXBException e) { // TODO Auto-generated catch
                     * block e.printStackTrace(); }
                     */

                    Resource r1 = FhirUtil.findResourceById(rr.getReference().getValue(), s);
                    resolvedChildren.add(getChildrenThruChain(r1, suffix, s));

                } else {
                    resolvedChildren.add(getChildrenThruChain(r, suffix, s));
                }

            }
        }
        return resolvedChildren;
    }

    public static Object getChildThruChain(Resource r, String pathStr, List<Resource> s)
            // is dot separated path
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Class c = FhirUtil.getResourceClass(r);

        String suffix = null;
        String prefix = pathStr;
        logger.trace("pathStr:" + pathStr);

        if (pathStr.indexOf('.') > -1) {
            suffix = pathStr.substring(pathStr.indexOf('.') + 1);
            prefix = pathStr.substring(0, pathStr.indexOf('.'));
        }

        String methodName = prefix.substring(0, 1).toUpperCase() + prefix.subSequence(1, prefix.length());
        Method method = c.getMethod("get" + methodName, null);
        Object o = method.invoke(c.cast(r));

        if (suffix == null) {
            return o;

        } else {
            if (Reference.class.isInstance(o)) {
                Reference rr = Reference.class.cast(o);
                logger.trace("gotc:" + o.getClass());

                /*
                 * try { logger.trace("seek:" + JAXBUtil.toXml(rr));
                 * logger.trace("seek:" + rr.getReference().getValue()); } catch
                 * (JAXBException e) { // TODO Auto-generated catch block
                 * e.printStackTrace(); }
                 */

                Resource r1 = FhirUtil.findResourceById(rr.getReference().getValue(), s);
                return getChildThruChain(r1, suffix, s);
            } else {
                return getChildThruChain(r, suffix, s);
            }
        }
    }

    public static Resource findResourceById(String idString, List<Resource> s) {
        for (Resource r : s) {
            if (r.getId().getValue().equals(idString))
                return r;
        }
        return null;

    }

    public static Object getChild(Resource r, String pathStr)
            // is dot separated path
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Class c = FhirUtil.getResourceClass(r);
        String returnStr = null;
        String suffix = null;
        String prefix = pathStr;
        logger.trace("pathStr:" + pathStr);
        if (pathStr.indexOf('.') > -1) {
            suffix = pathStr.substring(pathStr.indexOf('.') + 1);
            prefix = pathStr.substring(0, pathStr.indexOf('.'));
        }
        String methodName = prefix.substring(0, 1).toUpperCase() + prefix.subSequence(1, prefix.length());
        Method method = c.getMethod("get" + methodName, null);
        if (suffix == null) {
            Object o = method.invoke(c.cast(r));
            if (Reference.class.isInstance(o)) {
                return o;
            } else {
                return o;
            }
        } else {
            return getChild(r, suffix);
        }

    }

    // TO rename it
    public static List<String> getResourceList() {
        return Arrays.asList(Utils.getFile("resourceList.txt").split("\\n"));
    }

    public static String getResourceXml(String id, String metaResourceSetXml) throws FhirCoreException {
        String xml;
        String xQuery = namespaceDeclaration + "//i:Resource[@id='" + id + "']";

        // logger.trace("xml:" + metaResourceSetXml);
        String res;
        try {
            res = XQueryUtil.processXQuery(xQuery, metaResourceSetXml);
        } catch (XQueryUtilException e) {
            throw new FhirCoreException(e);
        }
        // logger.trace("res:" + res);
        return res;

    }

    public static Resource setId(Resource r, String idStr) {
        Id id = new Id();
        id.setValue(idStr);

        r.setId(id);
        return r;
    }

    public static Reference getReference(Resource r) {
        Reference pRef = new Reference();
        Class resourceClass = FhirUtil.getResourceClass(r);
        org.hl7.fhir.String str1 = new org.hl7.fhir.String();
        // str1.setValue(r.getId().getValue());
        str1.setValue(resourceClass.getSimpleName() + "/" + r.getId().getValue());
        pRef.setReference(str1);
        return pRef;
    }

    static public org.hl7.fhir.String getFhirString(String s1) {
        org.hl7.fhir.String s2 = new org.hl7.fhir.String();
        s2.setValue(s1);
        return s2;
    }

    public static Bundle getResourceBundle(List<Resource> s, String basePath, String url) {
        Bundle b = new Bundle();
        for (Resource r : s) {
            if (r.getMeta() == null) {
                r.setMeta(FhirUtil.createMeta());
            }
            BundleEntry be = FhirUtil.newBundleEntryForResource(r);
            b.getEntry().add(be);

        }

        BundleType value = new BundleType();
        value.setValue(BundleTypeList.SEARCHSET);
        b.setType(value);
        UnsignedInt total = new UnsignedInt();
        total.setValue(BigInteger.valueOf(s.size()));
        b.setTotal(total);

        Uri u = new Uri();
        u.setValue(basePath);

        FhirUtil.setId(b, Long.toHexString(new Random().nextLong()));

        b.setMeta(FhirUtil.createMeta());

        // b.setBase(u);
        return b;
    }

    private static Meta createMeta() {
        Meta meta = new Meta();
        Id vId = new Id();
        vId.setValue("1");
        meta.setVersionId(vId);
        Instant instantVal = new Instant();
        XMLGregorianCalendar xmlGregvalue;
        try {
            xmlGregvalue = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
        } catch (DatatypeConfigurationException e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        instantVal.setValue(xmlGregvalue);
        meta.setLastUpdated(instantVal);
        return meta;
    }

    static BundleEntry newBundleEntryForResource(Resource r) {
        BundleEntry be = new BundleEntry();
        ResourceContainer rc = FhirUtil.getResourceContainer(r);
        be.setResource(rc);
        return be;
    }

    public static ResourceContainer getResourceContainer(Resource r) {
        ResourceContainer rc = new ResourceContainer();
        String rClass = FhirUtil.getResourceClass(r).getSimpleName();
        switch (rClass) {
        case "Patient":
            rc.setPatient((Patient) r);
            break;
        case "Medication":
            rc.setMedication((Medication) r);
            break;
        case "MedicationStatement":
            rc.setMedicationStatement((MedicationStatement) r);
            break;
        case "MedicationOrder":
            rc.setMedicationOrder((MedicationOrder) r);
            break;
        case "MedicationDispense":
            rc.setMedicationDispense((MedicationDispense) r);
            break;
        case "Condition":
            rc.setCondition((Condition) r);
            break;
        case "Observation":
            rc.setObservation((Observation) r);
            break;
        case "Bundle":
            rc.setBundle((Bundle) r);
            break;
        case "DiagnosticReport":
            rc.setDiagnosticReport((DiagnosticReport) r);
            break;
        default:
            throw new RuntimeException("ResourceType not found:" + rClass);
        }
        return rc;
    }

    public static List<Resource> getResourceListFromBundle(Bundle b) {
        List<Resource> list = new ArrayList<Resource>();
        for (BundleEntry e : b.getEntry()) {
            e.getResource();
            list.add(FhirUtil.getResourceFromContainer(e.getResource()));
        }
        return list;
    }

    public static Resource getResourceFromContainer(ResourceContainer rc) {
        Resource r = null;
        if (rc.getPatient() != null)
            return rc.getPatient();
        if (rc.getMedication() != null)
            return rc.getMedication();
        if (rc.getMedicationStatement() != null)
            return rc.getMedicationStatement();
        if (rc.getMedicationDispense() != null)
            return rc.getMedicationDispense();
        if (rc.getMedicationOrder() != null)
            return rc.getMedicationOrder();
        if (rc.getCondition() != null)
            return rc.getCondition();
        if (rc.getObservation() != null)
            return rc.getObservation();
        if (rc.getBundle() != null)
            return rc.getBundle();
        if (rc.getSearchParameter() != null)
            return rc.getSearchParameter();
        if (rc.getDiagnosticReport() != null)
            return rc.getDiagnosticReport();
        if (rc.getDiagnosticOrder() != null)
            return rc.getDiagnosticOrder();
        if (rc.getOrder() != null)
            return rc.getOrder();
        String xml = null;
        try {
            xml = JAXBUtil.toXml(rc);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("Not implemented all resource types:" + xml);
    }

    public static String resourceToJsonString(Resource r) throws JAXBException, IOException {
        return WrapperHapi.resourceXmlToJson(JAXBUtil.toXml(r));

    }

    public static String hapiBundleToJsonString(ca.uhn.fhir.model.api.Bundle b) throws Exception {
        return WrapperHapi.bundleToJson(b);
    }

    public static ca.uhn.fhir.model.api.Bundle fhirBundleToHapiBundle(Bundle b) throws Exception {
        ca.uhn.fhir.model.api.Bundle hb = new ca.uhn.fhir.model.api.Bundle();

        // IdDt idb = new IdDt();
        // idb.setValue(b.getId().getValue());
        // id.setValue(fhirBase + UUID.randomUUID().toString());

        // hb.setId(idb);

        String fhirBase = "b.getBase().toString()";

        for (BundleEntry be : b.getEntry()) {
            ResourceContainer rc = be.getResource();

            Resource r = getResourceFromContainer(rc);
            for (Class c : getResourceClassList()) {

                if (c.isInstance(r)) {

                    ca.uhn.fhir.model.api.BundleEntry entry = new ca.uhn.fhir.model.api.BundleEntry();
                    IdDt ide = new IdDt();
                    ide.setValue(r.getId().getValue());
                    entry.setId(ide);
                    XMLGregorianCalendar lastUpdated = null;
                    try {
                        lastUpdated = null;
                    } catch (Exception ex) {
                    }
                    if (lastUpdated != null)

                    {
                        Date d = lastUpdated.toGregorianCalendar().getTime();
                        InstantDt dt = new InstantDt();
                        dt.setValue(d);
                        // entry.setUpdated(dt);
                    }
                    // entry.addExtension("http://www.w3.org/2005/Atom","published",null).setText(new
                    // Date().toGMTString());
                    // theLinkSelf
                    StringDt theLinkSelf = new StringDt();
                    theLinkSelf.setValue(fhirBase + r.getId());
                    entry.setLinkSelf(theLinkSelf);
                    IResource theResource = WrapperHapi.resourceXmlToIResource(JAXBUtil.toXml(r));
                    entry.setResource(theResource);
                    hb.addEntry(entry);
                }
            }
        }
        return hb;

    }

    @Deprecated // TODO
    public static Resource containResourceBySearchParameterName(Resource p, String searchParamName)
            throws JAXBException {

        Class parentClass = FhirUtil.getResourceClass(p);
        /*
         * <code value="result"/> <base value="DiagnosticReport"/> <type
         * value="reference"/> <description value=
         * "Link to an atomic result (observation resource)"/> <xpath
         * value="f:DiagnosticReport/f:result"/>
         */
        String paramterPath = null;
        try {
            paramterPath = new SearchParameterMap().getParameterPath(parentClass, searchParamName);
        } catch (FhirCoreException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        logger.trace("paramterPath:" + paramterPath);

        String[] set = paramterPath.split("/");
        String methodName = set[set.length - 1];
        logger.trace("MethodName:" + methodName);
        // XXXnot working
        return p;

    }

    // makes copy of child and puts in a container in p
    public static Resource containResource(Resource p, Resource c, String searchParamName) throws JAXBException {
        try {

            logger.trace("containing :" + c.getId().getValue() + " in " + p.getId().getValue());
            logger.trace("parent before :" + JAXBUtil.toXml(p));

            Class parentClass = FhirUtil.getResourceClass(p);
            Class childClass = FhirUtil.getResourceClass(c);

            if (childClass == null || parentClass == null)
                throw new RuntimeException("unknown resource class for child or parent");

            String xml = JAXBUtil.toXml(p);
            // add # prefix to reference of contained resource?
            String childReference = c.getId().getValue();
            // xml = xml.replace(childReference, "#-" + childReference);
            // p = JAXBUtil.fromXml(xml, parentClass);
            logger.trace("getting path to parent:" + parentClass + "\nchild:"
                    + childClass.getSimpleName().toLowerCase());

            // get path from profile

            String path = new SearchParameterMap().getParameterPath(parentClass, searchParamName.toLowerCase());

            logger.trace("SEARCH PATH:" + path);
            String childPath = path.replaceAll("^" + parentClass.getSimpleName() + "/", "");
            logger.trace("MchildPath:" + childPath);

            // Reference childRef = (Reference) FhirUtil.getChild(p, childPath);
            Object obj = FhirUtil.getChild(p, childPath);
            List<Reference> refList = new ArrayList();
            if (java.util.ArrayList.class.isInstance(obj)) {
                ArrayList<Object> childList = (ArrayList<Object>) obj;
                for (Object objA : childList)
                    refList.add((Reference) objA);
            } else {
                Reference ref = (Reference) obj;
                refList.add(ref);
            }
            for (Reference childRef : refList) {
                String childId = childRef.getReference().getValue();

                String expectedId = childClass.getSimpleName() + "/" + c.getId().getValue();
                logger.trace("childRef.getReference().getValue():" + childRef.getReference().getValue()
                        + "\n c.getId().getValue(): <" + expectedId + ">");
                if (!childId.equals(expectedId))
                    continue;

                childRef.getReference().setValue("#" // +
                        // childClass.getSimpleName()
                        // + "-"
                        + childId);

                Id cId = c.getId();
                c = FhirUtil.clone(c, childClass.getSimpleName() + "/" + cId.getValue());

                // Id cId = c.getId();
                // cId.setValue(childClass.getSimpleName() + "-" +
                // cId.getValue());
                // c.setId(cId);
                ResourceContainer childRc = FhirUtil.getResourceContainer(c);

                Method method;
                Object o;

                method = parentClass.getMethod("getContained", null);
                o = method.invoke(parentClass.cast(p));
                List<ResourceContainer> listRC = (List<ResourceContainer>) o;

                listRC.add(childRc);
                logger.debug("added " + c.getId() + " into " + p.getId());
                logger.trace("p during:" + JAXBUtil.toXml(p));
            }
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | FhirCoreException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
        }

        logger.trace("p after:" + JAXBUtil.toXml(p));
        return p;

    }

    private static Resource clone(Resource i, String newId) throws JAXBException {
        Class rClass = FhirUtil.getResourceClass(i);
        Resource c = JAXBUtil.fromXml(JAXBUtil.toXml(i), rClass);
        FhirUtil.setId(c, newId);
        return c;
    }

    public static String bundleToJsonString(Bundle s) throws IOException, JAXBException {
        return WrapperHapi.resourceXmlToJson(JAXBUtil.toXml(s));
    }

    public static Patient getPatientResource(String inputXml)
            throws XQueryUtilException, JAXBException, IOException {
        String query = IOUtils.toString(
                FhirUtil.class.getResourceAsStream("/transform/I2b2ToFhir/i2b2PatientToFhirPatient.xquery"));
        String bundleXml = XQueryUtil.processXQuery(query, inputXml).toString();
        Bundle b = JAXBUtil.fromXml(bundleXml, Bundle.class);
        return (Patient) FhirUtil.getResourceFromContainer(b.getEntry().get(0).getResource());
    }

    @Deprecated
    public static Bundle convertI2b2ToFhirForAParticularPatient(String i2b2Xml)
            throws IOException, XQueryUtilException, JAXBException {

        String query = IOUtils.toString(
                FhirUtil.class.getResourceAsStream("/transform/I2b2ToFhir/i2b2MedsToFHIRMedPrescription.xquery"));

        String xQueryResultString = XQueryUtil.processXQuery(query, i2b2Xml).toString();
        Bundle b = JAXBUtil.fromXml(xQueryResultString, Bundle.class);
        Patient p = getPatientResource(i2b2Xml);
        b.getEntry().add(newBundleEntryForResource(p));
        return b;
    }

    static public String extractPatientId(String input) {
        if (input == null)
            return null;
        String id = null;
        Pattern p = Pattern.compile("(Subject:subject|subject|Patient|patient|_id)+=([^?&]+)");
        Matcher m = p.matcher(input);

        if (m.find()) {
            id = m.group(2);
            logger.trace(id);
        }
        return id;
    }

    static public String extractPatientIdFromRequestById(String string, String resourceName) {
        logger.debug("requestUrl is:" + string);
        if (string == null)
            return null;
        String id = null;

        Pattern p = Pattern.compile(".*/([^?&]+)$");
        Matcher m = p.matcher(string);

        if (m.find()) {
            id = m.group(1);
            logger.trace("id:" + id);
        }
        if (id.equals(resourceName))
            id = null;

        return id;
    }

    static public org.hl7.fhir.String generateFhirString(String val) {
        org.hl7.fhir.String fstr = new org.hl7.fhir.String();
        fstr.setValue(val);
        return fstr;
    }

    public static String generateRandomId() {
        SecureRandom random = new SecureRandom();
        return new BigInteger(130, random).toString(32);

    }

    public static Id generateId(String idString) {
        Id id = new Id();
        id.setValue(idString);
        return id;
    }

    public static Bundle createBundle(List<Object> list) {
        Bundle b = new Bundle();

        for (Object o : list) {
            Resource r = (Resource) o;
            b.getEntry().add(FhirUtil.newBundleEntryForResource(r));
        }

        UnsignedInt ustotal = new UnsignedInt();
        BigInteger bigInt = new BigInteger(Integer.toString(list.size()));
        ustotal.setValue(bigInt);
        b.setTotal(ustotal);
        return b;

    }

    static public Bundle addResourceToBundle(Bundle b, Resource r) {
        BundleEntry be = FhirUtil.newBundleEntryForResource(r);
        b.getEntry().add(be);
        setBundleTotal(b);
        return b;
    }

    static public Bundle setBundleTotal(Bundle b) {
        int tot = 0;
        if (b.getEntry() != null) {
            tot = b.getEntry().size();
        }
        UnsignedInt ustotal = new UnsignedInt();
        BigInteger bigInt = new BigInteger(Integer.toString(tot));
        ustotal.setValue(bigInt);
        b.setTotal(ustotal);
        return b;
    }

    public static Bundle addBundles(Bundle b1, Bundle b2) {
        Bundle b = new Bundle();
        List<Resource> list1 = FhirUtil.getResourceListFromBundle(b1);
        List<Resource> list2 = FhirUtil.getResourceListFromBundle(b2);
        for (Resource r : list1)
            FhirUtil.addResourceToBundle(b, r);
        for (Resource r : list2)
            FhirUtil.addResourceToBundle(b, r);
        return b;
    }

    public static CodeableConcept generateCodeableConcept(String code, String codeSystem, String display) {

        Coding coding = createCoding(code, codeSystem, display);
        CodeableConcept codeableConcept = new CodeableConcept();
        codeableConcept.getCoding().add(coding);
        return codeableConcept;
    }

    public static Coding createCoding(String code, String codeSystem, String display) {

        Code ccode = new Code();
        ccode.setValue(code);

        Coding coding = new Coding();
        coding.setCode(ccode);

        Uri uri = new Uri();
        uri.setValue(codeSystem);
        coding.setSystem(uri);

        if (display != null) {
            coding.setDisplay(FhirUtil.generateFhirString(display));
        }
        return coding;
    }

    public static List<Object> getChildrenThruParPath(Resource r, String pathStr, MetaResourceDb db)
            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {

        List<Object> children = new ArrayList<Object>();
        List<Object> resolvedChildren = new ArrayList<Object>();
        List<Resource> s = db.getAll();

        logger.trace("got obj:" + r);
        Class c = FhirUtil.getResourceClass(r);

        String suffix = null;
        String prefix = pathStr;
        logger.trace("pathStr:" + pathStr);

        if (pathStr.indexOf('.') > -1) {
            suffix = pathStr.substring(pathStr.indexOf('.') + 1);
            prefix = pathStr.substring(0, pathStr.indexOf('.'));
        }

        String methodName = prefix.substring(0, 1).toUpperCase() + prefix.subSequence(1, prefix.length());
        Method method = c.getMethod("get" + methodName, null);
        Object o = method.invoke(c.cast(r));

        if (List.class.isInstance(o)) {
            children.addAll((List<Object>) o);
        } else {
            children.add(o);
        }

        if (suffix == null) {
            return children;

        } else {

            for (Object child : children) {

                // if it is a reference resolve the reference
                if (Reference.class.isInstance(child)) {
                    Reference rr = Reference.class.cast(child);
                    logger.trace("gotc:" + child.getClass());
                    Resource r1 = FhirUtil.findResourceById(rr.getReference().getValue(), s);
                    resolvedChildren.add(getChildrenThruChain(r1, suffix, s));

                } else {
                    resolvedChildren.add(getChildrenThruChain(r, suffix, s));
                }

            }
        }
        return resolvedChildren;
    }

    // Takes a bundle, and given the maxEntries and page Number,
    // generates the page for the bundle which includes links for related pages
    public static Bundle pageBundle(Bundle b, int maxEntries, int pageNum) {
        Bundle pagedB = new Bundle();
        FhirUtil.setId(pagedB, Long.toHexString(new Random().nextLong()));
        pagedB.setMeta(FhirUtil.createMeta());

        if (maxEntries <= 0)
            throw new IllegalArgumentException("max Entries should be >0 ");
        if (pageNum < 1)
            throw new IllegalArgumentException("page NUmber should be >=1 ");

        int sob = b.getEntry().size();// size of Bundle
        int lowIdx = maxEntries * (pageNum - 1);// index of lowest entry in
        // selected page
        int highIdx = (maxEntries * pageNum);// index of highest entry in
        // selected page

        int lastPageNum = (int) Math.ceil(sob / maxEntries);

        // if low and high index of
        if (lowIdx > sob) {
            return pagedB;
        }
        List<Object> listBE = new ArrayList<>();
        for (int i = lowIdx; i < highIdx; i++) {
            if (i < sob) {
                Resource r = FhirUtil.getResourceFromContainer(b.getEntry().get(i).getResource());
                listBE.add(r);
            }
        }
        pagedB = createBundle(listBE);

        // create links
        // get link for self from inputBundle if it exits

        String baseUrlValue = null;
        for (BundleLink link : b.getLink()) {
            if (link.getRelation() != null & link.getRelation().getValue() != null
                    & link.getRelation().getValue().equals("self") & link.getUrl() != null) {
                baseUrlValue = link.getUrl().getValue().replaceAll("&{0,1}page=\\d+", "").replaceAll("\\?$", "");
            }
        }

        if (baseUrlValue == null) {
            throw new RuntimeException("the self link is null ");
        }

        // self
        pagedB.getLink().add(createBundleLink("self",
                baseUrlValue + (baseUrlValue.contains("?") ? "&" : "?") + "page=" + pageNum));
        // first page
        pagedB.getLink().add(
                createBundleLink("first", baseUrlValue + (baseUrlValue.contains("?") ? "&" : "?") + "page=" + 1));

        // previous
        if (pageNum > 1) {
            pagedB.getLink().add(createBundleLink("previous",
                    baseUrlValue + (baseUrlValue.contains("?") ? "&" : "?") + "page=" + (pageNum - 1)));
        }

        // next
        if (pageNum < lastPageNum) {
            pagedB.getLink().add(createBundleLink("next",
                    baseUrlValue + (baseUrlValue.contains("?") ? "&" : "?") + "page=" + (pageNum + 1)));
        }
        // last page
        pagedB.getLink().add(createBundleLink("last",
                baseUrlValue + (baseUrlValue.contains("?") ? "&" : "?") + "page=" + lastPageNum));

        return pagedB;
    }

    public static BundleLink createBundleLink(String relation, String url) {
        BundleLink link = new BundleLink();
        org.hl7.fhir.String relString = new org.hl7.fhir.String();
        relString.setValue(relation);
        link.setRelation(relString);
        Uri uri = new Uri();
        uri.setValue(url);
        link.setUrl(uri);
        return link;
    }

}