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 "ValidationContextImpl.java".  Description: 
010"A default implementation of ValidationContext." 
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.impl;
027
028import java.io.Serializable;
029import java.util.*;
030
031import ca.uhn.hl7v2.model.Primitive;
032import ca.uhn.hl7v2.validation.EncodingRule;
033import ca.uhn.hl7v2.validation.MessageRule;
034import ca.uhn.hl7v2.validation.PrimitiveTypeRule;
035import ca.uhn.hl7v2.validation.Rule;
036import ca.uhn.hl7v2.validation.ValidationContext;
037import ca.uhn.hl7v2.validation.builder.ValidationRuleBuilder;
038
039/**
040 * A default implementation of <code>ValidationContext</code>.
041 * 
042 * @author Bryan Tripp
043 * @author Christian Ohr
044 */
045@SuppressWarnings("serial")
046public class ValidationContextImpl implements ValidationContext, Serializable {
047
048        private List<RuleBinding<PrimitiveTypeRule>> myPrimitiveRuleBindings;
049        private List<RuleBinding<MessageRule>> myMessageRuleBindings;
050        private List<RuleBinding<EncodingRule>> myEncodingRuleBindings;
051
052    protected Map<String, Collection<PrimitiveTypeRule>> primitiveRuleCache;
053    protected Map<String, Collection<MessageRule>> messageRuleCache;
054    protected Map<String, Collection<EncodingRule>> encodingRuleCache;
055
056        public ValidationContextImpl() {
057                myPrimitiveRuleBindings = new ArrayList<RuleBinding<PrimitiveTypeRule>>();
058                myMessageRuleBindings = new ArrayList<RuleBinding<MessageRule>>();
059                myEncodingRuleBindings = new ArrayList<RuleBinding<EncodingRule>>();
060        initCaches();
061        }
062        
063        ValidationContextImpl(ValidationRuleBuilder builder) {
064                this();
065                for (RuleBinding<? extends Rule<?>> ruleBinding : builder.initialize()) {
066                        if (ruleBinding instanceof MessageRuleBinding)
067                                myMessageRuleBindings.add((MessageRuleBinding)ruleBinding);
068                        else if (ruleBinding instanceof EncodingRuleBinding)
069                                myEncodingRuleBindings.add((EncodingRuleBinding)ruleBinding);
070                        else if (ruleBinding instanceof PrimitiveTypeRuleBinding)
071                                myPrimitiveRuleBindings.add((PrimitiveTypeRuleBinding)ruleBinding);
072                }
073        }
074
075    /**
076     * Initializes caches for the three rule types. Used to accelerate the identification
077     * of the rules that apply to a message or primitive.
078     *
079     * @see #newRuleCache(int)
080     * @see #primitiveRuleCache
081     * @see #messageRuleCache
082     * @see #encodingRuleCache
083     */
084    protected void initCaches() {
085        primitiveRuleCache = newRuleCache(100);
086        messageRuleCache = newRuleCache(100);
087        encodingRuleCache = newRuleCache(10);
088    }
089
090    /**
091         * @see ValidationContext#getPrimitiveRules(String, String, Primitive)
092         * @param theType ignored
093         */
094        public Collection<PrimitiveTypeRule> getPrimitiveRules(String theVersion, String theTypeName, Primitive theType) {
095        Collection<PrimitiveTypeRule> rules = primitiveRuleCache.get(theVersion + theTypeName);
096        if (rules == null) {
097            rules = getRules(myPrimitiveRuleBindings, theVersion, theTypeName);
098            primitiveRuleCache.put(theVersion + theTypeName, rules);
099        }
100        return rules;
101        }
102
103        /**
104         * @return a List of <code>RuleBinding</code>s for
105         *         <code>PrimitiveTypeRule</code>s.
106         */
107        public List<RuleBinding<PrimitiveTypeRule>> getPrimitiveRuleBindings() {
108                return myPrimitiveRuleBindings;
109        }
110                
111
112        /**
113         * @see ValidationContext#getMessageRules(java.lang.String, java.lang.String, java.lang.String)
114         */
115        public Collection<MessageRule> getMessageRules(String theVersion, String theMessageType, String theTriggerEvent) {
116        Collection<MessageRule> rules = messageRuleCache.get(theVersion + theMessageType + theTriggerEvent);
117        if (rules == null) {
118            rules = getRules(myMessageRuleBindings, theVersion, theMessageType + "^" + theTriggerEvent);
119            messageRuleCache.put(theVersion + theMessageType + theTriggerEvent, rules);
120        }
121        return rules;
122        }
123
124        /**
125         * @return a List of <code>RuleBinding</code>s for <code>MessageRule</code>s.
126         */
127        public List<RuleBinding<MessageRule>> getMessageRuleBindings() {
128                return myMessageRuleBindings;
129        }
130
131        /**
132         * @see ca.uhn.hl7v2.validation.ValidationContext#getEncodingRules(java.lang.String,
133         *      java.lang.String)
134         */
135        public Collection<EncodingRule> getEncodingRules(String theVersion, String theEncoding) {
136        Collection<EncodingRule> rules = encodingRuleCache.get(theVersion + theEncoding);
137        if (rules == null) {
138            rules = getRules(myEncodingRuleBindings, theVersion, theEncoding);
139            encodingRuleCache.put(theVersion + theEncoding, rules);
140        }
141        return rules;
142        }
143
144        /**
145         * @return a List of <code>RuleBinding</code>s for <code>EncodingRule</code>s.
146         */
147        public List<RuleBinding<EncodingRule>> getEncodingRuleBindings() {
148                return myEncodingRuleBindings;
149        }
150        
151        private <T extends Rule<?>> Collection<T> getRules(List<RuleBinding<T>> bindings, String version, String scope) {
152                List<T> active = new ArrayList<T>(bindings.size());
153                for (RuleBinding<T> binding : bindings) {
154                        if (applies(binding, version, scope))
155                                active.add(binding.getRule());
156                }
157                return active;
158        }
159
160        private boolean applies(RuleBinding<?> binding, String version, String scope) {
161                return (binding.getActive() && binding.appliesToVersion(version) && binding.appliesToScope(scope));
162        }
163
164
165    /**
166     * Simple cache implementation that keeps at most {@link #size} elements around
167     *
168     * @param <T>
169     */
170    private static class RuleCache<T extends Rule<?>> extends LinkedHashMap<String, Collection<T>> {
171
172        private final int size;
173
174        private RuleCache(int size) {
175            super(size);
176            this.size = size;
177        }
178
179        @Override
180        protected boolean removeEldestEntry(Map.Entry<String, Collection<T>> eldest) {
181            return size() > size;
182        }
183
184    }
185
186    protected static <T extends Rule<?>> Map<String, Collection<T>> newRuleCache(int size) {
187        Map<String, Collection<T>> cache = new RuleCache<T>(size);
188        return Collections.synchronizedMap(cache);
189    }
190}