Package net.sf.daotools.model

Source Code of net.sf.daotools.model.Converter

package net.sf.daotools.model;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import net.sf.daotools.exceptions.SQLSyntaxError;
import net.sf.daotools.util.Utils;

/**
* @author JOAO
*
*/
public class Converter {

  private String sql, hql, hqlAppend, metodo;

  /**
   * Indica se as linhas que estão sendo processadas atualmente "fazem parte"
   * do "from"
   */
  private boolean linhasSaoFrom = false;

  /**
   * Number of line being processed.
   */
  private int lnNumber = 0;

  private Set<String> keywords;

  private static Converter instance;

  private StringBuffer hqlBuffer;

  private Converter() {
    this.initializeKeywords();
  }

  public static Converter getInstance() {
    if (instance == null)
      instance = new Converter();
    return instance;
  }

  /**
   * Initializes the keywords list
   */
  private void initializeKeywords() {
    this.keywords = new HashSet<String>(Arrays.asList(new String[] {
        "select", "from", "where", "order", "by", "and", "or", "group",
        "left", "on", "right", "in","outer" }));
  }

  /**
   * Método que gera o HQL correspondente ao SQL passado como parâmetro. Não
   * analisa (faz parsing) do código, apenas converte para camel case. <br>
   * <br>
   *
   * No caso do "from" é utilizada uma lógica específica, pois o nome de cada
   * POJO precisa começar com UpperCase. Espera-se que a palavra chave "from"
   * esteja no início de uma linha, caso contrário o método não funciona.
   *
   * @param sql -a string que contém o código SQL.
   * @return o hql gerado
   *
   * @throws SQLSyntaxError
   */
  public String generateHQL(String sql) throws SQLSyntaxError {
    this.sql = sql.toLowerCase();
    this.hqlBuffer = new StringBuffer();
    this.verificarSintaxeSql();

    for (this.lnNumber = 0; this.lnNumber < this.obterLinhasSql().length; ++this.lnNumber) {

      String linha = this.obterLinhaSql(this.lnNumber);

      if (linha.startsWith("from ")) {
        // APENAS VAI GERAR O CÒDIGO CORRETO SE O "from" ESTIVER NO
        // INÍCIO DE UMA LINHA
        this.processarLinhaInicioFrom(linha);

      } else if (this.linhasSaoFrom) {

        this.processarFrom(linha);

      } else {
        // para todos os outros casos basta chamar o método
        // "converterParaCamelCase"
        linha = this.converterParaCamelCase(linha, false);
        hqlBuffer.append(linha + "\n");
      }
    }
    this.hql = hqlBuffer.toString();
    return this.hql;
  }

  /**
   * Verifica se a sintaxe do sql digitado está correta. Se não estiver
   * dispara uma {@link IllegalArgumentException}
   *
   * @throws SQLSyntaxError
   */
  private void verificarSintaxeSql() throws SQLSyntaxError {

    for (this.lnNumber = 0; this.lnNumber < this.obterLinhasSql().length; ++this.lnNumber) {

      final String linhaAtual = obterLinhaSql(this.lnNumber);
      final String proximaLinha = obterLinhaSql(this.lnNumber + 1);

      // por enquando apenas faz a verificação de virgulas.
      // qdo for adicionada mais verificação, as linhas abaixo devem virar
      // um método

      final boolean atualNaoTerminaComVirgula = !linhaAtual.trim()
          .endsWith(",");

      final boolean proxNaoComecaComKeyword = Utils
          .isStringNotVoid(proximaLinha)
          && !this.linhaComecaComKeyword(proximaLinha);

      if (atualNaoTerminaComVirgula && proxNaoComecaComKeyword) {

        throw new SQLSyntaxError(this.lnNumber, "");
      }

      if (!atualNaoTerminaComVirgula && !proxNaoComecaComKeyword) {

        throw new SQLSyntaxError(this.lnNumber, "");
      }
    }
  }

