All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.student.common.messagebuilder.impl.AbstractMessageBuilder Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2010 The Kuali Foundation Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 * http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package org.kuali.student.common.messagebuilder.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.velocity.exception.VelocityException;
import org.kuali.student.common.messagebuilder.MessageTreeBuilder;
import org.kuali.student.common.messagebuilder.booleanmessage.BooleanMessage;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.BinaryMessageTree;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanFunction;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanFunctionResult;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanMessageImpl;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.BooleanNode;
import org.kuali.student.common.messagebuilder.booleanmessage.ast.exceptions.BooleanFunctionException;
import org.kuali.student.common.messagebuilder.impl.exceptions.MessageBuilderException;
import org.kuali.student.common.util.VelocityTemplateEngine;

/**
 * This AbstractMessageBuilder class builds a summary message 
 * from plain strings or Velocity template messages. Summary message is built 
 * from analysing the outcome of a boolean expression. 
 * If no language is specified then the default language locale is used. 
 */
public abstract class AbstractMessageBuilder {
    private final VelocityTemplateEngine templateEngine = new VelocityTemplateEngine();

    private String booleanExpression;
    private Map messageMap;
    private Map messageContextMap;
    private String language;
    private MessageTreeBuilder treeNodeMessageBuilder;

    /**
     * Constructor.
     * 
     * @param language Language
     * @param treeNodeMessageBuilder AST tree node Message builder
     */
    public AbstractMessageBuilder(final String language, final MessageTreeBuilder treeNodeMessageBuilder) {
        this.language = language; 
        this.treeNodeMessageBuilder = treeNodeMessageBuilder;
    }
    
	/**
     * 

Builds and evaluates a boolean expression and returns the message and result * of the expression. Messages in the messageMap can * also contain VTL (Velocity Template Language) but without any VTL keys

*

Note: Order of boolean operation: ANDs before ORs and operations * inside parentheses before anything else.

* Example 1: 'A AND B OR C AND D' internally evaluates to '(A AND B) OR (C AND D)' *
booleanExpression = "A*B+C*D"
* Example 2: '(M1 AND M2) OR M3' *
booleanExpression = "(M1*M2)+M3"
* * @param booleanExpression Boolean expression * @param messageMap Contains a map of messages (or VTL) * @return Boolean function result */ public BooleanFunctionResult build( final String booleanExpression, final Map messageMap) { this.booleanExpression = booleanExpression; this.messageMap = messageMap; return build(); } /** *

Builds and evaluates a boolean expression and returns the message and result * of the expression. Messages in the messageMap can * also contain VTL (Velocity Template Language). * messageContextMap contains Velocity key/value entries * referenced in the messageMap.

*

Note: Order of boolean operation: ANDs before ORs and operations * inside parentheses before anything else.

* Example 1: 'A AND B OR C AND D' internally evaluates to '(A AND B) OR (C AND D)' *
booleanExpression = "A*B+C*D"
* Example 2: '(M1 AND M2) OR M3' *
booleanExpression = "(M1*M2)+M3"
* * * @param booleanExpression Boolean expression * @param messageMap Contains a map of messages (or VTL) * @param messageContextMap Message contact map for Velocity Template Engine * @return Boolean function result * @throws MessageBuilderException Errors building message */ public BooleanFunctionResult build( final String booleanExpression, final Map messageMap, final Map messageContextMap) { this.booleanExpression = booleanExpression; this.messageMap = messageMap; this.messageContextMap = messageContextMap; return build(); } public BooleanFunctionResult build() { BinaryMessageTree astTree = null; try { // set the functionString and Maps from the proposition container Map nodeMessageMap = buildMessageMap(); // go parse function in buildTree astTree = new BinaryMessageTree(this.language, nodeMessageMap); BooleanNode root = astTree.buildTree(this.booleanExpression); astTree.traverseTreePostOrder(root, null); List treeNodes = astTree.getAllNodes(); // tree node order in the list is important for building // the success and failure message this.treeNodeMessageBuilder.buildMessage(treeNodes); } catch(VelocityException e) { throw new MessageBuilderException("Building Velocity message failed: " + e.getMessage(), e); } catch (BooleanFunctionException e) { throw new MessageBuilderException("Building message failed: " + e.getMessage(), e); } // This is the final rule report message summary String message = astTree.getRoot().getNodeMessage(); Boolean result = astTree.getRoot().getValue(); // Removed starting and ending brackets if they are the only brackets in the message if (message.startsWith("(") && message.endsWith(")") && message.replaceAll("[^(]","").length() == 1 && message.replaceAll("[^)]","").length() == 1) { message = message.substring(1, message.length()-1); } return new BooleanFunctionResult(this.booleanExpression, result, message); } /** * Builds message map. Also builds message map using velocity templates. * * @return Boolean message map */ private Map buildMessageMap() { Map nodeMessageMap = new HashMap(); if (this.booleanExpression == null || this.booleanExpression.isEmpty()) { throw new MessageBuilderException("Boolean expression is null"); } BooleanFunction func = new BooleanFunction(this.booleanExpression); List funcVars = func.getVariables(); if(funcVars == null || funcVars.isEmpty()) { throw new MessageBuilderException("Boolean function variables are null or empty. Boolean expression: " + this.booleanExpression); } for (String id : funcVars) { if(id == null) { throw new MessageBuilderException("Boolean variable id is null or empty. Boolean variable ids: " + funcVars); } BooleanMessage message = this.messageMap.get(id); if (message == null) { throw new MessageBuilderException("Boolean message is null for id='" + id + "'"); } BooleanMessage booleanMessage = buildMessage(message); nodeMessageMap.put(id, booleanMessage); } return nodeMessageMap; } /** * Builds a failure/success message using the Velocity template engine. * * @param message Boolean failure/success message * @return */ private BooleanMessage buildMessage(BooleanMessage message) { String msg = message.getMessage(); if(msg != null) { msg = this.templateEngine.evaluate(this.messageContextMap, msg); } return new BooleanMessageImpl(message.getMessageId(), message.isSuccesful(), msg); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy