001package ca.uhn.hl7v2.conf.store;
002
003import java.io.IOException;
004import java.net.URL;
005import java.util.Iterator;
006import java.util.List;
007
008import org.jdom.Document;
009import org.jdom.Element;
010import org.jdom.input.SAXBuilder;
011import org.jdom.xpath.XPath;
012
013import ca.uhn.hl7v2.conf.ProfileException;
014
015/**
016 * @author Neal Acharya
017 * Created on 27-Aug-2003
018 *
019 * This particular implementation of CodeStore retrieves valid codes and validates codeSystems
020 * using tables found in 'spec xml tables only' docs generated from the HL7 Messaging
021 * Workbench tool.
022 *
023 * Note:  The codeSystem parameter value used in the following methods must be a concatenation
024 * of a coding authority and coding table number that is 4 digits long.
025 *
026 * Note: The current implementation only accepts a coding authority of HL7
027 *
028 */
029public class ProfileCodeStore extends AbstractCodeStore {
030    
031    private Document tableDoc;
032    
033    /**
034     * @param uri the location of the specification XML file
035     * @throws ProfileException
036     * @throws IOException
037     *
038     * Creates a ProfileCodeStore object that uses tables found in an 'spec xml tables only'
039     * xml doc specified by the input URI. The private field member tableDoc is created with
040     * content from the xml doc specified by the URI.
041     */
042    public ProfileCodeStore(String uri) throws ProfileException, IOException {
043        try {
044            if (uri == null) {
045                throw new ProfileException("The input url parameter cannot be null");
046            } //end if
047            //create tableDoc object
048            tableDoc = new SAXBuilder().build(uri);
049        } //end try
050        catch (ProfileException e) {
051            throw e;
052        } //end catch
053        catch (IOException e){
054            throw e;
055        }//end catch
056        catch (Exception e) {
057            throw new ProfileException(e.toString(), e);
058        } //end catch
059    } //end constructor
060
061    /** As string constructor but accepts a URL object */
062    public ProfileCodeStore(URL url) throws ProfileException, IOException {
063        if (url == null) 
064            throw new ProfileException("The input url parameter cannot be null");
065        
066        try {            
067            tableDoc = new SAXBuilder().build(url);
068        } catch (org.jdom.JDOMException e) {
069            throw new ProfileException(e.toString(), e); 
070        } 
071    } 
072    
073    /**
074     * @param codeSystem
075     * @return String[]
076     * @throws ProfileException
077     * @see ca.uhn.hl7v2.conf.store.CodeStore#getValidCodes(java.lang.String, java.lang.String)
078     *
079     * Retreives all codes for a given conformance profile and codeSystem.
080     * Note:  The codeSystem parameter value must be a concatenation of a coding authority
081     * and coding table number that is 4 digits long.
082     *
083     * Note: The current implementation only accepts a coding authority of HL7
084     */
085    public String[] getValidCodes(String codeSystem) throws ProfileException {
086        String[] codeValues = null;
087        //obtain the table for the codesystem
088        try {
089            Element table = getCodeTable(codeSystem);
090            List<?> tableElementList = table.getChildren("tableElement");
091            Iterator<?> itr = tableElementList.iterator();
092            codeValues = new String[tableElementList.size()];
093            int i = 0;
094            while (itr.hasNext()) {
095                Element tableElement = (Element) itr.next();
096                codeValues[i] = tableElement.getAttributeValue("code");
097                i++;
098            } //end while
099        } //end try
100        catch (NullPointerException e) {
101            throw new ProfileException("The spec xml table doc is missing one or more of the following: tableElement element, code attribute", e);
102        } //end catch
103        return codeValues;
104    } //end method
105    
106    /**
107     * @param codeSystem
108     * @return boolean
109     * @see ca.uhn.hl7v2.conf.store.CodeStore#knowsCodes(java.lang.String, java.lang.String)
110     *
111     * Validates the codeSytem against the input conformance profile. If valid then
112     * output is 'true' else 'false'.
113     * Note:  The codeSystem parameter value must be a concatenation of a coding authority
114     * and coding table number that is 4 digits long.
115     *
116     * Note: The current implementation only accepts a coding authority of HL7
117     */
118    public boolean knowsCodes(String codeSystem){
119        try{
120            Element table = getCodeTable(codeSystem);
121            if (table != null) {
122                return true;
123            } //end if
124            else {
125                return false;
126            } //end else
127        }//end try
128        catch (Exception e){
129            return false;
130        }//end catch
131    } //end method
132    
133    /**
134     * @param profileId
135     * @throws ProfileException
136     * void
137     *
138     * Validates the input conformance profile. Returns an exception if invalid.
139     */    
140    /*private void validateProfile(String profileId) throws ProfileException {
141        try {
142            if (profileId == null) {
143                throw new ProfileException("The input profileId parameter cannot be null");
144            } //end if
145            XPath path = XPath.newInstance("/Specification/Conformance[@StaticID]");
146            Element conformance = (Element) path.selectSingleNode(tableDoc);
147            String staticId = conformance.getAttributeValue("StaticID");
148            if (!staticId.equals(profileId)) {
149                throw new ProfileException("The input profileId is not valid or is not specified for the spec xml table doc");
150            } //end if
151        } //end try
152        catch (ProfileException e) {
153            throw e;
154        } //end catch
155        catch (Exception e) {
156            throw new ProfileException(e.toString(), e);
157        } //end catch
158    }*/ //end method
159    
160    /**
161     * @param profileId
162     * @param codeSystem
163     * @return Element
164     * @throws ProfileException
165     * Element
166     *
167     * Retreives the hl7Table Element from the tableDoc object defined by the table number
168     * in the input codeSystem.
169     */
170    private Element getCodeTable(String codeSystem) throws ProfileException {
171        //initialize return param
172        Element table = null;
173        //Validate the input Profile
174        //validateProfile(profileId);
175        //Validate the codeSystem
176        if (codeSystem == null) {
177            throw new ProfileException("The input codeSystem parameter cannot be null");
178        } //end if
179        if (codeSystem.length() < 4) {
180            throw new ProfileException("The input codeSystem parameter cannot be less than 4 characters long");
181        } //end if
182        try {
183            //Extract the last 4 characters from the codeSystem param
184            String tableId = codeSystem.substring(codeSystem.length() - 4);
185            //System.out.println(tableId);
186            XPath path = XPath.newInstance("/Specification/hl7tables/hl7table[@id='" + tableId + "']");
187            table = (Element) path.selectSingleNode(tableDoc);
188        } //end try
189        catch (Exception e) {
190            throw new ProfileException(e.toString(), e);
191        } //end catch
192        return table;
193    } //end method
194} //end class