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 "RuleTypeBuilder.java". Description: 010 "RuleBuilder that determines which kind of rule shall be built" 011 012 The Initial Developer of the Original Code is University Health Network. Copyright (C) 013 2004. 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 */ 026package ca.uhn.hl7v2.validation.builder; 027 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Collection; 031import java.util.Collections; 032import java.util.HashSet; 033import java.util.List; 034import java.util.Set; 035 036import ca.uhn.hl7v2.HL7Exception; 037import ca.uhn.hl7v2.Version; 038import ca.uhn.hl7v2.model.Message; 039import ca.uhn.hl7v2.util.Terser; 040import ca.uhn.hl7v2.validation.MessageRule; 041import ca.uhn.hl7v2.validation.PrimitiveTypeRule; 042import ca.uhn.hl7v2.validation.Rule; 043import ca.uhn.hl7v2.Severity; 044import ca.uhn.hl7v2.validation.ValidationException; 045import ca.uhn.hl7v2.validation.impl.AbstractMessageRule; 046import ca.uhn.hl7v2.validation.impl.RuleBinding; 047import ca.uhn.hl7v2.validation.impl.RuleSupport; 048 049/** 050 * Defines the type of rule to be built. 051 * <p/> 052 * The recursive type parameter allows the builder methods common to all subclasses (e.g. 053 * {@link #refersToSection}, {@link #active}, {@link #test}) to return their specific builder type. 054 * 055 * @author Christian Ohr 056 */ 057@SuppressWarnings("serial") 058public class RuleTypeBuilder<S extends RuleTypeBuilder<S, T>, T extends Rule<?>> extends 059 BuilderSupport { 060 061 private List<RuleBinding<? extends Rule<?>>> rules = new ArrayList<RuleBinding<? extends Rule<?>>>(); 062 private Set<Version> versions; 063 private String description; 064 private String sectionReference; 065 private boolean active = true; 066 private Severity severity = Severity.ERROR; 067 068 protected RuleTypeBuilder() { 069 super(); 070 } 071 072 protected RuleTypeBuilder(List<RuleBinding<? extends Rule<?>>> rules, Set<Version> versions) { 073 super(); 074 if (versions.size() == 0) 075 throw new IllegalArgumentException("Must specify a version"); 076 this.rules = rules; 077 this.versions = versions; 078 } 079 080 protected RuleTypeBuilder(List<RuleBinding<? extends Rule<?>>> rules, Version... versions) { 081 super(); 082 if (versions.length == 0) 083 throw new IllegalArgumentException("Must specify a version"); 084 this.rules = rules; 085 this.versions = new HashSet<Version>(Arrays.asList(versions)); 086 } 087 088 @SuppressWarnings("unchecked") 089 protected S instance() { 090 return (S) this; 091 } 092 093 protected List<RuleBinding<? extends Rule<?>>> getRules() { 094 return rules; 095 } 096 097 protected T prepareRule(T rule) { 098 if (rule instanceof RuleSupport) { 099 RuleSupport<?> rs = (RuleSupport<?>) rule; 100 if (description != null) rs.setDescription(description); 101 if (sectionReference != null) rs.setSectionReference(sectionReference); 102 rs.setSeverity(severity); 103 } 104 return rule; 105 } 106 107 /** 108 * Adds a description to the rule 109 * 110 * @param description description 111 * @return this instance to build more rules 112 */ 113 public S description(String description) { 114 this.description = description; 115 return instance(); 116 } 117 118 /** 119 * Adds a HL7 section reference to a rule 120 * 121 * @param sectionReference the section in the HL7 specification 122 * @return this instance to build more rules 123 */ 124 public S refersToSection(String sectionReference) { 125 this.sectionReference = sectionReference; 126 return instance(); 127 } 128 129 /** 130 * Sets the severity of the rule 131 * 132 * @param severity the the severity of the rule 133 * @return this instance to build more rules 134 */ 135 public S severity(Severity severity) { 136 this.severity = severity; 137 return instance(); 138 } 139 140 /** 141 * Marks the rule as being active (default) or inactive 142 * 143 * @param active true if this rule shall be active 144 * @return this instance to build more rules 145 */ 146 public S active(boolean active) { 147 this.active = active; 148 return instance(); 149 } 150 151 /** 152 * Adds the specified rule to the set of rules. 153 * 154 * @param rule the rule to be tested 155 * @return this instance to build more rules 156 */ 157 public S test(T rule) { 158 addRuleBindings(rule); 159 return instance(); 160 } 161 162 /** 163 * Builds {@link PrimitiveTypeRule}s for the specified types 164 * 165 * @param type an array of types 166 * @return this instance to continue building rules 167 */ 168 public PrimitiveRuleBuilder primitive(String... type) { 169 if (type.length == 0) { 170 throw new IllegalArgumentException("Must specify a type"); 171 } 172 return new PrimitiveRuleBuilder(rules, versions, new HashSet<String>(Arrays.asList(type))); 173 } 174 175 /** 176 * Builds {@link MessageRule}s for the specified event types and triggers 177 * 178 * @param eventType Event type, e.g. "ADT", or "*" for all types 179 * @param triggerEvents, e.g. "A01" or "A01,A04", or "*" for all trigger events 180 * @return this instance to continue building rules 181 */ 182 public MessageRuleBuilder message(String eventType, String... triggerEvents) { 183 return new MessageRuleBuilder(rules, versions, eventType, triggerEvents); 184 } 185 186 /** 187 * Builds {@link MessageRule}s for event types and triggers to be specified 188 * using the returned MessageExpressionBuilder. 189 * 190 * @return MessageExpressionBuilder instance to continue building rules 191 */ 192 public MessageExpressionBuilder message() { 193 return new MessageExpressionBuilder(); 194 } 195 196 /** 197 * Builds {@link MessageRule}s for the specified encoding 198 * 199 * @param encoding "XML" or "VB" 200 * @return this instance to continue building rules 201 */ 202 public EncodingRuleBuilder encoding(String encoding) { 203 return new EncodingRuleBuilder(rules, versions, encoding); 204 } 205 206 /** 207 * Add {@link RuleBinding}s for the rule that have been built 208 * 209 * @param rule the rule for which bindings shall be added 210 */ 211 protected void addRuleBindings(T rule) { 212 if (Version.allVersions(versions)) { 213 // Save some bindings when all HL7 versions are affected 214 rules.addAll(getRuleBindings(rule, "*")); 215 } else { 216 for (Version version : versions) { 217 rules.addAll(getRuleBindings(rule, version.getVersion())); 218 } 219 } 220 } 221 222 /** 223 * Builder implementation must overwrite this method to return all {@link RuleBinding}s for 224 * rules that have been built. 225 * 226 * @param rule the rule for which bindings shall be retrieved 227 * @param version the HL7 version for which bindings shall be retrieved 228 * @return a collection of {@link RuleBinding}s 229 */ 230 @SuppressWarnings("unchecked") 231 protected Collection<RuleBinding<T>> getRuleBindings(T rule, String version) { 232 return (Collection<RuleBinding<T>>) Collections.EMPTY_LIST; 233 } 234 235 protected Collection<RuleBinding<T>> activate(Collection<RuleBinding<T>> bindings) { 236 for (RuleBinding<T> ruleBinding : bindings) { 237 ruleBinding.setActive(active); 238 } 239 return bindings; 240 } 241 242 // for tests only 243 Set<Version> getVersions() { 244 return versions; 245 } 246 247 /** 248 * Helper builder when the events are not given explicitly but in form of an expression. 249 */ 250 public class MessageExpressionBuilder { 251 252 /** 253 * Applies {@link MessageRule}s for all event types and trigger events 254 * 255 * @return rule builder 256 */ 257 public MessageRuleBuilder all() { 258 return new MessageRuleBuilder(rules, versions, "*", "*"); 259 } 260 261 /** 262 * Applies {@link MessageRule}s for all trigger events of a given event type 263 * 264 * @param eventType event type, e.g. "ADT" 265 * @return rule builder 266 */ 267 public MessageRuleBuilder allOfEventType(String eventType) { 268 return new MessageRuleBuilder(rules, versions, eventType, "*"); 269 } 270 271 /** 272 * Applies a {@link MessageRule} for all event types and trigger events, checking 273 * whether the message is of the specified event type and trigger event(s) 274 * 275 * @param triggerEvents trigger events, e.g. "A01", "A04" 276 * @return rule builder 277 */ 278 public MessageRuleBuilder rejectOtherThan(final String... triggerEvents) { 279 final Set<String> triggers = new HashSet<String>(Arrays.asList(triggerEvents)); 280 return all().test(new AbstractMessageRule() { 281 public ValidationException[] apply(Message message) { 282 try { 283 Terser t = new Terser(message); 284 String eventType = t.get("MSH-9-1"); 285 String triggerEvent = t.get("MSH-9-2"); 286 return triggers.contains(triggerEvent) ? 287 passed() : 288 failed(eventType + "^" + triggerEvent + " is not accepted"); 289 } catch (HL7Exception e) { 290 return failed(e); 291 } 292 } 293 }); 294 295 } 296 297 } 298}