package com.temenos.interaction.odataext.odataparser.output; import java.util.ArrayList; import java.util.List; /* * Class containing an Odata4j Expression constructed as a tree . This is required because OData4j Expression calls it's * visitor in a different sequence to that required printing OData parameters. * * Handles errors by return true/false values (like java.util.Set). */ /* * #%L * interaction-odata4j-ext * %% * Copyright (C) 2012 - 2013 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ public class OutputExpressionNode { private List<String> arguments = new ArrayList<String>(); // String representation of operator, function or value. private String op; // Flag indicating term is bracketed. private boolean isBracketed; // Flag indicating arguments should be quoted. private boolean quoteArguments; // Flag indicating therm is a 'function', e.g. func(args), rather than an // 'operator', e.g. arg op arg. // // TODO: We would like to set this based on the visiting oData4j expression // type e.g. something like: // // 'MethodCallExpression.class.isAssignableFrom(expr)'. // // However by the time our visitors append() function is called the type is // no longer available. So have to set this with a messy additional call. // private boolean isFunction; // Parent node of this node. private OutputExpressionNode parent; // Maximum number of sub nodes per node. private static int MAX_SUB_NODES = 3; // Constructor for the root node. public OutputExpressionNode() { this(null); } // Constructor for child nodes. public OutputExpressionNode(OutputExpressionNode parent) { this.parent = parent; isBracketed = false; isFunction = false; quoteArguments = false; } /* * Method to print a complete node as an oData parameter. */ public String toOdataParameter() { StringBuffer sb = new StringBuffer(); if (isBracketed) { appendOpenBracket(sb); } if (isFunction()) { appendFunction(sb); } else { appendOperator(sb); } if (isBracketed) { appendCloseBracket(sb); } // Remove any trailing spaces String str = sb.toString().trim(); return str; } private void appendFunction(StringBuffer sb) { sb.append(op); appendOpenBracket(sb); appendFunctionArguments(sb); appendCloseBracket(sb); } private void appendFunctionArguments(StringBuffer sb) { boolean first = true; for (String argument : arguments) { if (first) { first = false; } else { appendCommaSpace(sb); } appendArgument(sb, argument); } } private void appendArgument(StringBuffer sb, String argument) { if (isQuoteArgumnets()) { appendQuote(sb); } sb.append(argument); if (isQuoteArgumnets()) { appendQuote(sb); } } private void appendQuote(StringBuffer sb) { sb.append("'"); } private void appendOperator(StringBuffer sb) { switch (arguments.size()) { case 0: // Just append self appendValue(sb); break; case 1: appendUnaryOperator(sb); break; case 2: appendBinaryOperator(sb); break; default: throw new RuntimeException("Too many arguments for an operator \"" + op + "\". Trailing args ignored."); } } private void appendBinaryOperator(StringBuffer sb) { sb.append(arguments.get(0)); appendSpace(sb); if (null != op) { appendValue(sb); appendSpace(sb); } sb.append(arguments.get(1)); } private void appendUnaryOperator(StringBuffer sb) { // It's a unary op. Since it was written first the single operand // will be on the LHS if (null != op) { appendValue(sb); appendSpace(sb); } sb.append(arguments.get(0)); } private void appendValue(StringBuffer sb) { sb.append(op); } private void appendOpenBracket(StringBuffer sb) { sb.append("("); } private void appendCloseBracket(StringBuffer sb) { sb.append(")"); } private void appendSpace(StringBuffer sb) { sb.append(" "); } private void appendComma(StringBuffer sb) { sb.append(","); } private void appendCommaSpace(StringBuffer sb) { appendComma(sb); appendSpace(sb); } /* * Get parent node. If already at the parent returns null. */ public OutputExpressionNode getParent() { return parent; } public boolean addArgument(String argument) { if (MAX_SUB_NODES <= arguments.size()) { return false; } arguments.add(argument); return true; } public boolean setOp(String op) { if (null != this.op) { return false; } this.op = op; return true; } public void setIsBracketed() { isBracketed = true; } public boolean isBracketed() { return isBracketed; } public void setQuoteArguments() { quoteArguments = true; } public boolean isQuoteArgumnets() { return quoteArguments; } public void setIsFunction() { isFunction = true; } public boolean isFunction() { return isFunction; } }