  /**
   * verifica se uma linha começa com uma keyword
   *
   * @param linha
   * @return
   */
  private boolean linhaComecaComKeyword(String linha) {
    if (Utils.isStringVoid(linha)) {
      // linha vazia não começa com a keyword...
      return false;
    }
    return this.keywords.contains(linha.trim().split(" ")[0]);
  }

  /**
   * Retorna uma linha específica do sql
   *
   * @param i
   * @return
   */
  private String obterLinhaSql(int i) {
    String[] linhas = this.obterLinhasSql();
    if (i >= linhas.length) {
      return null;
    }
    return linhas[i];
  }

  /**
   * Gera o hql para a linha que começa com a palavra "from"
   *
   * @param linha
   */
  private void processarLinhaInicioFrom(String linha) {

    this.hqlBuffer.append("from ");

    this.processarFrom(this.linhaSemKeyword(linha, "from"));
  }

  /**
   * Gera o hql para linhas relativas ao "from"
   *
   * @param linha
   */
  private void processarFrom(String linha) {

    String[] tabelas = this.obterTabelasDoFrom(linha);

    for (int i = 0; i < tabelas.length; ++i) {

      final String nomeTabela = tabelas[i].trim();

      if (Utils.isStringNotVoid(nomeTabela)) {

        this.hqlBuffer.append(this.converterParaCamelCase(nomeTabela,
            true));

        this.verificarSeProximaLinhaEhFrom(linha);

        final boolean haMaisTabelasNessaLinha = i < (tabelas.length - 1);

        if (haMaisTabelasNessaLinha || this.linhasSaoFrom) {
          this.hqlBuffer.append(this.linhasSaoFrom ? "," : ", ");
        }

      }
    }
    this.hqlBuffer.append("\n");
  }

  /**
   * Verifica se a próxima linha ainda é relativa ao from
   *
   * @param linhaAtual
   */
  private void verificarSeProximaLinhaEhFrom(String linhaAtual) {

    if (linhaAtual.trim().endsWith(",")) {
      this.linhasSaoFrom = true;
    } else {
      this.linhasSaoFrom = false;
    }
  }

  /**
   * Retorna uma array contendo o nome das tabelas que estão no "from"
   *
   * @param linha
   * @return
   */
  private String[] obterTabelasDoFrom(String linha) {
    return linha.split(",");
  }

  /**
   * Elimina o "from" do início de uma linha
   *
   * @param linha
   * @return
   */
  private String linhaSemKeyword(String linha, String keyword) {
    return linha.substring((keyword.length() + 1));
  }

  /**
   * Retorna um array de String contendo as linhas de um sql.
   *
   * @return
   */
  private String[] obterLinhasSql() {
    return this.sql.split("\n");
  }

  /**
   * Converte uma string para camel case. O boolean informa se a primeira
   * letra deve ser maiúscula (nome de classe) ou não (nome de variável).
   *
   * @param string
   * @param primeiraMaiuscula
   * @return
   */
  private String converterParaCamelCase(String string,
      boolean primeiraMaiuscula) {

    // se a string for vazia, vai retornar uma string vazia
    if (Utils.isStringVoid(string)) {
      return "";
    }

    StringBuffer sb = new StringBuffer();
    String[] partes = string.split("_");
    if (primeiraMaiuscula) {
      sb.append(partes[0].substring(0, 1).toUpperCase()
          + partes[0].substring(1));
    } else {
      sb.append(partes[0]);
    }
    for (int i = 1; i < partes.length; ++i) {
      sb.append(partes[i].substring(0, 1).toUpperCase()
          + partes[i].substring(1));
    }
    return sb.toString();
  }

  /**
   * Gera o código HQL já dentro de um <code>sql.append(" codigo ")</code>;<br>
   * <br>
   * Utiliza o método <code>criarHQL(String sql)</code> para gerar o HQL.
   *
   * @param sql -
   *            a string que contém o código SQL.
   * @return
   * @throws SQLSyntaxError
   */
  public String criarHQLAppend(String sql) throws SQLSyntaxError {
    this.generateHQL(sql);
    StringBuffer sb = new StringBuffer();
    String[] linhas = this.hql.split("\n");
    for (String linha : linhas) {
      sb.append("sql.append(\" " + linha + " \");\n");
    }
    this.hqlAppend = sb.toString();
    return this.hqlAppend;
  }

