NIH | National Cancer Institute | NCI Wiki  

Java Code
/*
 * Copyright: (c) 2004-2009 Mayo Foundation for Medical Education and 
 * Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
 * triple-shield Mayo logo are trademarks and service marks of MFMER.
 *
 * Except as contained in the copyright notice above, or as used to identify 
 * MFMER as the author of this software, the trade names, trademarks, service
 * marks, or product names of the copyright holder shall not be used in
 * advertising, promotion or otherwise in connection with this software without
 * prior written authorization of the copyright holder.
 * 
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * 		http://www.eclipse.org/legal/epl-v10.html
 * 
 */
package org.LexGrid.LexBIG.example;

import org.LexGrid.LexBIG.DataModel.Collections.AssociatedConceptList;
import org.LexGrid.LexBIG.DataModel.Collections.AssociationList;
import org.LexGrid.LexBIG.DataModel.Core.AssociatedConcept;
import org.LexGrid.LexBIG.DataModel.Core.Association;
import org.LexGrid.LexBIG.DataModel.Core.CodingSchemeSummary;
import org.LexGrid.LexBIG.DataModel.Core.CodingSchemeVersionOrTag;
import org.LexGrid.LexBIG.Exceptions.LBException;
import org.LexGrid.LexBIG.Extensions.Generic.LexBIGServiceConvenienceMethods;
import org.LexGrid.LexBIG.Impl.LexBIGServiceImpl;
import org.LexGrid.LexBIG.LexBIGService.LexBIGService;

/**
 * Example showing how to determine and display the hierarchical relationships
 * for a specific code, ancestors or descendants, within a fixed distance.
 * 
 * This program accepts two parameters, indicating the code and distance. The
 * first parameter is the code (required). The second parameter is the distance
 * (optional). If 1, immediate children are displayed. If 2, grandchildren are
 * displayed, etc. If absent or < 0, all downstream branches are displayed.
 * 
 * BACKGROUND: From a database perspective, LexBIG stores relationships
 * internally in a forward direction, source to target. Due to differences in
 * source formats, however, a wide variety of associations may be used ('PAR',
 * 'CHD', 'isa', 'hasSubtype', etc). In addition, the direction of navigation
 * may vary ('isa' expands in a reverse direction whereas 'hasSubtype' expands
 * in a forward direction.
 * 
 * The intent of the getHierarchy* methods on the
 * LexBIGServiceConvenienceMethods interface is to simplify the process of
 * hierarchy discovery and navigation. These methods significantly reduce the
 * need to understand conventions for root nodes, associations, and direction of
 * navigation for a specific source format.
 * 
 */
public class ListHierarchyByCode {
    final static int DEFAULT_DISTANCE = -1;

    public ListHierarchyByCode() {
        super();
    }

