View Javadoc

1   package org.kuali.student.common.messagebuilder.impl;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.kuali.student.common.messagebuilder.MessageTreeBuilder;
7   import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanNode;
8   import org.kuali.student.common.messagebuilder.impl.exceptions.MessageBuilderException;
9   
10  /**
11   * This class creates success messages for boolean binary tree nodes.
12   *
13   * Default display is a single line message (e.g. A OR (B AND (C OR D))).  
14   * To display as multiple lines where each operator and message is on its own line.
15   * set the following:
16   * <pre>
17   * INDENT_CHAR = ' '
18   * INDENT_NUMBER_OF_SPACES = 4
19   * BOOLEAN_OPERATOR_PREFIX = "\n"
20   * BOOLEAN_OPERATOR_SUFFIX = "\n"
21   * Example:
22   * </pre>
23   * <pre>
24   *    MATH101
25   * OR
26   *        (MATH201
27   *    AND
28   *            (MATH301
29   *        OR
30   *            MATH401))
31   * </pre>
32   */
33  public class SimpleBooleanMessageBuilder implements MessageTreeBuilder {
34  	// Default indentation character
35  	private final static char INDENT_CHAR = 0;
36  	// Default number of spaces to indent
37  	private final static int INDENT_NUMBER_OF_SPACES = 0;
38  	// Default indentation string
39  	private final static String INDENT_STRING = getString(INDENT_NUMBER_OF_SPACES, INDENT_CHAR);
40  	// Default boolean operator prefix string
41  	private final static String BOOLEAN_OPERATOR_PREFIX = " ";
42  	// Default boolean operator suffix string
43  	private final static String BOOLEAN_OPERATOR_SUFFIX = " ";
44  
45  	// Indentation character
46  	private int indentCharacter = INDENT_CHAR;
47  	// Number of spaces to indent
48  	private int indentNumberOfSpaces = INDENT_NUMBER_OF_SPACES;
49  	// Indentation string
50  	private String indentString = INDENT_STRING;
51  	// Boolean operator prefix string
52  	private String booleanOperatorPrefix = BOOLEAN_OPERATOR_PREFIX;
53  	// Boolean operator suffix string
54  	private String booleanOperatorSuffix = BOOLEAN_OPERATOR_SUFFIX;
55  	
56  	/** Boolean operators to use in creating the success message */
57  	private BooleanOperators booleanOperators;
58  
59  	/**
60  	 * Creates a success message builder with boolean operators to use in 
61  	 * building the success message.
62  	 * 
63  	 * @param andOperator AND logical operator
64  	 * @param orOperator OR logical operator
65  	 */
66  	public SimpleBooleanMessageBuilder(String andOperator, String orOperator) {
67  		this.booleanOperators = new BooleanOperators(andOperator, orOperator);
68  	}
69  
70  	/**
71  	 * Creates a success message builder with boolean operators to use in 
72  	 * building the success message.
73  	 * 
74  	 * @param bo Boolean operators to build success message
75  	 */
76  	public SimpleBooleanMessageBuilder(BooleanOperators bo) {
77  		this.booleanOperators = bo;
78  	}
79  
80  	public void setIndentCharacter(int indentChar) {
81  		this.indentCharacter = indentChar;
82  	}
83  
84  	public void setIndentNumberOfSpaces(int indentNumberOfSpaces) {
85  		this.indentNumberOfSpaces = indentNumberOfSpaces;
86  	}
87  
88  	public void setIndentString(String indentString) {
89  		this.indentString = indentString;
90  	}
91  
92  	public void setBooleanOperatorPrefix(String booleanOperatorPrefix) {
93  		this.booleanOperatorPrefix = booleanOperatorPrefix;
94  	}
95  
96  	public void setBooleanOperatorSuffix(String booleanOperatorSuffix) {
97  		this.booleanOperatorSuffix = booleanOperatorSuffix;
98  	}
99  
100 	/**
101 	 * Builds and sets the success message for each of the boolean nodes 
102 	 * (binary tree) in the <code>nodeList</code>.
103 	 * 
104 	 * @param nodeList List of boolean nodes 
105 	 * @return Complete success message 
106 	 */
107 	public String buildMessage(List<BooleanNode> nodeList) throws MessageBuilderException {
108 		// List must only contain one root node
109 		List<BooleanNode> rootNodeList = new ArrayList<BooleanNode>();
110 		for(BooleanNode node : nodeList) {
111 			if(node.getParent() == null) {
112 				rootNodeList.add(node);
113 			}
114 			buildMessage(node);
115 		}
116 		if(rootNodeList.size() > 1) {
117 			throw new MessageBuilderException("Node list contains more than one root node: " + rootNodeList);
118 		}
119 		return rootNodeList.get(0).getNodeMessage();
120 	}
121 
122 	/**
123 	 * Builds and sets the success message for a single 
124 	 * boolean <code>node</code> (b-tree node).
125 	 * 
126 	 * @param node Boolean node
127 	 */
128 	public String buildMessage(final BooleanNode node) {
129 		// AND node
130 		if(node.getLabel().equals("*")) {
131 			buildAndNodeSuccessMessage(node);
132 		} 
133 		// OR node
134 		else if(node.getLabel().equals("+")) {
135 			buildOrNodeSuccessMessage(node);
136 		}
137 		return node.getNodeMessage();
138 	}
139 
140 	/**
141 	 * Builds a success message for an AND node (b-tree node) where 
142 	 * left node and right node are true.
143 	 * 
144 	 * @param node Boolean node
145 	 */
146 	private void buildAndNodeSuccessMessage(BooleanNode node) {
147 		if(node.getLabel().equals("*") && 
148 				node.getLeftNode() != null && 
149 				node.getRightNode() != null &&
150 				node.getLeftNode().getNodeMessage() != null && 
151 				node.getRightNode().getNodeMessage() != null) {
152 			String preIndent = "";
153 			if(node.getLeftNode().getChildCount() == 0) {
154 				preIndent = getIndent(node, 0);
155 			}
156 			String postIndent = "";
157 			if(node.getRightNode().getChildCount() == 0) {
158 				postIndent = getIndent(node, 0);
159 			}
160 
161 			String logMessage = this.indentString + node.getLeftNode().getNodeMessage() + 
162 				this.booleanOperatorPrefix + 
163 				preIndent + this.booleanOperators.getAndOperator() + 
164 				this.booleanOperatorSuffix + 
165 				postIndent + this.indentString + node.getRightNode().getNodeMessage();
166 
167 			if(node.getParent() != null && 
168 					((node.getLabel().equals("+") && 
169 							node.getParent().getLabel().equals("*")) || 
170 							(node.getLabel().equals("*") && 
171 									node.getParent().getLabel().equals("+")))) {
172 				logMessage = node.getLeftNode().getNodeMessage() + 
173 					this.booleanOperatorPrefix + 
174 					preIndent + this.booleanOperators.getAndOperator() + 
175 					this.booleanOperatorSuffix + 
176 					postIndent + this.indentString + node.getRightNode().getNodeMessage();
177 				    logMessage = preIndent + "(" + logMessage + ")";
178 			}
179 			node.setNodeMessage(logMessage);
180 		}
181 	}
182 
183 	/**
184 	 * Builds a success message for an OR node (b-tree node) where 
185 	 * left node and right node are true.
186 	 * 
187 	 * @param node
188 	 */
189 	private void buildOrNodeSuccessMessage(BooleanNode node) {
190 		// OR2
191 		if(node.getLabel().equals("+") &&
192 				node.getLeftNode() != null && 
193 				node.getRightNode() != null &&
194 				node.getLeftNode().getNodeMessage() != null && 
195 				node.getRightNode().getNodeMessage() != null) {
196 			String preIndent = "";
197 			if(node.getLeftNode().getChildCount() == 0) {
198 				preIndent = getIndent(node, 0);
199 			}
200 			String postIndent = "";
201 			if(node.getRightNode().getChildCount() == 0) {
202 				postIndent = getIndent(node, 0);
203 			}
204 
205 			String logMessage = this.indentString + node.getLeftNode().getNodeMessage() + 
206 			this.booleanOperatorPrefix + 
207 				preIndent + this.booleanOperators.getOrOperator() + 
208 				this.booleanOperatorSuffix + 
209 				postIndent + this.indentString + node.getRightNode().getNodeMessage();
210 
211 			if(node.getParent() != null && 
212 					((node.getLabel().equals("+") && 
213 							node.getParent().getLabel().equals("*")) || 
214 							(node.getLabel().equals("*") && 
215 									node.getParent().getLabel().equals("+")))) {
216 				logMessage = node.getLeftNode().getNodeMessage() + 
217 					this.booleanOperatorPrefix + 
218 					preIndent + this.booleanOperators.getOrOperator() + 
219 					this.booleanOperatorSuffix + 
220 					postIndent + this.indentString + node.getRightNode().getNodeMessage();
221 				    logMessage = preIndent + "(" + logMessage + ")";
222 			}
223 			node.setNodeMessage(logMessage);
224 		} 
225 	}
226 	
227 	private int parentCount;
228 	
229 	private void countParents(BooleanNode node) {
230 		if(node.getParent() != null) {
231 			this.parentCount++;
232 			countParents(node.getParent());
233 		}
234 	}
235 	
236 	private String getIndent(BooleanNode node, int multiplier) {
237 		this.parentCount = 0;
238 		countParents(node);
239 		if(this.parentCount > 0) {
240 			return getString(this.parentCount * this.indentNumberOfSpaces + multiplier, (char) this.indentCharacter);
241 		}
242 		return "";
243 	}
244 	
245 	private static String getString(int charCount, char indentChr) {
246 		char[] chr = new char[charCount];
247 		for(int i=0; i<chr.length; i++) {
248 			chr[i] = indentChr;
249 		}
250 		return String.valueOf(chr);
251 	}
252 }