  public String criarMetodo(String sql) {
    // ANTIGO "gerarHQL" - copiado aqui por conter c�digo que pode ser util
    // neste m�todo
    // this.sql = sql.toLowerCase();
    // StringBuffer sbHql = new StringBuffer();
    // String[] linhas = this.sql.split("\n");
    // for (String linha : linhas) {
    // if (linha.startsWith("select ")) {
    // // adiciona a keyword "select" no HQL
    // sbHql.append("select ");
    // // elemina "select " da string que ser� processada
    // linha = linha.substring(7);
    // String[] atrSelect = linha.split(",");
    // for (int i = 0; i < atrSelect.length; ++i) {
    // String atr = atrSelect[i].trim();
    // String[] atrArray = atr.split("[.]");
    // sbHql.append(atrArray[0] + "." +
    // this.converterParaCamelCase(atrArray[1], false));
    // if (i < (atrSelect.length - 1 )) {
    // sbHql.append(", ");
    // }
    // }
    // sbHql.append("\n");
    // }
    // else if (linha.startsWith("from ")) {
    // // adiciona a keyword "from" no HQL
    // sbHql.append("from ");
    // // elemina "from " da string que ser� processada
    // linha = linha.substring(5);
    // String[] tabelasFrom = linha.split(",");
    // for (int i = 0; i < tabelasFrom.length; ++i) {
    // String atr = tabelasFrom[i].trim();
    // String[] atrArray = atr.split(" ");
    // sbHql.append(this.converterParaCamelCase(atrArray[0], true) + " " +
    // atrArray[1]);
    // if (i < (tabelasFrom.length - 1 )) {
    // sbHql.append(", ");
    // }
    // }
    // sbHql.append("\n");
    // }
    // else if (linha.startsWith("where ")) {
    // sbHql.append("where ");
    // linha = linha.substring(6);
    // String[] condWhere = linha.split("[=]");
    // for (int i = 0; i < condWhere.length; ++i) {
    // String atr = condWhere[i].trim();
    // if (atr.contains(".")) {
    // String[] atrArray = atr.split("[.]");
    // sbHql.append(atrArray[0] + "." +
    // this.converterParaCamelCase(atrArray[1], false));
    // }
    // else {
    // sbHql.append(atr);
    // }
    // if (i < (condWhere.length - 1 )) {
    // sbHql.append(" = ");
    // }
    // }
    // sbHql.append("\n");
    // }
    // else if (linha.startsWith("and ")) {
    // sbHql.append("and ");
    // linha = linha.substring(4);
    // String[] condWhere = linha.split("[=]");
    // for (int i = 0; i < condWhere.length; ++i) {
    // String atr = condWhere[i].trim();
    // if (atr.contains(".")) {
    // String[] atrArray = atr.split("[.]");
    // sbHql.append(atrArray[0] + "." +
    // this.converterParaCamelCase(atrArray[1], false));
    // }
    // else {
    // sbHql.append(atr);
    // }
    // if (i < (condWhere.length - 1 )) {
    // sbHql.append(" = ");
    // }
    // }
    // sbHql.append("\n");
    // }
    // else {
    // // converte a linha para camelcase, e mostra msg de erro dizendo que
    // pode haver erros
    // sbHql.append(converterParaCamelCase(linha, false)+ "\n");
    // sbHql.append("\nERRO: Nesta vers�o do programa uma linha pode come�ar
    // apenas com ");
    // sbHql.append("\"select\", \"from\", \"where\" ou \"and\".\n");
    // sbHql.append("ERRO: a linha \"" + linha + "\" foi convertida para
    // camel case, ");
    // sbHql.append("mas pode haver erros nela.\n");
    // }
    // }
    // this.hql = sbHql.toString();
    return this.metodo;
  }
}
TOP

Related Classes of net.sf.daotools.model.Converter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.