/** * OpenSpotLight - Open Source IT Governance Platform * * Copyright (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA * or third-party contributors as indicated by the @author tags or express * copyright attribution statements applied by the authors. All third-party * contributions are distributed under license by CARAVELATECH CONSULTORIA E * TECNOLOGIA EM INFORMATICA LTDA. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA * *********************************************************************** * OpenSpotLight - Plataforma de Governança de TI de Código Aberto * * Direitos Autorais Reservados (c) 2009, CARAVELATECH CONSULTORIA E TECNOLOGIA * EM INFORMATICA LTDA ou como contribuidores terceiros indicados pela etiqueta * @author ou por expressa atribuição de direito autoral declarada e atribuída pelo autor. * Todas as contribuições de terceiros estão distribuídas sob licença da * CARAVELATECH CONSULTORIA E TECNOLOGIA EM INFORMATICA LTDA. * * Este programa é software livre; você pode redistribuí-lo e/ou modificá-lo sob os * termos da Licença Pública Geral Menor do GNU conforme publicada pela Free Software * Foundation. * * Este programa é distribuído na expectativa de que seja útil, porém, SEM NENHUMA * GARANTIA; nem mesmo a garantia implícita de COMERCIABILIDADE OU ADEQUAÇÃO A UMA * FINALIDADE ESPECÍFICA. Consulte a Licença Pública Geral Menor do GNU para mais detalhes. * * Você deve ter recebido uma cópia da Licença Pública Geral Menor do GNU junto com este * programa; se não, escreva para: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.openspotlight.graph.query; import static org.openspotlight.common.util.StringBuilderUtil.append; import static org.openspotlight.common.util.StringBuilderUtil.appendIfNotNull; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.openspotlight.common.exception.SLRuntimeException; import org.openspotlight.graph.query.XPathStatementBuilder.Statement.Condition; /** * The Class SLXPathStatementBuilder. * * @author Vitor Hugo Chagas */ public class XPathStatementBuilder { /** * The Class Statement. * * @author Vitor Hugo Chagas */ public static class Statement { /** * The Class Condition. * * @author Vitor Hugo Chagas */ public static class Condition { /** * The Class LeftOperand. * * @author Vitor Hugo Chagas */ public static class LeftOperand { /** * The Class RelationalOperator. * * @author Vitor Hugo Chagas */ public static class RelationalOperator { /** The condition. */ private final Condition condition; /** * Instantiates a new relational operator. * * @param condition the condition */ private RelationalOperator( final Condition condition) { this.condition = condition; } /** * Right operand. * * @param value the value * @return the statement */ public Statement rightOperand(final Object value) { condition.rightOperandValue = value; condition.closed = true; return condition.outerStatement; } } /** The condition. */ private final Condition condition; /** * Instantiates a new left operand. * * @param condition the condition */ private LeftOperand( final Condition condition) { this.condition = condition; } /** * Inexistent. * * @return the statement */ public Statement inexistent() { condition.closed = true; condition.inexistent = true; return condition.outerStatement; } /** * Operator. * * @param relationalOperator the relational operator * @return the relational operator */ public RelationalOperator operator(final RelationalOperatorType relationalOperator) { return operator(relationalOperator, false); } /** * Operator. * * @param relationalOperator the relational operator * @param applyNot the apply not * @return the relational operator */ public RelationalOperator operator(final RelationalOperatorType relationalOperator, final boolean applyNot) { condition.relationalOperator = relationalOperator; condition.relationalOperatorApplyNot = applyNot; return new RelationalOperator(condition); } } /** The closed. */ private boolean closed = false; /** The conditional operator. */ private ConditionalOperatorType conditionalOperator; /** The conditional operator apply not. */ private boolean conditionalOperatorApplyNot; /** The inexistent. */ private boolean inexistent = false; /** The inner statement. */ private Statement innerStatement; /** The left operand value. */ private Object leftOperandValue; /** The outer statement. */ private Statement outerStatement; /** The relational operator. */ private RelationalOperatorType relationalOperator; /** The relational operator apply not. */ private boolean relationalOperatorApplyNot; /** The right operand value. */ private Object rightOperandValue; /** The stack trace. */ private final StackTraceElement[] stackTrace; /** * Instantiates a new condition. * * @param outerStatement the outer statement */ private Condition( final Statement outerStatement) { stackTrace = Thread.currentThread().getStackTrace(); this.outerStatement = outerStatement; } /** * Left operand. * * @param value the value * @return the left operand */ public LeftOperand leftOperand(final Object value) { leftOperandValue = value; return new LeftOperand(this); } } /** * The Class ConditionalOperator. * * @author Vitor Hugo Chagas */ public static class ConditionalOperator { /** The apply not. */ private final boolean applyNot; /** The conditional operator. */ private final ConditionalOperatorType conditionalOperator; /** The statement. */ private final Statement statement; /** * Instantiates a new conditional operator. * * @param statement the statement * @param conditionalOperator the conditional operator * @param applyNot the apply not */ private ConditionalOperator( final Statement statement, final ConditionalOperatorType conditionalOperator, final boolean applyNot) { this.statement = statement; this.conditionalOperator = conditionalOperator; this.applyNot = applyNot; } /** * Condition. * * @return the condition */ public Condition condition() { final Condition condition = new Condition(statement); condition.conditionalOperator = conditionalOperator; condition.conditionalOperatorApplyNot = applyNot; condition.outerStatement = statement; statement.conditions.add(condition); return condition; } /** * Open bracket. * * @return the statement */ public Statement openBracket() { final Condition condition = new Condition(statement); condition.conditionalOperator = conditionalOperator; condition.conditionalOperatorApplyNot = applyNot; statement.conditions.add(condition); final Statement innerStatement = new Statement(condition); condition.innerStatement = innerStatement; return innerStatement; } } /** The conditions. */ private final List<Condition> conditions = new ArrayList<Condition>(); /** The parent. */ private final Condition parent; /** * Instantiates a new statement. * * @param parent the parent */ private Statement( final Condition parent) { this.parent = parent; } /** * Close bracket. * * @return the statement */ public Statement closeBracket() { parent.closed = true; return parent.outerStatement; } /** * Condition. * * @return the condition */ public Condition condition() { final Condition condition = new Condition(this); conditions.add(condition); return condition; } /** * Gets the condition count. * * @return the condition count */ public int getConditionCount() { return conditions.size(); } /** * Open bracket. * * @return the statement */ public Statement openBracket() { final Condition condition = new Condition(this); conditions.add(condition); final Statement innerStatement = new Statement(condition); condition.innerStatement = innerStatement; return innerStatement; } /** * Operator. * * @param conditionalOperator the conditional operator * @return the conditional operator */ public ConditionalOperator operator(final ConditionalOperatorType conditionalOperator) { return operator(conditionalOperator, false); } /** * Operator. * * @param conditionalOperator the conditional operator * @param applyNot the apply not * @return the conditional operator */ public ConditionalOperator operator(final ConditionalOperatorType conditionalOperator, final boolean applyNot) { return new ConditionalOperator(this, conditionalOperator, applyNot); } } /** The order by. */ private String orderBy; /** The path. */ private String path; /** The root statement. */ private Statement rootStatement; /** * Instantiates a new sLX path statement builder. */ public XPathStatementBuilder() {} /** * Instantiates a new sLX path statement builder. * * @param path the path */ public XPathStatementBuilder( final String path) { this.path = path; } /** * Prints the statement. * * @param buffer the buffer * @param statement the statement * @param identLevel the ident level */ private void printStatement(final StringBuilder buffer, final Statement statement, final int identLevel) { validate(rootStatement); final StringBuilder statementBuffer = new StringBuilder(); final String tabs0 = StringUtils.repeat("\t", identLevel); final String tabs1 = StringUtils.repeat("\t", identLevel + 1); for (final Condition condition: statement.conditions) { append(statementBuffer, tabs0); if (condition.innerStatement == null) { if (condition.conditionalOperator != null) { if (condition.conditionalOperator != null) { append(statementBuffer, condition.conditionalOperator.symbol().toLowerCase(), ' '); } if (condition.conditionalOperatorApplyNot) { append(statementBuffer, "not(\n", tabs1); } } if (condition.inexistent) { append(statementBuffer, "not(@", condition.leftOperandValue, ")\n"); } else { final String expression = condition.relationalOperator.xPathExpression(condition.leftOperandValue, condition.rightOperandValue, condition.relationalOperatorApplyNot); append(statementBuffer, expression, '\n'); if (condition.conditionalOperator != null && condition.conditionalOperatorApplyNot) { append(statementBuffer, tabs0, ")\n"); } } } else { if (condition.conditionalOperator != null) { append(statementBuffer, condition.conditionalOperator.symbol().toLowerCase(), ' '); } if (condition.conditionalOperatorApplyNot) { append(statementBuffer, "not(\n"); } else { append(statementBuffer, "(\n"); } printStatement(statementBuffer, condition.innerStatement, identLevel + 1); append(statementBuffer, tabs0, ")\n"); } } append(buffer, statementBuffer); } /** * Validate. * * @param statement the statement */ private void validate(final Statement statement) { if (statement != null) { for (final Condition condition: statement.conditions) { if (!condition.closed) { final RuntimeException e = new SLRuntimeException("All conditions must be closed."); e.setStackTrace(condition.stackTrace); throw e; } validate(condition.innerStatement); } } } /** * Gets the root statement. * * @return the root statement */ public Statement getRootStatement() { if (rootStatement == null) { rootStatement = new Statement(null); } return rootStatement; } /** * Gets the x path. * * @return the x path */ public String getXPath() { final StringBuilder buffer = new StringBuilder(); final StringBuilder statementBuffer = new StringBuilder(); printStatement(statementBuffer, rootStatement, 0); append(buffer, path, "\n[\n", statementBuffer, "]"); appendIfNotNull(buffer, orderBy, "\norder by @", orderBy); return buffer.toString(); } /** * Gets the x path string. * * @return the x path string */ public String getXPathString() { String xpath = getXPath(); xpath = StringUtils.replace(xpath, "\t", ""); xpath = StringUtils.replace(xpath, "\n", " "); return xpath; } /** * Sets the order by. * * @param orderBy the new order by */ public void setOrderBy(final String orderBy) { this.orderBy = orderBy; } /** * Sets the path. * * @param path the new path */ public void setPath(final String path) { this.path = path; } }