View Javadoc
1   package ca.uhn.hl7v2.parser;
2   
3   import java.util.Arrays;
4   import java.util.Collections;
5   import java.util.HashSet;
6   import java.util.Set;
7   
8   import ca.uhn.hl7v2.HapiContext;
9   import ca.uhn.hl7v2.model.GenericMessage;
10  import ca.uhn.hl7v2.util.Terser;
11  import ca.uhn.hl7v2.util.idgenerator.FileBasedHiLoGenerator;
12  import ca.uhn.hl7v2.util.idgenerator.IDGenerator;
13  import ca.uhn.hl7v2.validation.ValidationContext;
14  
15  /**
16   * Contains configuration which will be applied to any parsers which are a part of the given
17   * HAPI Context.
18   * 
19   * @see HapiContext#getParserConfiguration()
20   */
21  public class ParserConfiguration {
22  
23  	/**
24  	 * @link {@link UnexpectedSegmentBehaviourEnum#ADD_INLINE}
25  	 */
26  	// NB if you change the default, edit the javadoc for the enum itself
27  	public static final UnexpectedSegmentBehaviourEnum DEFAULT_UNEXPECTED_SEGMENT_BEHAVIOUR = UnexpectedSegmentBehaviourEnum.ADD_INLINE;
28  
29  	private boolean allowUnknownVersions;
30  	private boolean escapeSubcomponentDelimiterInPrimitive = false;
31  	private IDGenerator idGenerator = new FileBasedHiLoGenerator();
32  	private String myDefaultObx2Type;
33  	private boolean myEncodeEmptyMandatorySegments = true;
34  	private final Set<String> myForcedEncode = new HashSet<>();
35  	private String myInvalidObx2Type;
36  	private UnexpectedSegmentBehaviourEnum myUnexpectedSegmentBehaviour;
37  	private boolean nonGreedyMode = false;
38  	private boolean prettyPrintWhenEncodingXml = true;
39  	private boolean validating = true;
40      private Escaping escaping = new DefaultEscaping();
41  	private boolean xmlDisableWhitespaceTrimmingOnAllNodes = false;
42  	private Set<String> xmlDisableWhitespaceTrimmingOnNodeNames = Collections.emptySet();
43      private String myInvalidMfe5Type;
44      private String myDefaultMfe5Type;
45  
46  	/**
47  	 * <p>
48  	 * Forces the parser to encode certain segments/fields, even if they contain
49  	 * no content. This method may be called multiple times with multiple path
50  	 * definitions, and each path definition contains the path to the segment or
51  	 * field which needs to be forced.
52  	 * </p>
53  	 * <p>
54  	 * Path definitions are similar in format to {@link Terser Terser} paths.
55  	 * They contain a slash-separated lookup path to reach a given segment, and
56  	 * optionally a field number. The following are examples of paths which
57  	 * could be added here, as well as the sample output for an otherwise empty
58  	 * ORU^R01 message:
59  	 * </p>
60  	 * <table cellpadding="2" cellspacing="2" border="0">
61  	 * <thead>
62  	 * <tr>
63  	 * <th style="background: #FFA0FF;">Forced Encode Path</th>
64  	 * <th style="background: #FFA0FF;">Encode Output</th>
65  	 * </tr>
66  	 * </thead>
67  	 * <tr>
68  	 * <td>None (for illustration purposes)</td>
69  	 * <td style=" font-family: monospace;">
70  	 * MSH|^~\&amp;|||||||ORU^R01^ORU_R01||T|2.4</td>
71  	 * </tr>
72  	 * <tr>
73  	 * <td style="background: #E0E0E0;">PATIENT_RESULT/ORDER_OBSERVATION/ORC</td>
74  	 * <td style="background: #E0E0E0; font-family: monospace;">
75  	 * MSH|^~\&amp;|||||||ORU^R01^ORU_R01||T|2.4<br>
76  	 * ORC|</td>
77  	 * </tr>
78  	 * <tr>
79  	 * <td>PATIENT_RESULT/ORDER_OBSERVATION/ORC-4</td>
80  	 * <td style=" font-family: monospace;">
81  	 * MSH|^~\&amp;|||||||ORU^R01^ORU_R01||T|2.4<br>
82  	 * ORC||||</td>
83  	 * </tr>
84  	 * <tr>
85  	 * <td style="background: #E0E0E0;">PATIENT_RESULT/ORDER_OBSERVATION/ORC-4-2
86  	 * </td>
87  	 * <td style="background: #E0E0E0; font-family: monospace;">
88  	 * MSH|^~\&amp;|||||||ORU^R01^ORU_R01||T|2.4<br>
89  	 * ORC||||^</td>
90  	 * </tr>
91  	 * </table>
92  	 * <p>
93  	 * While empty segments do not generally have any meaning according to HL7,
94  	 * this may be useful when transmitting to systems which rely on segments
95  	 * being received even if they have no content.
96  	 * </p>
97  	 * <p>
98  	 * Note that this configuration item currently only applies to
99  	 * {@link PipeParser}
100 	 * </p>
101 	 *
102      * @param theForcedEncode path definition
103 	 * @since 2.0
104 	 */
105 	public void addForcedEncode(String theForcedEncode) {
106 		if (theForcedEncode == null) {
107 			throw new NullPointerException("forced encode may not be null");
108 		}
109 
110 		int lastSlashIndex = theForcedEncode.lastIndexOf('/');
111 		lastSlashIndex = Math.max(lastSlashIndex, 0);
112 
113 		if (lastSlashIndex == 0) {
114 			if (!theForcedEncode.matches("[A-Z0-9]{3}(-[0-9]+){0,2}$")) {
115 				throw new IllegalArgumentException("Definition must end with a segment name or field lookup, e.g. MSH or MSH-2");
116 			}
117 		} else {
118 			if (lastSlashIndex == theForcedEncode.length() || !theForcedEncode.substring(lastSlashIndex + 1).matches("[A-Z0-9]{3}(-[0-9]+){0,2}$")) {
119 				throw new IllegalArgumentException("Definition must end with a segment name or field lookup, e.g. MSH or MSH-2");
120 			}
121 		}
122 		myForcedEncode.add(theForcedEncode);
123 	}
124 
125 	boolean determineForcedEncodeIncludesTerserPath(String theTerserPath) {
126 		for (String next : getForcedEncode()) {
127 			if (next.startsWith(theTerserPath)) {
128 				return true;
129 			}
130 		}
131 		return false;
132 	}
133 
134 	int determineForcedFieldNumForTerserPath(String theCurrentTerserPath) {
135 		int forceUpToFieldNum = 0;
136 		for (String nextPath : getForcedEncode()) {
137 			if (nextPath.startsWith(theCurrentTerserPath) && nextPath.length() > theCurrentTerserPath.length()) {
138 				int endOfFieldDef = nextPath.indexOf('-', theCurrentTerserPath.length() + 1);
139 				if (endOfFieldDef == -1) {
140 					endOfFieldDef = nextPath.length();
141 				}
142 				String fieldNumString = nextPath.substring(theCurrentTerserPath.length() + 1, endOfFieldDef);
143 				forceUpToFieldNum = Math.max(forceUpToFieldNum, Integer.parseInt(fieldNumString));
144 			}
145 		}
146 		return forceUpToFieldNum;
147 	}
148 
149 	/**
150 	 * Returns the default datatype ("ST", "NM", etc) for an OBX segment with a
151 	 * missing OBX-2 value
152 	 * 
153 	 * @return Returns the default datatype ("ST", "NM", etc) for an OBX segment
154 	 *         with a missing OBX-2 value
155 	 * @see #setDefaultObx2Type(String)
156 	 */
157 	public String getDefaultObx2Type() {
158 		return myDefaultObx2Type;
159 	}
160 
161     /**
162      * Returns the default datatype ("ST", "NM", etc) for an MFE segment with a
163      * missing MFE-5 value
164      *
165      * @return Returns the default datatype ("ST", "NM", etc) for an OBX segment
166      *         with a missing MFE-5 value
167      * @see #setDefaultMfe5Type(String)
168      */
169     public String getDefaultMfe5Type() {
170         return myDefaultMfe5Type;
171     }
172 
173 	/**
174 	 * @return Returns the forced encode strings added by
175 	 *         {@link #addForcedEncode(String)}
176 	 * 
177 	 * @see #addForcedEncode(String)
178 	 * @since 1.3
179 	 */
180 	public Set<String> getForcedEncode() {
181 		return Collections.unmodifiableSet(myForcedEncode);
182 	}
183 
184 	/**
185 	 * @return the ID Generator to be used for generating IDs for new messages
186 	 */
187 	public IDGenerator getIdGenerator() {
188 		return idGenerator;
189 	}
190 
191 	/**
192 	 * Returns the value provides a default datatype ("ST", "NM", etc) for an
193 	 * OBX segment with an invalid OBX-2 value.
194 	 * 
195 	 * @return Returns the value provides a default datatype ("ST", "NM", etc)
196 	 *         for an OBX segment with an invalid OBX-2 value.
197 	 * @see #setInvalidObx2Type(String)
198 	 */
199 	public String getInvalidObx2Type() {
200 		return myInvalidObx2Type;
201 	}
202 
203     /**
204      * Returns the value provides a default datatype ("ST", "NM", etc) for an
205      * MFE segment with an invalid MFE-5 value.
206      *
207      * @return Returns the value provides a default datatype ("ST", "NM", etc)
208      *         for an MFE segment with an invalid MFE-5 value.
209      * @see #setInvalidMfe5Type(String)
210      */
211     public String getInvalidMfe5Type() {
212         return myInvalidMfe5Type;
213     }
214 
215 
216 	/**
217 	 * Returns the behaviour to use when parsing a message and a nonstandard
218 	 * segment is found. Default is
219 	 * {@link #DEFAULT_UNEXPECTED_SEGMENT_BEHAVIOUR}
220      *
221      * @return the behaviour to use when a nonstandard egment is found
222 	 */
223 	public UnexpectedSegmentBehaviourEnum getUnexpectedSegmentBehaviour() {
224 		if (myUnexpectedSegmentBehaviour == null) {
225 			myUnexpectedSegmentBehaviour = DEFAULT_UNEXPECTED_SEGMENT_BEHAVIOUR;
226 		}
227 		return myUnexpectedSegmentBehaviour;
228 	}
229 
230 	/**
231 	 * @see #setXmlDisableWhitespaceTrimmingOnNodeNames(Set)
232 	 */
233 	public Set<String> getXmlDisableWhitespaceTrimmingOnNodeNames() {
234 		return xmlDisableWhitespaceTrimmingOnNodeNames;
235 	}
236 
237 	/**
238 	 * If set to <code>true</code> (default is <code>false</code>) the parser
239 	 * will allow messages to parse, even if they contain a version which is not
240 	 * known to the parser. When operating in this mode, if a message arrives
241 	 * with an unknown version string, the parser will attempt to parse it using
242 	 * a {@link GenericMessage Generic Message} class instead of a specific HAPI
243 	 * structure class. Default is <code>false</code>.
244      *
245      * @return true if parsing messages with unknown versions is allowed
246 	 */
247 	public boolean isAllowUnknownVersions() {
248 		return this.allowUnknownVersions;
249 	}
250 
251 	/**
252      * Returns <code>true</code> if empty segments should still be encoded
253      * if they are mandatory within their message structure.  Default is <code>false</code>.
254 	 * @return <code>true</code> if empty segments should still be encoded
255      *
256 	 * @see #setEncodeEmptyMandatoryFirstSegments(boolean)
257 	 */
258 	public boolean isEncodeEmptyMandatorySegments() {
259 		return myEncodeEmptyMandatorySegments;
260 	}
261 
262 	/**
263      * Returns code>true</code> if subcomponent delimiters in OBX-5 shall be
264      *         ignored. Default is <code>false</code>.
265 	 * @return <code>true</code> if subcomponent delimiters in OBX-5 shall be
266 	 *         ignored
267 	 */
268 	public boolean isEscapeSubcomponentDelimiterInPrimitive() {
269 		return escapeSubcomponentDelimiterInPrimitive;
270 	}
271 
272 	/**
273 	 * Returns <code>true</code> if the parser should parse in non-greedy mode. Default
274 	 * is <code>false</code>
275 	 * 
276 	 * @see #setNonGreedyMode(boolean) for an explanation of non-greedy mode
277 	 */
278 	public boolean isNonGreedyMode() {
279 		return nonGreedyMode;
280 	}
281 
282 	/**
283 	 * If set to <code>true</code> (which is the default), {@link XMLParser XML Parsers}
284 	 * will attempt to pretty-print the XML they generate. This means the messages will look
285 	 * nicer to humans, but may take up slightly more space/bandwidth.
286 	 */
287 	public boolean isPrettyPrintWhenEncodingXml() {
288 		return prettyPrintWhenEncodingXml;
289 	}
290 
291 	/**
292      * Returns <code>true</code> if the parser validates using a configured
293      *         {@link ValidationContext}. Default is <code>true</code>.
294 	 * @return <code>true</code> if the parser validates using a configured
295 	 *         {@link ValidationContext}
296 	 */
297 	public boolean isValidating() {
298 		return validating;
299 	}
300 
301 	/**
302 	 * @see #setXmlDisableWhitespaceTrimmingOnAllNodes(boolean)
303 	 */
304 	public boolean isXmlDisableWhitespaceTrimmingOnAllNodes() {
305 		return xmlDisableWhitespaceTrimmingOnAllNodes;
306 	}
307 
308 	/**
309 	 * Removes a forced encode entry
310 	 *
311      * @param theForcedEncode path definition to be removed
312 	 * @see #addForcedEncode(String)
313 	 * @since 1.3
314 	 */
315 	public void removeForcedEncode(String theForcedEncode) {
316 		if (theForcedEncode == null) {
317 			throw new NullPointerException("forced encode may not be null");
318 		}
319 
320 		myForcedEncode.remove(theForcedEncode);
321 	}
322 
323 	/**
324 	 * If set to <code>true</code> (default is <code>false</code>) the parser
325 	 * will allow messages to parse, even if they contain a version which is not
326 	 * known to the parser. When operating in this mode, if a message arrives
327 	 * with an unknown version string, the parser will attempt to parse it using
328 	 * a {@link GenericMessage Generic Message} class instead of a specific HAPI
329 	 * structure class.
330      *
331      * @param theAllowUnknownVersions true if parsing unknown versions shall be allowed
332 	 */
333 	public void setAllowUnknownVersions(boolean theAllowUnknownVersions) {
334 		allowUnknownVersions = theAllowUnknownVersions;
335 	}
336 
337 	/**
338 	 * <p>
339 	 * If this property is set, the value provides a default datatype ("ST",
340 	 * "NM", etc) for an OBX segment with a missing OBX-2 value. This is useful
341 	 * when parsing messages from systems which do not correctly populate OBX-2.
342 	 * </p>
343 	 * <p>
344 	 * For example, if this property is set to "ST", and the following OBX
345 	 * segment is encountered:
346 	 * 
347 	 * <pre>
348 	 * OBX|||||This is a value
349 	 * </pre>
350 	 * 
351 	 * It will be parsed as though it had read:
352 	 * 
353 	 * <pre>
354 	 * OBX||ST|||This is a value
355 	 * </pre>
356 	 * 
357 	 * </p>
358 	 * <p>
359 	 * Note that this configuration can also be set globally using the system
360 	 * property {@link FixFieldDataType#DEFAULT_OBX2_TYPE_PROP}, but any value provided to
361 	 * {@link ParserConfiguration} takes priority over the system property.
362 	 * </p>
363 	 * 
364 	 * @param theDefaultObx2Type
365 	 *            If this property is set, the value provides a default datatype
366 	 *            ("ST", "NM", etc) for an OBX segment with a missing OBX-2
367 	 *            value
368 	 * @see #setInvalidObx2Type(String)
369 	 * @see FixFieldDataType#INVALID_OBX2_TYPE_PROP
370 	 */
371 	public void setDefaultObx2Type(String theDefaultObx2Type) {
372 		myDefaultObx2Type = theDefaultObx2Type;
373 	}
374 
375     /**
376      * <p>
377      * If this property is set, the value provides a default datatype ("ST",
378      * "NM", etc) for an MFE segment with a missing MFE-5 value. This is useful
379      * when parsing messages from systems which do not correctly populate MFE-5.
380      * </p>
381      * <p>
382      * For example, if this property is set to "ST", and the following MFE
383      * segment is encountered:
384      *
385      * <pre>
386      * MFE||||This is a value
387      * </pre>
388      *
389      * It will be parsed as though it had read:
390      *
391      * <pre>
392      * MFE||||This is a value|ST
393      * </pre>
394      *
395      * </p>
396      * <p>
397      * Note that this configuration can also be set globally using the system
398      * property {@link FixFieldDataType#DEFAULT_MFE5_TYPE_PROP}, but any value provided to
399      * {@link ParserConfiguration} takes priority over the system property.
400      * </p>
401      *
402      * @param theDefaultMfe5Type
403      *            If this property is set, the value provides a default datatype
404      *            ("ST", "NM", etc) for an MFE segment with a missing MFE-5
405      *            value
406      * @see #setInvalidMfe5Type(String)
407      * @see FixFieldDataType#DEFAULT_MFE5_TYPE_PROP
408      */
409     public void setDefaultMfe5Type(String theDefaultMfe5Type) {
410         myDefaultMfe5Type = theDefaultMfe5Type;
411     }
412 
413 	/**
414 	 * <p>
415 	 * If set to <code>true</code> (default is <code>true</code>), when encoding
416 	 * a group using the PipeParser where the first segment is required, but no
417 	 * data has been populated in that segment, the empty segment is now still
418 	 * encoded if needed as a blank segment in order to give parsers a hint
419 	 * about which group subsequent segments are in. This helps to ensure that
420 	 * messages can be "round tripped", meaning that a message which is parsed,
421 	 * encoded, and then re-parsed should contain exactly the same structure
422 	 * from beginning to end.
423 	 * </p>
424 	 * <p>
425 	 * </p>
426 	 * For example, in an ORU^R01 message with a populated OBX segment, but no
427 	 * data in the mandatory OBR segment which begins the ORDER_OBSERVATION
428 	 * group the message would still contain an empty OBR segment when encoded:
429 	 * 
430 	 * <pre>
431 	 * 	MSH|^~\&|REG|W|||201103230042||ORU^R01|32153168|P|2.5
432 	 * 	OBR|
433 	 * 	OBX||ST|||Value Data
434 	 * </pre>
435 	 * 
436 	 * Previously, the following encoding would have occurred, which would have
437 	 * incorrectly been parsed as having a custom OBX segment instead of having
438 	 * a normal ORDER_OBSERVATION group:
439 	 * 
440 	 * <pre>
441 	 * 	MSH|^~\&|REG|W|||201103230042||ORU^R01|32153168|P|2.5
442 	 * 	OBX||ST|||Value Data
443 	 * </pre>
444 	 * 
445 	 * @param theEncodeEmptyMandatorySegments
446 	 *            If set to <code>true</code> (default is <code>true</code>),
447 	 *            when encoding a group using the PipeParser where the first
448 	 *            segment is required, but no data has been populated in that
449 	 *            segment, the empty segment is now still encoded if needed as a
450 	 *            blank segment in order to give parsers a hint about which
451 	 *            group subsequent segments are in
452 	 */
453 	public void setEncodeEmptyMandatoryFirstSegments(boolean theEncodeEmptyMandatorySegments) {
454 		myEncodeEmptyMandatorySegments = theEncodeEmptyMandatorySegments;
455 	}
456 
457 	/**
458 	 * Set to <code>true</code> if subcomponent delimiters in OBX-5 shall be
459 	 * ignored
460      * @param escapeSubcomponentDelimiterInPrimitive boolean flag to enable or disable this behavior
461 	 */
462 	public void setEscapeSubcomponentDelimiterInPrimitive(boolean escapeSubcomponentDelimiterInPrimitive) {
463 		this.escapeSubcomponentDelimiterInPrimitive = escapeSubcomponentDelimiterInPrimitive;
464 	}
465 
466 	/**
467 	 * @param idGenerator
468 	 *            the {@link IDGenerator} to be used for generating IDs for new
469 	 *            messages, preferable initialized using the methods described
470 	 *            in IDGeneratorFactory.
471 	 * 
472 	 * @see IDGenerator
473 	 */
474 	public void setIdGenerator(IDGenerator idGenerator) {
475 		this.idGenerator = idGenerator;
476 	}
477 
478 	/**
479 	 * <p>
480 	 * If this property is set, the value provides a default datatype ("ST",
481 	 * "NM", etc) for an OBX segment with an invalid OBX-2 value. This is useful
482 	 * when parsing messages from systems which do not correctly populate OBX-2.
483 	 * </p>
484 	 * <p>
485 	 * For example, if this property is set to "ST", and the following OBX
486 	 * segment is encountered:
487 	 * 
488 	 * <pre>
489 	 * OBX||INVALID|||This is a value
490 	 * </pre>
491 	 * 
492 	 * It will be parsed as though it had read:
493 	 * 
494 	 * <pre>
495 	 * OBX||ST|||This is a value
496 	 * </pre>
497 	 * 
498 	 * </p>
499 	 * <p>
500 	 * Note that this configuration can also be set globally using the system
501 	 * property {@link FixFieldDataType#INVALID_OBX2_TYPE_PROP}, but any value provided to
502 	 * {@link ParserConfiguration} takes priority over the system property.
503 	 * </p>
504 	 * 
505 	 * @param theInvalidObx2Type
506 	 *            If this property is set, the value provides a default datatype
507 	 *            ("ST", "NM", etc) for an OBX segment with an invalid OBX-2
508 	 *            value. This is useful when parsing messages from systems which
509 	 *            do not correctly populate OBX-2.
510 	 * @see ParserConfiguration#setDefaultObx2Type(String)
511 	 * @see FixFieldDataType#DEFAULT_OBX2_TYPE_PROP
512 	 */
513 	public void setInvalidObx2Type(String theInvalidObx2Type) {
514 		myInvalidObx2Type = theInvalidObx2Type;
515 	}
516 
517     /**
518      * <p>
519      * If this property is set, the value provides a default datatype ("ST",
520      * "NM", etc) for an MFE segment with an invalid MFE-5 value. This is useful
521      * when parsing messages from systems which do not correctly populate MFE-5.
522      * </p>
523      * <p>
524      * For example, if this property is set to "ST", and the following MFE
525      * segment is encountered:
526      *
527      * <pre>
528      * MFE||||This is a value|INVALID
529      * </pre>
530      *
531      * It will be parsed as though it had read:
532      *
533      * <pre>
534      * MFE||||This is a value|ST
535      * </pre>
536      *
537      * </p>
538      * <p>
539      * Note that this configuration can also be set globally using the system
540      * property {@link FixFieldDataType#INVALID_MFE5_TYPE_PROP}, but any value provided to
541      * {@link ParserConfiguration} takes priority over the system property.
542      * </p>
543      *
544      * @param theInvalidMfe5Type
545      *            If this property is set, the value provides a default datatype
546      *            ("ST", "NM", etc) for an MFE segment with an invalid MFE-5
547      *            value. This is useful when parsing messages from systems which
548      *            do not correctly populate MFE-5.
549      * @see ParserConfiguration#setDefaultMfe5Type(String)
550      * @see FixFieldDataType#INVALID_MFE5_TYPE_PROP
551      */
552     public void setInvalidMfe5Type(String theInvalidMfe5Type) {
553         myInvalidMfe5Type = theInvalidMfe5Type;
554     }
555 
556 	/**
557 	 * If set to <code>true</code> (default is <code>false</code>), pipe parser will be
558 	 * put in non-greedy mode. This setting applies only to {@link PipeParser Pipe Parsers} and
559 	 * will have no effect on {@link XMLParser XML Parsers}.
560 	 * 
561 	 * <p>
562 	 * In non-greedy mode, if the message structure being parsed has an ambiguous
563 	 * choice of where to put a segment because there is a segment matching the
564 	 * current segment name in both a later position in the message, and
565 	 * in an earlier position as a part of a repeating group, the earlier
566 	 * position will be chosen.
567 	 * </p>
568 	 * <p>
569 	 * This is perhaps best explained with an example. Consider the following structure:
570 	 * </p>
571 	 * <pre>
572 	 * MSH
573 	 * GROUP_1 (start)
574 	 * {
575 	 *    AAA
576 	 *    BBB
577 	 *    GROUP_2 (start)
578 	 *    {
579 	 *       AAA
580 	 *    }
581 	 *    GROUP_2 (end)
582 	 * }
583 	 * GROUP_1 (end)
584 	 * </pre>
585 	 * <p>
586 	 * </p>
587 	 * For the above example, consider a message containing the following segments:<br/>
588 	 * <code>MSH<br/>
589 	 * AAA<br/>
590 	 * BBB<br/>
591 	 * AAA</code>
592 	 * </p>
593 	 * <p>
594 	 * In this example, when the second AAA segment is encountered, there are two
595 	 * possible choices. It would be placed in GROUP_2, or it could be placed in 
596 	 * a second repetition of GROUP_1. By default it will be placed in GROUP_2, but
597 	 * in non-greedy mode it will be put in a new repetition of GROUP_1.
598 	 * </p>
599 	 * <p>
600 	 * This mode is useful for example when parsing OML^O21 messages containing
601 	 * multiple orders.
602 	 * </p>
603 	 */
604 	public void setNonGreedyMode(boolean theNonGreedyMode) {
605 		nonGreedyMode = theNonGreedyMode;
606 	}
607 
608 	/**
609 	 * If set to <code>true</code> (which is the default), {@link XMLParser XML Parsers}
610 	 * will attempt to pretty-print the XML they generate. This means the messages will look
611 	 * nicer to humans, but may take up slightly more space/bandwidth.
612 	 */
613 	public void setPrettyPrintWhenEncodingXml(boolean thePrettyPrintWhenEncodingXml) {
614 		prettyPrintWhenEncodingXml = thePrettyPrintWhenEncodingXml;
615 	}
616 
617 	/**
618 	 * Sets the behaviour to use when parsing a message and a nonstandard
619 	 * segment is found
620      *
621      * @param theUnexpectedSegmentBehaviour behaviour to use when a nonstandard segment is found
622      */
623 	public void setUnexpectedSegmentBehaviour(UnexpectedSegmentBehaviourEnum theUnexpectedSegmentBehaviour) {
624 		if (theUnexpectedSegmentBehaviour == null) {
625 			throw new NullPointerException("UnexpectedSegmentBehaviour can not be null");
626 		}
627 		myUnexpectedSegmentBehaviour = theUnexpectedSegmentBehaviour;
628 	}
629 
630 	/**
631 	 * Determines whether the parser validates using a configured
632 	 * {@link ValidationContext} or not. This allows to disable message
633 	 * validation although a validation context is defined.
634 	 * 
635 	 * @param validating
636 	 *            <code>true</code> if parser shall validate, <code>false</code>
637 	 *            if not
638 	 */
639 	public void setValidating(boolean validating) {
640 		this.validating = validating;
641 	}
642 
643     public Escaping getEscaping() {
644         return escaping;
645     }
646 
647     /**
648      * Sets an escaping strategy
649      * @param escaping escaping strategy instance
650      */
651     public void setEscaping(Escaping escaping) {
652         if (escaping == null) {
653             throw new NullPointerException("Escaping can not be null");
654         }
655         this.escaping = escaping;
656     }
657 	/**
658 	 * Configures the XML Parser to treat all whitespace within text nodes as literal, meaning that
659 	 * line breaks, tabs, multiple spaces, etc. will be preserved. If set to <code>true</code>, any values
660 	 * passed to {@link #setXmlDisableWhitespaceTrimmingOnNodeNames(Set)} will be superceded since all
661 	 * whitespace will be treated as literal.
662 	 * <p>
663 	 * Default is <b>false</b>
664 	 * </p> 
665 	 */
666 	public void setXmlDisableWhitespaceTrimmingOnAllNodes(boolean theXmlDisableWhitespaceTrimmingOnAllNodes) {
667 		this.xmlDisableWhitespaceTrimmingOnAllNodes = theXmlDisableWhitespaceTrimmingOnAllNodes;
668 	}
669 
670 	/**
671 	 * Configures the XML Parser to treat all whitespace within the given nodes as literal, meaning that
672 	 * line breaks, tabs, multiple spaces, etc. will be preserved. This method takes individual XML node names
673 	 * as arguments (e.g. "HD.2", or "TX.1").
674 	 * <p>
675 	 * Default is <b>none</b>
676 	 * </p> 
677 	 */
678 	public void setXmlDisableWhitespaceTrimmingOnNodeNames(Set<String> theXmlDisableWhitespaceTrimmingOnNodeNames) {
679 		if (theXmlDisableWhitespaceTrimmingOnNodeNames==null) {
680 			this.xmlDisableWhitespaceTrimmingOnNodeNames = Collections.emptySet();
681 		} else {
682 			this.xmlDisableWhitespaceTrimmingOnNodeNames = theXmlDisableWhitespaceTrimmingOnNodeNames;
683 		}
684 	}
685 
686 	/**
687 	 * Configures the XML Parser to treat all whitespace within the given nodes as literal, meaning that
688 	 * line breaks, tabs, multiple spaces, etc. will be preserved. This method takes individual XML node names
689 	 * as arguments (e.g. "HD.2", or "TX.1").
690 	 * <p>
691 	 * Default is <b>none</b>
692 	 * </p> 
693 	 */
694 	public void setXmlDisableWhitespaceTrimmingOnNodeNames(String... theKeepAsOriginalNodes) {
695 		if (theKeepAsOriginalNodes==null) {
696 			setXmlDisableWhitespaceTrimmingOnNodeNames((Set<String>)null);
697 		} else {
698 			setXmlDisableWhitespaceTrimmingOnNodeNames(new HashSet<>(Arrays.asList(theKeepAsOriginalNodes)));
699 		}
700 	}
701 
702 }