    /**
     * Entry point for processing.
     * 
     * @param args
     */
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("Example: ListHierarchyByCode \"C0000\" 2");
            return;
        }
        ;

        try {
            String code = args[0];
            int distance = args.length == 1 ? DEFAULT_DISTANCE : Integer.parseInt(args[1]);
            new ListHierarchyByCode().run(code, distance);
        } catch (NumberFormatException nfe) {
            System.out.println("Parameter 2 must indicate a number representing maximum distance to display.\n"
                    + "Example: ListHierarchyByCode \"C0000\" 2");
            return;
        } catch (Exception e) {
            Util.displayAndLogError("REQUEST FAILED !!!", e);
        }
    }

    public void run(String code, int maxDistance) throws LBException {
        CodingSchemeSummary css = Util.promptForCodeSystem();
        long ms = System.currentTimeMillis();
        try {
            if (css != null) {
                LexBIGService lbSvc = LexBIGServiceImpl.defaultInstance();
                LexBIGServiceConvenienceMethods lbscm = (LexBIGServiceConvenienceMethods) lbSvc
                        .getGenericExtension("LexBIGServiceConvenienceMethods");

                String scheme = css.getCodingSchemeURI();
                CodingSchemeVersionOrTag csvt = new CodingSchemeVersionOrTag();
                csvt.setVersion(css.getRepresentsVersion());
                String desc = null;
                try {
                    desc = lbscm.createCodeNodeSet(new String[] { code }, scheme, csvt).resolveToList(null, null, null,
                            1).getResolvedConceptReference(0).getEntityDescription().getContent();
                } catch (Exception e) {
                    desc = "<not found>";
                }
                Util.displayMessage("============================================================");
                Util.displayMessage("Focus code: " + code + ":" + desc);
                Util.displayMessage("============================================================");

                // Iterate through all hierarchies and levels ...
                String[] hierarchyIDs = lbscm.getHierarchyIDs(scheme, csvt);
                for (int i = 0; i < hierarchyIDs.length; i++) {
                    String hierarchyID = hierarchyIDs[i];
                    String reportedDistance = maxDistance >= 0 ? Integer.toString(maxDistance) : "ALL";
                    Util.displayMessage("------------------------------------------------------------");
                    Util.displayMessage("Hierarchy ID: " + hierarchyID);
                    Util.displayMessage("------------------------------------------------------------");
                    Util.displayMessage("Paths to ancestors (distance <= " + reportedDistance + ") ...");
                    printLevelPrev(lbscm, scheme, csvt, hierarchyID, code, maxDistance, 0);
                    Util.displayMessage("");
                    Util.displayMessage("Paths to descendants (distance <= " + reportedDistance + ") ...");
                    printLevelNext(lbscm, scheme, csvt, hierarchyID, code, maxDistance, 0);
                    Util.displayMessage("");
                }
            }
        } finally {
            System.out.println("Run time (ms): " + (System.currentTimeMillis() - ms));
        }
    }

    /**
     * Displays ancestors for a code within the specified hierarchy up to the
     * given distance or until paths to root nodes are exhausted, recursing as
     * necessary.
     * 
     * @param lbcsm
     * @param scheme
     * @param csvt
     * @param hierarchyID
     * @param code
     * @param maxDistance
     * @param currentDistance
     * @throws LBException
     */
    protected void printLevelPrev(LexBIGServiceConvenienceMethods lbscm, String scheme, CodingSchemeVersionOrTag csvt,
            String hierarchyID, String code, int maxDistance, int currentDistance) throws LBException {
        if (maxDistance < 0 || currentDistance < maxDistance) {
            StringBuffer indent = new StringBuffer();
            for (int i = 0; i <= currentDistance; i++)
                indent.append("    ");

            AssociationList associations = lbscm.getHierarchyLevelPrev(scheme, csvt, hierarchyID, code, false, null);
            for (int i = 0; i < associations.getAssociationCount(); i++) {
                Association assoc = associations.getAssociation(i);
                AssociatedConceptList concepts = assoc.getAssociatedConcepts();
                for (int j = 0; j < concepts.getAssociatedConceptCount(); j++) {
                    AssociatedConcept concept = concepts.getAssociatedConcept(j);
                    String prevCode = concept.getConceptCode();
                    String prevDesc = concept.getEntityDescription() == null ? "NO DESCRIPTION" : concept
                            .getEntityDescription().getContent();
                    Util.displayMessage(indent + assoc.getDirectionalName() + "<-" + prevCode + ":" + prevDesc);
                    printLevelPrev(lbscm, scheme, csvt, hierarchyID, prevCode, maxDistance, currentDistance + 1);
                }
            }
        }
    }

    /**
     * Displays descendants for a code within the specified hierarchy up to the
     * given distance or until all paths to leaf nodes is exhausted, recursing
     * as necessary.
     * 
     * @param lbscm
     * @param scheme
     * @param csvt
     * @param hierarchyID
     * @param code
     * @param maxDistance
     * @param currentDistance
     * @throws LBException
     */
    protected void printLevelNext(LexBIGServiceConvenienceMethods lbscm, String scheme, CodingSchemeVersionOrTag csvt,
            String hierarchyID, String code, int maxDistance, int currentDistance) throws LBException {
        if (maxDistance < 0 || currentDistance < maxDistance) {
            StringBuffer indent = new StringBuffer();
            for (int i = 0; i <= currentDistance; i++)
                indent.append("    ");

            AssociationList associations = lbscm.getHierarchyLevelNext(scheme, csvt, hierarchyID, code, false, null);
            for (int i = 0; i < associations.getAssociationCount(); i++) {
                Association assoc = associations.getAssociation(i);
                AssociatedConceptList concepts = assoc.getAssociatedConcepts();
                for (int j = 0; j < concepts.getAssociatedConceptCount(); j++) {
                    AssociatedConcept concept = concepts.getAssociatedConcept(j);
                    String nextCode = concept.getConceptCode();
                    String nextDesc = concept.getEntityDescription().getContent();
                    Util.displayMessage(indent + assoc.getDirectionalName() + "->" + nextCode + ":" + nextDesc);
                    printLevelNext(lbscm, scheme, csvt, hierarchyID, nextCode, maxDistance, currentDistance + 1);
                }
            }
        }
    }
}