001/**
002The 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. 
004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
005Software distributed under the License is distributed on an "AS IS" basis, 
006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 
007specific language governing rights and limitations under the License. 
008
009The Original Code is "RuleTypeBuilder.java".  Description: 
010"RuleBuilder that determines which kind of rule shall be built" 
011
012The Initial Developer of the Original Code is University Health Network. Copyright (C) 
0132004.  All Rights Reserved. 
014
015Contributor(s): ______________________________________. 
016
017Alternatively, the contents of this file may be used under the terms of the 
018GNU General Public License (the "GPL"), in which case the provisions of the GPL are 
019applicable instead of those above.  If you wish to allow use of your version of this 
020file only under the terms of the GPL and not to allow others to use your version 
021of this file under the MPL, indicate your decision by deleting  the provisions above 
022and replace  them with the notice and other provisions required by the GPL License.  
023If you do not delete the provisions above, a recipient may use your version of 
024this 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.Version;
037import ca.uhn.hl7v2.validation.MessageRule;
038import ca.uhn.hl7v2.validation.PrimitiveTypeRule;
039import ca.uhn.hl7v2.validation.Rule;
040import ca.uhn.hl7v2.Severity;
041import ca.uhn.hl7v2.validation.impl.RuleBinding;
042import ca.uhn.hl7v2.validation.impl.RuleSupport;
043
044/**
045 * Defines the type of rule to be built.
046 * <p>
047 * The recursive type parameter allows the builder methods common to all subclasses (e.g.
048 * {@link #refersToSection}, {@link #active}, {@link #test}) to return their specific builder type.
049 * 
050 * @author Christian Ohr
051 */
052@SuppressWarnings("serial")
053public class RuleTypeBuilder<S extends RuleTypeBuilder<S, T>, T extends Rule<?>> extends
054                BuilderSupport {
055
056        private List<RuleBinding<? extends Rule<?>>> rules = new ArrayList<RuleBinding<? extends Rule<?>>>();
057        private Set<Version> versions;
058        private String description;
059        private String sectionReference;
060        private boolean active = true;
061    private Severity severity = Severity.ERROR;
062
063        protected RuleTypeBuilder() {
064                super();
065        }
066        
067        protected RuleTypeBuilder(List<RuleBinding<? extends Rule<?>>> rules, Set<Version> versions) {
068                super();
069                if (versions.size() == 0)
070                        throw new IllegalArgumentException("Must specify a version");
071                this.rules = rules;
072                this.versions = versions;
073        }
074
075        protected RuleTypeBuilder(List<RuleBinding<? extends Rule<?>>> rules, Version... versions) {
076                super();
077                if (versions.length == 0)
078                        throw new IllegalArgumentException("Must specify a version");
079                this.rules = rules;
080                this.versions = new HashSet<Version>(Arrays.asList(versions));
081        }
082
083        @SuppressWarnings("unchecked")
084        protected S instance() {
085                return (S) this;
086        }
087        
088        protected List<RuleBinding<? extends Rule<?>>> getRules() {
089                return rules;
090        }
091
092    protected T prepareRule(T rule) {
093        if (rule instanceof RuleSupport) {
094            RuleSupport<?> rs = (RuleSupport<?>)rule;
095            if (description != null) rs.setDescription(description);
096            if (sectionReference != null) rs.setSectionReference(sectionReference);
097            rs.setSeverity(severity);
098        }
099        return rule;
100    }
101
102        /**
103         * Adds a description to the rule
104         * 
105         * @param description description
106         * @return this instance to build more rules
107         */
108        public S description(String description) {
109                this.description = description;
110                return instance();
111        }
112
113        /**
114         * Adds a HL7 section reference to a rule
115         * 
116         * @param sectionReference the section in the HL7 specification
117         * @return this instance to build more rules
118         */
119        public S refersToSection(String sectionReference) {
120                this.sectionReference = sectionReference;
121                return instance();
122        }
123
124    /**
125     * Sets the severity of the rule
126     *
127     * @param severity the the severity of the rule
128     * @return this instance to build more rules
129     */
130    public S severity(Severity severity) {
131        this.severity = severity;
132        return instance();
133    }
134
135        /**
136         * Marks the rule as being active (default) or inactive
137         * 
138         * @param active true if this rule shall be active
139         * @return this instance to build more rules
140         */
141        public S active(boolean active) {
142                this.active = active;
143                return instance();
144        }
145
146        /**
147         * Adds the specified rule to the set of rules.
148         * 
149         * @param rule the rule to be tested
150         * @return this instance to build more rules
151         */
152        public S test(T rule) {
153                addRuleBindings(rule);
154                return instance();
155        }
156
157        /**
158         * Builds {@link PrimitiveTypeRule}s for the specified types
159         * 
160         * @param type an array of types
161         * @return this instance to continue building rules
162         */
163        public PrimitiveRuleBuilder primitive(String... type) {
164                if (type.length == 0) {
165                        throw new IllegalArgumentException("Must specify a type");
166                }
167                return new PrimitiveRuleBuilder(rules, versions, new HashSet<String>(Arrays.asList(type)));
168        }
169
170        /**
171         * Builds {@link MessageRule}s for the specified event types and triggers
172         * 
173         * @param eventType Event type, e.g. "ADT", or "*" for all types
174         * @param triggerEvent, e.g. "A01" or "*" for all trigger events
175         * @return this instance to continue building rules
176         */
177        public MessageRuleBuilder message(String eventType, String triggerEvent) {
178                return new MessageRuleBuilder(rules, versions, eventType, triggerEvent);
179        }
180
181    /**
182     * Builds {@link MessageRule}s for event types and triggers to be specified
183     * using the returned MessageExpressionBuilder.
184     *
185     * @return MessageExpressionBuilder instance to continue building rules
186     */
187        public MessageExpressionBuilder message() {
188                return new MessageExpressionBuilder();
189        }
190
191        /**
192         * Builds {@link MessageRule}s for the specified encoding
193         * 
194         * @param encoding "XML" or "VB"
195         * @return this instance to continue building rules
196         */
197        public EncodingRuleBuilder encoding(String encoding) {
198                return new EncodingRuleBuilder(rules, versions, encoding);
199        }
200
201        /**
202         * Add {@link RuleBinding}s for the rule that have been built
203         * 
204         * @param rule the rule for which bindings shall be added
205         */
206        protected void addRuleBindings(T rule) {
207                if (Version.allVersions(versions)) {
208                        // Save some bindings when all HL7 versions are affected
209                        rules.addAll(getRuleBindings(rule, "*"));
210                } else {
211                        for (Version version : versions) {
212                                rules.addAll(getRuleBindings(rule, version.getVersion()));
213                        }
214                }
215        }
216
217        /**
218         * Builder implementation must overwrite this method to return all {@link RuleBinding}s for
219         * rules that have been built.
220         * 
221         * @param rule the rule for which bindings shall be retrieved
222         * @param version the HL7 version for which bindings shall be retrieved
223         * @return a collection of {@link RuleBinding}s
224         */
225        @SuppressWarnings("unchecked")
226        protected Collection<RuleBinding<T>> getRuleBindings(T rule, String version) {
227                return (Collection<RuleBinding<T>>) Collections.EMPTY_LIST;
228        }
229
230        protected Collection<RuleBinding<T>> activate(Collection<RuleBinding<T>> bindings) {
231                for (RuleBinding<T> ruleBinding : bindings) {
232                        ruleBinding.setActive(active);
233                }
234                return bindings;
235        }
236
237        // for tests only
238        Set<Version> getVersions() {
239                return versions;
240        }
241
242        /**
243         * Helper builder when the versions are not given explicitly but in form of an expression.
244         */
245        public class MessageExpressionBuilder {
246
247        /**
248         * Applies {@link MessageRule}s for all event types and trigger events
249         * @return rule builder
250         */
251                public MessageRuleBuilder all() {
252                        return new MessageRuleBuilder(rules, versions, "*", "*");
253                }
254
255        /**
256         * Applies {@link MessageRule}s for all trigger events of a given event type
257         * @param eventType  event type, e.g. "ADT"
258         * @return rule builder
259         */
260                public MessageRuleBuilder allOfEventType(String eventType) {
261                        return new MessageRuleBuilder(rules, versions, eventType, "*");
262                }
263
264        }
265
266}