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 "ValidationContextImpl.java".  Description: 
10  "A default implementation of ValidationContext." 
11  
12  The Initial Developer of the Original Code is University Health Network. Copyright (C) 
13  2004.  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.impl;
27  
28  import java.io.Serializable;
29  import java.util.*;
30  
31  import ca.uhn.hl7v2.model.Primitive;
32  import ca.uhn.hl7v2.validation.EncodingRule;
33  import ca.uhn.hl7v2.validation.MessageRule;
34  import ca.uhn.hl7v2.validation.PrimitiveTypeRule;
35  import ca.uhn.hl7v2.validation.Rule;
36  import ca.uhn.hl7v2.validation.ValidationContext;
37  import ca.uhn.hl7v2.validation.builder.ValidationRuleBuilder;
38  
39  /**
40   * A default implementation of <code>ValidationContext</code>.
41   * 
42   * @author Bryan Tripp
43   * @author Christian Ohr
44   */
45  @SuppressWarnings("serial")
46  public class ValidationContextImpl implements ValidationContext, Serializable {
47  
48  	private final List<RuleBinding<PrimitiveTypeRule>> myPrimitiveRuleBindings;
49  	private final List<RuleBinding<MessageRule>> myMessageRuleBindings;
50  	private final List<RuleBinding<EncodingRule>> myEncodingRuleBindings;
51  
52      protected Map<String, Collection<PrimitiveTypeRule>> primitiveRuleCache;
53      protected Map<String, Collection<MessageRule>> messageRuleCache;
54      protected Map<String, Collection<EncodingRule>> encodingRuleCache;
55  
56  	public ValidationContextImpl() {
57  		myPrimitiveRuleBindings = new ArrayList<>();
58  		myMessageRuleBindings = new ArrayList<>();
59  		myEncodingRuleBindings = new ArrayList<>();
60          initCaches();
61  	}
62  	
63  	ValidationContextImpl(ValidationRuleBuilder builder) {
64  		this();
65  		for (RuleBinding<? extends Rule<?>> ruleBinding : builder.initialize()) {
66  			if (ruleBinding instanceof MessageRuleBinding)
67  				myMessageRuleBindings.add((MessageRuleBinding)ruleBinding);
68  			else if (ruleBinding instanceof EncodingRuleBinding)
69  				myEncodingRuleBindings.add((EncodingRuleBinding)ruleBinding);
70  			else if (ruleBinding instanceof PrimitiveTypeRuleBinding)
71  				myPrimitiveRuleBindings.add((PrimitiveTypeRuleBinding)ruleBinding);
72  		}
73  	}
74  
75      /**
76       * Initializes caches for the three rule types. Used to accelerate the identification
77       * of the rules that apply to a message or primitive.
78       *
79       * @see #newRuleCache(int)
80       * @see #primitiveRuleCache
81       * @see #messageRuleCache
82       * @see #encodingRuleCache
83       */
84      protected void initCaches() {
85          primitiveRuleCache = newRuleCache(100);
86          messageRuleCache = newRuleCache(100);
87          encodingRuleCache = newRuleCache(10);
88      }
89  
90      /**
91  	 * @see ValidationContext#getPrimitiveRules(String, String, Primitive)
92  	 * @param theType ignored
93  	 */
94  	public Collection<PrimitiveTypeRule> getPrimitiveRules(String theVersion, String theTypeName, Primitive theType) {
95          Collection<PrimitiveTypeRule> rules = primitiveRuleCache.get(theVersion + theTypeName);
96          if (rules == null) {
97              rules = getRules(myPrimitiveRuleBindings, theVersion, theTypeName);
98              primitiveRuleCache.put(theVersion + theTypeName, rules);
99          }
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<>(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<>(size);
188         return Collections.synchronizedMap(cache);
189     }
190 }