Clover Coverage Report - KS Common 1.1 (Aggregated)
Coverage timestamp: Sun Mar 6 2011 20:59:55 EST
../../../../../../img/srcFileCovDistChart9.png 18% of files have more coverage
44   203   19   7.33
12   96   0.43   6
6     3.17  
1    
 
  AbstractMessageBuilder       Line # 40 44 0% 19 9 85.5% 0.8548387
 
  (38)
 
1    /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10    * software distributed under the License is distributed on an "AS IS"
11    * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12    * or implied. See the License for the specific language governing
13    * permissions and limitations under the License.
14    */
15   
16    package org.kuali.student.common.messagebuilder.impl;
17   
18    import java.util.HashMap;
19    import java.util.List;
20    import java.util.Map;
21   
22    import org.apache.velocity.exception.VelocityException;
23    import org.kuali.student.common.messagebuilder.MessageTreeBuilder;
24    import org.kuali.student.common.messagebuilder.booleanmessage.BooleanMessage;
25    import org.kuali.student.common.messagebuilder.booleanmessage.ast.BinaryMessageTree;
26    import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanFunction;
27    import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanFunctionResult;
28    import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanMessageImpl;
29    import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanNode;
30    import org.kuali.student.common.messagebuilder.booleanmessage.ast.exceptions.BooleanFunctionException;
31    import org.kuali.student.common.messagebuilder.impl.exceptions.MessageBuilderException;
32    import org.kuali.student.common.util.VelocityTemplateEngine;
33   
34    /**
35    * This <code>AbstractMessageBuilder</code> class builds a summary message
36    * from plain strings or Velocity template messages. Summary message is built
37    * from analysing the outcome of a boolean expression.
38    * If no language is specified then the default language locale is used.
39    */
 
