001 /** 002 The contents of this file are subject to the Mozilla Public License Version 1.1 003 (the "License"); you may not use this file except in compliance with the License. 004 You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005 Software distributed under the License is distributed on an "AS IS" basis, 006 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007 specific language governing rights and limitations under the License. 008 009 The Original Code is "GroupPointer.java". Description: 010 "A GroupPointer is used when parsing traditionally encoded HL7 messages" 011 012 The Initial Developer of the Original Code is University Health Network. Copyright (C) 013 2001. All Rights Reserved. 014 015 Contributor(s): ______________________________________. 016 017 Alternatively, the contents of this file may be used under the terms of the 018 GNU General Public License (the ???GPL???), in which case the provisions of the GPL are 019 applicable instead of those above. If you wish to allow use of your version of this 020 file only under the terms of the GPL and not to allow others to use your version 021 of this file under the MPL, indicate your decision by deleting the provisions above 022 and replace them with the notice and other provisions required by the GPL License. 023 If you do not delete the provisions above, a recipient may use your version of 024 this file under either the MPL or the GPL. 025 026 */ 027 package ca.uhn.hl7v2.parser; 028 029 import ca.uhn.hl7v2.HL7Exception; 030 import ca.uhn.hl7v2.model.Message; 031 import ca.uhn.hl7v2.model.Segment; 032 import ca.uhn.hl7v2.model.Type; 033 import ca.uhn.hl7v2.validation.ValidationContext; 034 035 /** 036 * A Parser that delegates parsing tasks to an underlying PipeParser and DefaultXMLParser 037 * as needed. Messages to be parsed are inspected in order to determine which Parser 038 * to use. If a message is to be encoded, the "primary" Parser will be used. The 039 * primary parser defaults to PipeParser, and can be configured using the 040 * set...AsPrimary() methods. 041 * @author Bryan Tripp 042 */ 043 public class GenericParser extends Parser { 044 045 private Parser primaryParser; 046 private Parser secondaryParser; 047 private PipeParser pipeParser; 048 private XMLParser xmlParser; 049 050 /** Creates a new instance of GenericParser */ 051 public GenericParser() { 052 this(null); 053 } 054 055 /** 056 * Creates a new instance of GenericParser 057 * 058 * @param theFactory custom factory to use for model class lookup 059 */ 060 public GenericParser(ModelClassFactory theFactory) { 061 super(theFactory); 062 063 pipeParser = new PipeParser(); 064 xmlParser = new DefaultXMLParser(); 065 setPipeParserAsPrimary(); 066 } 067 068 /** 069 * Sets the underlying XMLParser as the primary parser, so that subsequent calls to 070 * encode() will return XML encoded messages, and an attempt will be made to use the 071 * XMLParser first for parsing. 072 */ 073 public void setXMLParserAsPrimary() { 074 primaryParser = xmlParser; 075 secondaryParser = pipeParser; 076 } 077 078 /** 079 * Sets the underlying PipeParser as the primary parser, so that subsequent calls to 080 * encode() will return traditionally encoded messages, and an attempt will be made to use the 081 * PipeParser first for parsing. This is the default setting. 082 */ 083 public void setPipeParserAsPrimary() { 084 primaryParser = pipeParser; 085 secondaryParser = xmlParser; 086 } 087 088 /** 089 * @param theContext the set of validation rules to be applied to messages parsed or 090 * encoded by this parser (defaults to ValidationContextFactory.DefaultValidation) 091 */ 092 public void setValidationContext(ValidationContext theContext) { 093 super.setValidationContext(theContext); 094 095 // These parsers are not yet initialized when this is called during the Parser constructor 096 if (xmlParser != null) { 097 pipeParser.setValidationContext(theContext); 098 xmlParser.setValidationContext(theContext); 099 } 100 } 101 102 /** 103 * Checks the encoding of the message using getEncoding(), and returns the corresponding 104 * parser (either pipeParser or xmlParser). If the encoding is not recognized an 105 * HL7Exception is thrown. 106 */ 107 private Parser getAppropriateParser(String message) throws HL7Exception { 108 String encoding = getEncoding(message); 109 if (encoding == null) 110 encoding = ""; //prevent null pointer exception 111 Parser appropriateParser = null; 112 if (encoding.equalsIgnoreCase("VB")) { 113 appropriateParser = pipeParser; 114 } 115 else if (encoding.equalsIgnoreCase("XML")) { 116 appropriateParser = xmlParser; 117 } 118 else { 119 throw new HL7Exception( 120 "Can't find appropriate parser - encoding not recognized", 121 HL7Exception.APPLICATION_INTERNAL_ERROR); 122 } 123 return appropriateParser; 124 } 125 126 /** 127 * Formats a Message object into an HL7 message string using the given 128 * encoding. 129 * @throws HL7Exception if the data fields in the message do not permit encoding 130 * (e.g. required fields are null) 131 * @throws EncodingNotSupportedException if the requested encoding is not 132 * supported by this parser. 133 */ 134 protected String doEncode(Message source, String encoding) throws HL7Exception, EncodingNotSupportedException { 135 String ret = null; 136 if (encoding == null) 137 encoding = ""; //prevent null pointer exception 138 if (encoding.equalsIgnoreCase("VB")) { 139 ret = pipeParser.doEncode(source); 140 } 141 else if (encoding.equalsIgnoreCase("XML")) { 142 ret = xmlParser.doEncode(source); 143 } 144 else { 145 throw new EncodingNotSupportedException( 146 "The encoding " + encoding + " is not supported by " + this.getClass().getName()); 147 } 148 return ret; 149 } 150 151 /** 152 * <p>Returns a minimal amount of data from a message string, including only the 153 * data needed to send a response to the remote system. This includes the 154 * following fields: 155 * <ul><li>field separator</li> 156 * <li>encoding characters</li> 157 * <li>processing ID</li> 158 * <li>message control ID</li></ul> 159 * This method is intended for use when there is an error parsing a message, 160 * (so the Message object is unavailable) but an error message must be sent 161 * back to the remote system including some of the information in the inbound 162 * message. This method parses only that required information, hopefully 163 * avoiding the condition that caused the original error.</p> 164 */ 165 public Segment getCriticalResponseData(String message) throws HL7Exception { 166 return getAppropriateParser(message).getCriticalResponseData(message); 167 } 168 169 /** 170 * Returns the version ID (MSH-12) from the given message, without fully parsing the message. 171 * The version is needed prior to parsing in order to determine the message class 172 * into which the text of the message should be parsed. 173 * @throws HL7Exception if the version field can not be found. 174 */ 175 public String getVersion(String message) throws HL7Exception { 176 return getAppropriateParser(message).getVersion(message); 177 } 178 179 /** 180 * Returns a String representing the encoding of the given message, if 181 * the encoding is recognized. For example if the given message appears 182 * to be encoded using HL7 2.x XML rules then "XML" would be returned. 183 * If the encoding is not recognized then null is returned. That this 184 * method returns a specific encoding does not guarantee that the 185 * message is correctly encoded (e.g. well formed XML) - just that 186 * it is not encoded using any other encoding than the one returned. 187 * Returns null if the encoding is not recognized. 188 */ 189 public String getEncoding(String message) { 190 String encoding = primaryParser.getEncoding(message); 191 if (encoding == null) 192 encoding = secondaryParser.getEncoding(message); 193 return encoding; 194 } 195 196 /** 197 * For response messages, returns the value of MSA-2 (the message ID of the message 198 * sent by the sending system). This value may be needed prior to main message parsing, 199 * so that (particularly in a multi-threaded scenario) the message can be routed to 200 * the thread that sent the request. We need this information first so that any 201 * parse exceptions are thrown to the correct thread. Implementers of Parsers should 202 * take care to make the implementation of this method very fast and robust. 203 * Returns null if MSA-2 can not be found (e.g. if the message is not a 204 * response message). 205 */ 206 public String getAckID(String message) { 207 try { 208 return getAppropriateParser(message).getAckID(message); 209 } 210 catch (HL7Exception e) { 211 return null; 212 } 213 } 214 215 /** 216 * Returns true if and only if the given encoding is supported 217 * by this Parser. 218 */ 219 public boolean supportsEncoding(String encoding) { 220 boolean supported = false; 221 if ("VB".equalsIgnoreCase(encoding) || "XML".equalsIgnoreCase(encoding)) 222 supported = true; 223 return supported; 224 } 225 226 /** 227 * @return the preferred encoding of the current primary Parser 228 */ 229 public String getDefaultEncoding() { 230 return primaryParser.getDefaultEncoding(); 231 } 232 233 /** 234 * Parses a message string and returns the corresponding Message 235 * object. 236 * @throws HL7Exception if the message is not correctly formatted. 237 * @throws EncodingNotSupportedException if the message encoded 238 * is not supported by this parser. 239 */ 240 protected Message doParse(String message, String version) throws HL7Exception, EncodingNotSupportedException { 241 return getAppropriateParser(message).doParse(message, version); 242 } 243 244 /** 245 * Formats a Message object into an HL7 message string using this parser's 246 * default encoding. 247 * @throws HL7Exception if the data fields in the message do not permit encoding 248 * (e.g. required fields are null) 249 */ 250 protected String doEncode(Message source) throws HL7Exception { 251 return primaryParser.doEncode(source); 252 } 253 254 /** 255 * {@inheritDoc } 256 */ 257 @Override 258 public String doEncode(Segment structure, EncodingCharacters encodingCharacters) throws HL7Exception { 259 return primaryParser.doEncode(structure, encodingCharacters); 260 } 261 262 /** 263 * {@inheritDoc } 264 */ 265 @Override 266 public String doEncode(Type type, EncodingCharacters encodingCharacters) throws HL7Exception { 267 return primaryParser.doEncode(type, encodingCharacters); 268 } 269 270 /** 271 * {@inheritDoc } 272 */ 273 @Override 274 public void parse(Type type, String string, EncodingCharacters encodingCharacters) throws HL7Exception { 275 primaryParser.parse(type, string, encodingCharacters); 276 } 277 278 /** 279 * {@inheritDoc } 280 */ 281 @Override 282 public void parse(Segment segment, String string, EncodingCharacters encodingCharacters) throws HL7Exception { 283 primaryParser.parse(segment, string, encodingCharacters); 284 } 285 286 287 @Override 288 public void parse(Message message, String string) throws HL7Exception { 289 primaryParser.parse(message, string); 290 } 291 292 }