View Javadoc

1   /**
2   The contents of this file are subject to the Mozilla Public License Version 1.1 
3   (the "License"); you may not use this file except in compliance with the License. 
4   You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
5   Software distributed under the License is distributed on an "AS IS" basis, 
6   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
7   specific language governing rights and limitations under the License. 
8   
9   The Original Code is "AbstractValidator.java".  Description: 
10  "Abstract implementation of a message validator." 
11  
12  The Initial Developer of the Original Code is University Health Network. Copyright (C) 
13  2012.  All Rights Reserved. 
14  
15  Contributor(s): ______________________________________. 
16  
17  Alternatively, the contents of this file may be used under the terms of the 
18  GNU General Public License (the "GPL"), in which case the provisions of the GPL are 
19  applicable instead of those above.  If you wish to allow use of your version of this 
20  file only under the terms of the GPL and not to allow others to use your version 
21  of this file under the MPL, indicate your decision by deleting  the provisions above 
22  and replace  them with the notice and other provisions required by the GPL License.  
23  If you do not delete the provisions above, a recipient may use your version of 
24  this file under either the MPL or the GPL. 
25   */
26  package ca.uhn.hl7v2.validation;
27  
28  import java.util.ArrayList;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  import ca.uhn.hl7v2.HL7Exception;
36  import ca.uhn.hl7v2.Location;
37  import ca.uhn.hl7v2.model.Composite;
38  import ca.uhn.hl7v2.model.Message;
39  import ca.uhn.hl7v2.model.Primitive;
40  import ca.uhn.hl7v2.model.Segment;
41  import ca.uhn.hl7v2.model.Structure;
42  import ca.uhn.hl7v2.model.Type;
43  import ca.uhn.hl7v2.model.Varies;
44  import ca.uhn.hl7v2.util.ReadOnlyMessageIterator;
45  import ca.uhn.hl7v2.util.Terser;
46  
47  /**
48   * Abstract implementation of a message validator.
49   * 
50   * @param <R> The type parameter R denotes the result type of the validation
51   *            process.
52   * 
53   * @author Christian Ohr
54   */
55  public abstract class AbstractValidator<R> implements Validator<R> {
56  
57  	private static final Logger LOG = LoggerFactory.getLogger(AbstractValidator.class);
58  
59  	/**
60  	 * Calls {@link #initializeHandler()} to obtain a default instance of a
61  	 * {@link ValidationExceptionHandler} before starting the validation.
62  	 * 
63  	 * @see ca.uhn.hl7v2.validation.Validator#validate(ca.uhn.hl7v2.model.Message)
64  	 */
65  	public R validate(Message message) throws HL7Exception {
66  		return validate(message, initializeHandler());
67  	}
68  
69  	/**
70  	 * @see ca.uhn.hl7v2.validation.Validator#validate(ca.uhn.hl7v2.model.Message,
71  	 *      ca.uhn.hl7v2.validation.ValidationExceptionHandler)
72  	 */
73  	public R validate(Message message, ValidationExceptionHandler<R> handler) throws HL7Exception {
74  		if (message == null) {
75  			throw new NullPointerException("Message may not be null");
76  		}
77  		if (handler == null) {
78  			throw new NullPointerException("ValidationExceptionHandler may not be null");
79  		}
80  		handler.setValidationSubject(message);
81  		// testPrimitiveRules(message, handler); TODO this slows down parser 3x
82  		testMessageRules(message, handler);
83  		return handler.result();
84  	}
85  
86  	private void testMessageRules(Message message, ValidationExceptionHandler<R> handler)
87  			throws HL7Exception {
88  		Terser t = new Terser(message);
89  		String messageType = t.get("MSH-9-1");
90  		String triggerEvent = t.get("MSH-9-2");
91  		List<MessageRule> rules = new ArrayList<MessageRule>();
92  		if (getValidationContext() != null) {
93  			rules.addAll(getValidationContext().getMessageRules(message.getVersion(), messageType,
94  					triggerEvent));
95  		}
96  		LOG.debug("Validating message against {} message rules", rules.size());
97  		for (MessageRule rule : rules) {
98  			ValidationException[] ex = rule.apply(message);
99  			if (ex != null && ex.length > 0) {
100 				handler.onExceptions(ex);
101 			}
102 		}
103 	}
104 
105 	private void testPrimitiveRules(Message message, ValidationExceptionHandler<R> handler)
106 			throws HL7Exception {
107 		LOG.debug("Validating message against primitive type rules");
108 		for (Iterator<Structure> iter = ReadOnlyMessageIterator
109 				.createPopulatedSegmentIterator(message); iter.hasNext();) {
110 			Segment s = (Segment) iter.next();
111 			for (int field = 1; field <= s.numFields(); field++) {
112 				Type[] t = s.getField(field);
113 				for (int rep = 0; rep < t.length; rep++) {
114 					Location location = new Location();
115 					location.setSegmentName(s.getName());
116 					location.setField(field);
117 					location.setFieldRepetition(rep);
118 					testType(t[rep], handler, location);
119 				}
120 			}
121 		}
122 	}
123 
124 	private void testType(Type type, ValidationExceptionHandler<R> handler, Location l) {
125 		if (type instanceof Composite) {
126 			Type[] components = ((Composite) type).getComponents();
127 			for (int comp = 0; comp < components.length; comp++) {
128 				Location location = new Location(l);
129 				location.setComponent(comp + 1);
130 				testComponent(components[comp], handler, location);
131 			}
132 		} else if (type instanceof Varies) {
133 			testType(((Varies) type).getData(), handler, l);
134 		} else {
135 			testPrimitive((Primitive) type, handler, l);
136 		}
137 	}
138 
139 	private void testComponent(Type type, ValidationExceptionHandler<R> handler, Location l) {
140 		if (type instanceof Composite) {
141 			Type[] component = ((Composite) type).getComponents();
142 			for (int sub = 0; sub < component.length; sub++) {
143 				Location location = new Location(l);
144 				location.setSubcomponent(sub + 1);
145 				testSubComponent(component[sub], handler, location);
146 			}
147 		} else if (type instanceof Varies) {
148 			testComponent(((Varies) type).getData(), handler, l);
149 		} else {
150 			testPrimitive((Primitive) type, handler, l);
151 		}
152 	}
153 
154 	private void testSubComponent(Type type, ValidationExceptionHandler<R> handler, Location l) {
155 		if (type instanceof Primitive) {
156 			testPrimitive((Primitive) type, handler, l);
157 		} else if (type instanceof Varies) {
158 			testSubComponent(((Varies) type).getData(), handler, l);
159 		}
160 	}
161 
162 	private void testPrimitive(Primitive p, ValidationExceptionHandler<R> handler, Location l) {
163 		List<PrimitiveTypeRule> rules = new ArrayList<PrimitiveTypeRule>();
164 		Message m = p.getMessage();
165 		if (getValidationContext() != null) {
166 			rules.addAll(getValidationContext().getPrimitiveRules(m.getVersion(), p.getName(), p));
167 		}
168 		for (PrimitiveTypeRule rule : rules) {
169 			ValidationException[] exceptions = rule.apply(p.getValue());
170 			for (ValidationException ve : exceptions) {
171                 ve.setLocation(l);
172 			}
173 			if (exceptions.length > 0) {
174 				handler.onExceptions(exceptions);
175 			}
176 		}
177 	}
178 
179 	/**
180 	 * Calls {@link #initializeHandler()} to obtain a default instance of a
181 	 * {@link ValidationExceptionHandler} before starting the validation.
182 	 * 
183 	 * @see ca.uhn.hl7v2.validation.Validator#validate(Message,
184 	 *      ValidationExceptionHandler)
185 	 */
186 	public R validate(String message, boolean isXML, String version) throws HL7Exception {
187 		return validate(message, isXML, version, initializeHandler());
188 	}
189 
190 	/**
191 	 * @see ca.uhn.hl7v2.validation.Validator#validate(java.lang.String,
192 	 *      boolean, java.lang.String,
193 	 *      ca.uhn.hl7v2.validation.ValidationExceptionHandler)
194 	 */
195 	public R validate(String message, boolean isXML, String version,
196 			ValidationExceptionHandler<R> handler) throws HL7Exception {
197 		if (message == null) {
198 			throw new NullPointerException("Message may not be null");
199 		}
200 		if (handler == null) {
201 			throw new NullPointerException("ValidationExceptionHandler may not be null");
202 		}
203 		handler.setValidationSubject(message);
204 		List<EncodingRule> rules = new ArrayList<EncodingRule>();
205 		if (getValidationContext() != null) {
206 			rules.addAll(getValidationContext().getEncodingRules(version, isXML ? "XML" : "ER7"));
207 		}
208 		LOG.debug("Validating message against {} encoding rules", rules.size());
209 		for (EncodingRule rule : rules) {
210 			ValidationException[] ex = rule.apply(message);
211 			if (ex != null && ex.length > 0) {
212 				handler.onExceptions(ex);
213 			}
214 		}
215 		return handler.result();
216 	}
217 
218 	protected abstract ValidationContext getValidationContext();
219 
220 	protected abstract ValidationExceptionHandler<R> initializeHandler();
221 
222 }