40    public abstract class AbstractMessageBuilder {
41    private final VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();
42   
43    private String booleanExpression;
44    private Map<String, ? extends BooleanMessage> messageMap;
45    private Map<String, Object> messageContextMap;
46    private String language;
47    private MessageTreeBuilder treeNodeMessageBuilder;
48   
49    /**
50    * Constructor.
51    *
52    * @param language Language
53    * @param treeNodeMessageBuilder AST tree node Message builder
54    */
 
55  30 toggle public AbstractMessageBuilder(final String language, final MessageTreeBuilder treeNodeMessageBuilder) {
56  30 this.language = language;
57  30 this.treeNodeMessageBuilder = treeNodeMessageBuilder;
58    }
59   
60    /**
61    * <p>Builds and evaluates a boolean expression and returns the message and result
62    * of the expression. Messages in the <code>messageMap</code> can
63    * also contain VTL (Velocity Template Language) but without any VTL keys</p>
64    * <p><b>Note:</b> Order of boolean operation: ANDs before ORs and operations
65    * inside parentheses before anything else.</p>
66    * Example 1: 'A AND B OR C AND D' internally evaluates to '(A AND B) OR (C AND D)'
67    * <pre><code>booleanExpression</code> = "A*B+C*D"</pre>
68    * Example 2: '(M1 AND M2) OR M3'
69    * <pre><code>booleanExpression</code> = "(M1*M2)+M3"</pre>
70    *
71    * @param booleanExpression Boolean expression
72    * @param messageMap Contains a map of messages (or VTL)
73    * @return Boolean function result
74    */
 
75  39 toggle public BooleanFunctionResult build(
76    final String booleanExpression,
77    final Map<String, ? extends BooleanMessage> messageMap) {
78  39 this.booleanExpression = booleanExpression;
79  39 this.messageMap = messageMap;
80   
81  39 return build();
82    }
83   
84    /**
85    * <p>Builds and evaluates a boolean expression and returns the message and result
86    * of the expression. Messages in the <code>messageMap</code> can
87    * also contain VTL (Velocity Template Language).
88    * <code>messageContextMap</code> contains Velocity key/value entries
89    * referenced in the <code>messageMap</code>.</p>
90    * <p><b>Note:</b> Order of boolean operation: ANDs before ORs and operations
91    * inside parentheses before anything else.</p>
92    * Example 1: 'A AND B OR C AND D' internally evaluates to '(A AND B) OR (C AND D)'
93    * <pre><code>booleanExpression</code> = "A*B+C*D"</pre>
94    * Example 2: '(M1 AND M2) OR M3'
95    * <pre><code>booleanExpression</code> = "(M1*M2)+M3"</pre>
96    *
97    *
98    * @param booleanExpression Boolean expression
99    * @param messageMap Contains a map of messages (or VTL)
100    * @param messageContextMap Message contact map for Velocity Template Engine
101    * @return Boolean function result
102    * @throws MessageBuilderException Errors building message
103    */
 
104  5 toggle public BooleanFunctionResult build(
105    final String booleanExpression,
106    final Map<String, ? extends BooleanMessage> messageMap,
107    final Map<String, Object> messageContextMap) {
108  5 this.booleanExpression = booleanExpression;
109  5 this.messageMap = messageMap;
110  5 this.messageContextMap = messageContextMap;
111   
112  5 return build();
113    }
114   
 
115  44 toggle public BooleanFunctionResult build() {
116  44 BinaryMessageTree astTree = null;
117   
118  44 try {
119    // set the functionString and Maps from the proposition container
120  44 Map<String, BooleanMessage> nodeMessageMap = buildMessageMap();
121   
122    // go parse function in buildTree
123  42 astTree = new BinaryMessageTree(this.language, nodeMessageMap);
124  42 BooleanNode root = astTree.buildTree(this.booleanExpression);
125  42 astTree.traverseTreePostOrder(root, null);
126   
127  42 List<BooleanNode> treeNodes = astTree.getAllNodes();
128    // tree node order in the list is important for building
129    // the success and failure message
130  42 this.treeNodeMessageBuilder.buildMessage(treeNodes);
131    } catch(VelocityException e) {
132  1 throw new MessageBuilderException("Building Velocity message failed: " + e.getMessage(), e);
133    } catch (BooleanFunctionException e) {
134  1 throw new MessageBuilderException("Building message failed: " + e.getMessage(), e);
135    }
136   
137    // This is the final rule report message summary
138  42 String message = astTree.getRoot().getNodeMessage();
139  42 Boolean result = astTree.getRoot().getValue();
140   
141    // Removed starting and ending brackets if they are the only brackets in the message
142  42 if (message.startsWith("(") && message.endsWith(")") &&
143    message.replaceAll("[^(]","").length() == 1 &&
144    message.replaceAll("[^)]","").length() == 1) {
145  4 message = message.substring(1, message.length()-1);
146    }
147   
148  42 return new BooleanFunctionResult(this.booleanExpression, result, message);
149    }
150   
151    /**
152    * Builds message map. Also builds message map using velocity templates.
153    *
154    * @return Boolean message map
155    */
 
156  44 toggle private Map<String, BooleanMessage> buildMessageMap() {
157  44 Map<String, BooleanMessage> nodeMessageMap = new HashMap<String, BooleanMessage>();
158   
159  44 if (this.booleanExpression == null || this.booleanExpression.isEmpty()) {
160  0 throw new MessageBuilderException("Boolean expression is null");
161    }
162   
163  44 BooleanFunction func = new BooleanFunction(this.booleanExpression);
164  43 List<String> funcVars = func.getVariables();
165   
166  43 if(funcVars == null || funcVars.isEmpty()) {
167  0 throw new MessageBuilderException("Boolean function variables are null or empty. Boolean expression: " + this.booleanExpression);
168    }
169   
170  43 for (String id : funcVars) {
171  114 if(id == null) {
172  0 throw new MessageBuilderException("Boolean variable id is null or empty. Boolean variable ids: " + funcVars);
173    }
174   
175  114 BooleanMessage message = this.messageMap.get(id);
176   
177  114 if (message == null) {
178  0 throw new MessageBuilderException("Boolean message is null for id='" + id + "'");
179    }
180   
181  114 BooleanMessage booleanMessage = buildMessage(message);
182  113 nodeMessageMap.put(id, booleanMessage);
183    }
184   
185  42 return nodeMessageMap;
186    }
187   
188    /**
189    * Builds a failure/success message using the Velocity template engine.
190    *
191    * @param message Boolean failure/success message
192    * @return
193    */
 
194  114 toggle private BooleanMessage buildMessage(BooleanMessage message) {
195  114 String msg = message.getMessage();
196   
197  114 if(msg != null) {
198  114 msg = this.templateEngine.evaluate(this.messageContextMap, msg);
199    }
200   
201  113 return new BooleanMessageImpl(message.getMessageId(), message.isSuccesful(), msg);
202    }
203    }