Package com.im.imjutil.query

Source Code of com.im.imjutil.query.AbstractJPAQuery

package com.im.imjutil.query;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.im.imjutil.exception.QueryException;
import com.im.imjutil.exception.ValidationException;
import com.im.imjutil.util.Filter;
import com.im.imjutil.util.Pair;
import com.im.imjutil.validation.Convert;
import com.im.imjutil.validation.Validator;

/**
* Classe abstrata que implementa a base para geracao de consulta
* personalizadas do tipo {@link Query} para consultas do JPA.
* <br>
* Deve-se extender essa classe e sobrescrever o seu metodo
* {@link AbstractJPAQuery#createQuery(Filter...)} para obter
* suas funcionalidades.
* <br>
* Para constucao de um decorador, usar a seguinte sintaxe na sobrescrita:
* <code>
*   <pre>
*     public String createQuery(Filter... filters) throws QueryException {
*       // Adiciona a clausula personalizada
*       super.addClause("t.name IN ('AA', 'BB')");
*       super.addClause("t.number == :number");
*      
*       if (super.hasDecorator()) {
*         // Retorna a chamada para o decorador
*         return super.decorate.createQuery(filters); 
*       }
*       // Retorna a chamada para o superior
*       return super.createQuery(filters);
*     }
*   </pre>
* </code>
*
* @param <T> O tipo T alvo da consulta.
* @author Felipe Zappala
*/
public abstract class AbstractJPAQuery<T> implements Query {

  /*
   *
   * http://www.jpox.org/docs/1_2/jpa/jpql.html
   * http://www.jpox.org/docs/1_2/jpa/query.html
   * http://java.dzone.com/articles/jpa-20-concurrency-and-locking
 
  SELECT [<result>]
      [FROM <candidate-class(es)>]
      [WHERE <filter>]
      [GROUP BY <grouping>]
      [HAVING <having>]
      [ORDER BY <ordering>]
    
   */
 
  /** Clausulas where personalizadas. */
  private final List<String> clauses;
 
  /** Campos de ordenacao personalizada. */
  private final List<String> ordering;
 
  /** A consulta base padrao. */
  private final StringBuilder query;
 
  /** Campos validos para uso no objeto algo. */
  @SuppressWarnings("unused")
  private final Set<String> availableFields;
 
  /** A classe do objeto alvo do tipo T da consulta. */
  private Class<T> clazz;
 
  /** A classe decorada pela implementacao. */
  protected final AbstractJPAQuery<T> decorator;
 
  /**
   * Construtor padrao das consultas do tipo JPA.
   * <br>
   * Esse inicializa uma consulta padrao do tipo:
   * <code>SELECT t FROM T t</code>
   *
   * @param clazz A classe alvo do tipo T da consulta.
   */
  protected AbstractJPAQuery(Class<T> clazz, AbstractJPAQuery<T> decorator) {
    if (clazz == null) {
      throw new ValidationException("A classe da entidade e' nula.");
    }
    this.decorator = decorator;
    this.clazz = clazz;
    this.query = new StringBuilder();
    this.clauses = new ArrayList<String>();
    this.ordering = new ArrayList<String>();
    this.availableFields = getAvailableFields();
  }
 
  /**
   * Cria a consulta base padrao para todas as consultas.
   * 
   * @return A consulta base padrao.
   */
  protected void createBaseQuery() {
    query.append("SELECT t FROM ");
    query.append(clazz.getSimpleName());
    query.append(" AS t");
  }
 
  /**
   * Configura a consulta de base a ser usada na cricao da consulta.
   *
   * @param query A consulta de base.
   */
  protected final void setQueryBase(String query) {
    if (Validator.isValid(query)) {
      String className = clazz.getSimpleName();
     
      if (!query.contains(className)) {
        throw new ValidationException(Convert.toString("Consulta '",
            query, "' invalida para o tipo: ", className));
      }
      this.query.setLength(0);
      this.query.append(query);
    }
  }

  /**
   * Adiciona as clausulas whare personalizadas na consulta.
   * Formato esperado: <code>t.fieldName = :fieldValue</code>
   *
   * @param clauses As clausulas whare personalizadas.
   */
  protected final void addWhere(String... clauses) {
    if (!Validator.isEmpty(clauses)) {
      for (String clause : clauses) {
        this.clauses.add(clause);       
      }
    }
  }
 
  /**
   * Adiciona campos de ordenacao na consulta.
   * Formato esperado: <code>t.fieldName</code>
   *
   * @param fields Os campos a ordenar
   */
  protected final void addOrderBy(String... fields) {
    if (!Validator.isEmpty(fields)) {
      for (String field : fields) {
        this.ordering.add(field);       
      }
    }
  }
 
  /**
   * Verifica se a consulta possui um decorador.
   *
   * @return Verdadeiro caso o decorador for diferente de nulo.
   */
  public final boolean isDecorator() {
    return this.decorator != null;
  }
 
  @Override
  public String createQuery(Filter... filters) throws QueryException {
    throw new UnsupportedOperationException(
        "Classe com implementacao ainda nao finalizada.");
   
    /*
    // Cria a consulta de base
    createBaseQuery();
   
    // Obtem um filtro unificado
    Filter filter = getUnifiedFilter(filters);
   
    // Caso existir filtros, cria a clausula whare.
    if (!filter.isEmpty()) {
     
      // Obtem os campos disponiveis na classe alvo
     
     
      query.append(" WHERE ");
     
      if (!this.clauses.isEmpty()) {
        // Adiciona as clausulas no where
        for (String clause : this.clauses) {
          query.append("(").append(clause).append(")");
          query.append(filter.isExclusive() ? " AND " : " OR  ");
        }
        query.setLength(query.length() -5);
       
        // Remove os filtros usados nas clausulas personalizadas
        removeFilterInClauses(filter);
      }
     
      // Adiciona os filtros restantes no where
      if (!filter.isEmpty()) {
        for (Pair<String, Object> pair : filter) {
         
          // Valida se o campo do filtro esta disponivel no objeto alvo
          if (!availableFields.contains(pair.getFirst())) {
            throw new ValidationException(Convert.toString(
                "Campo invalido para filtro da classe ",
                clazz.getSimpleName(), ": ", pair.getFirst()));
          }
          query.append("o.").append(pair.getFirst());
          query.append((pair.getLast() instanceof String)?" LIKE ":" = ");
          query.append(":").append(pair.getFirst());
          query.append(filter.isExclusive() ? " AND " : " OR  ");
        }
        query.setLength(query.length() -5);
      }
    }
   
    // Retorna a consulta JPA resultante
    return query.toString();
    */
  }
 
  /**
   * Obtem os campos disponiveis para filtro na classe alvo.
   * 
   * @return O conjunto de campos.
   */
  private Set<String> getAvailableFields() {
    Field[] fields = clazz.getDeclaredFields();
    Set<String> availableFields = new HashSet<String>(fields.length);
   
    for (Field field : fields) {
      availableFields.add(field.getName());
    }
    return availableFields;
  }

  /**
   * Remove os filtros contidos nas clausulas whare personalizadas,
   * para que sejam usados uma unica vez na montagem da consulta.
   *
   * @param filter O filtro a ser removido.
   */
  @SuppressWarnings("unused")
  private void removeFilterInClauses(Filter filter) {
    if (!filter.isEmpty()) {
      List<String> fields = new ArrayList<String>();
     
      // Marca os campos a serem removidos
      for (String clause : this.clauses) {
        for (Pair<String, Object> pair : filter) {
          if(clause.contains(pair.getFirst())) {
            fields.add(pair.getFirst());
          }
        }
      }
     
      // Remove os campos do filtro
      for (String field : fields) {
        filter.removeFilter(field);
      }
    }
  }

  /**
   * Obtem um filtro que unifica todos os filtros passados.
   *
   * @param filters Os filtros a serem unificados.
   * @return O filtro unificado
   */
  @SuppressWarnings("unused")
  private Filter getUnifiedFilter(Filter... filters) {
    Filter filter = new Filter();
    
    if (!Validator.isEmpty(filters)) {
      for (Filter f : filters) {
        filter.addFilters(f);

        if (f.isExclusive()) {
          filter.setExclusive();
        } else {
          filter.setInclusive();
        }
      }
    }
    return filter;
  }
/*
  public static void main(String[] args) {
    class P {
      public String name = "";
      public int age = 0;
    }
   
    P p1 = new P(); p1.name = "Joao";  p1.age = 5;
    P p2 = new P(); p2.name = "Maria"; p1.age = 3;
   
    AbstractJPAQuery<P> q1 = new AbstractJPAQuery<P>(P.class, null) {
      @Override
      public String createQuery(Filter... filters) throws QueryException {
        String clause1 = "t.name IN ('Maria', 'Jose')";
        String clause2 = "t.age == :age";
       
        if (this.isDecorator()) {
//          super.decorator.addWhereClauses(clause1, clause2);
          return super.decorator.createQuery(filters); 
        }
//        super.addWhereClauses(clause1, clause2);
        return super.createQuery(filters);
      }
    };
   
    AbstractJPAQuery<P> q2 = new AbstractJPAQuery<P>(P.class, q1) {
      @Override
      public String createQuery(Filter... filters) throws QueryException {
        String clause = "t.name LIKE :name";
       
//        if (this.hasDecorator()) {
//          super.decorator.addClause(clause);
//          return super.decorator.createQuery(filters); 
//        }
//        super.addClause(clause);
        return super.createQuery(filters);
      }
    };
   
    AbstractJPAQuery<P> q3 = new AbstractJPAQuery<P>(P.class, null) {
      @Override
      public String createQuery(Filter... filters) throws QueryException {
//        super.addClause("t.name IN ('Maria', 'Jose') ORDER BY t.name");
       
        return super.createQuery(filters);
      }
    };
   
    AbstractJPAQuery<P> q4 = new AbstractJPAQuery<P>(P.class, null) {
      @Override
      protected void createBaseQuery() {
//        super.query.append(b)
      }
      @Override
      public String createQuery(Filter... filters) throws QueryException {
//        super.addClause("t.name IN ('Maria', 'Jose') ORDER BY t.name");
       
        return super.createQuery(filters);
      }
    };
   
    //SELECT e FROM Event AS e, IN(e.places) p, IN(p.address) a, IN(a.city) c, IN(c.state) s where s = :state
   
    String query = q3.createQuery(new Filter()
        .addFilter("name", "Maria")
        .addFilter("age", 5)
        .setInclusive());
   
    System.out.println(query);
   
  }
 
//  public static void main(String[] args) {
//        EntityManager manager = Persistence.createEntityManagerFactory("jpa-dindin").createEntityManager();
//       
//        //ErrorCode e = manager.find(ErrorCode.class, 1);
//       
////        javax.persistence.Query q = manager.createQuery("SELECT e FORM ErrorCode e WHERE e.description LIKE :desc");
////        q.setParameter("desc", "%INVaLIDO%");
//       
//        javax.persistence.Query q = manager.createQuery("SELECT e FROM ErrorCode e " +
//            "WHERE (e.code = :code1) OR (e.code = :code2)");
//        q.setParameter("code1", 1);
//        q.setParameter("code2", 2);
//       
//        List l = q.getResultList();
//       
//        System.out.println(l);
//        System.out.println(l.size());
//    }
*/
  
   /*
    protected <T> List<T> findAll(Class<T> clazz,
      EntityManager entityManager, Filter filter) {
    if (clazz == null) {
      throw new ValidationException("A classe da entidade e' nula.");
    }
    if (entityManager == null) {
      throw new ValidationException("O EntityManager e' nulo.");
    }
    if (filter == null) {
      throw new ValidationException("O filtro e' nulo.");
    }
   
    // Prepara a consulta
    Query query;
    StringBuilder sql = new StringBuilder();
    sql.append("SELECT o FROM ");
    sql.append(clazz.getSimpleName());
    sql.append(" AS o");
   
    // Obtem os filtros disponiveis
    Set<String> availableFields = new HashSet<String>();
    for (Field field : clazz.getDeclaredFields()) {
      availableFields.add(field.getName());
    }
   
    // Associa os filtros
    if (!filter.isEmpty()) {
      sql.append(" WHERE ");
     
      for (Pair<String, Object> pair : filter) {
        if (!availableFields.contains(pair.getFirst())) {
          throw new ValidationException(
              "Campo invalido para filtro da classe "
              + clazz.getSimpleName() + ": " + pair.getFirst());
        }
        sql.append("o.").append(pair.getFirst());
        sql.append((pair.getLast() instanceof String) ?" LIKE ":" = ");
        sql.append(":").append(pair.getFirst());
        sql.append(" AND ");
      }
      // Remove o ultimo ' AND '
      sql.setLength(sql.length() -5);
    }

    //Cria a consulta
    query = entityManager.createQuery(sql.toString());
   
    // Associa os valores
    for (Pair<String, Object> pair : filter) {
      if (pair.getLast() instanceof String) {
        query.setParameter(pair.getFirst(), new StringBuilder("%")
            .append(pair.getLast()).append("%").toString());
      } else {
        query.setParameter(pair.getFirst(), pair.getLast());
      }
    }
   
    // Executa a consulta
    return query.getResultList();
  }
    */
 
 
 
 
 
 
 
 
//  public static void main(String[] args) {
//    EntityManagerFactory factory = Persistence.createEntityManagerFactory("jpa-plugin");
//    EntityManager manager = factory.createEntityManager();
//   
//    //Seleciona eventos pelo estado
//    String sql = "SELECT e FROM Event AS e, IN(e.places) p, IN(p.address) a, IN(a.city) c, IN(c.state) s where s = :state";
//
//    Query query = manager.createQuery(sql);
//    query.setParameter("state", StateManager.get(1));
//    //query.setParameter("id", 1);
//   
//    System.out.println(query.getResultList());
//    System.out.println(query.getResultList().size());
//   
//    manager.close();
//    factory.close();
//  }
   

}

/*
  // Exemplo de classe
 
  public class QueryUserByAddress extends AbstractJPAQuery<CSVMaker> {

  public QueryUserByAddress() {
    super(CSVMaker.class, null);
  }
 
  public QueryUserByAddress(AbstractJPAQuery<CSVMaker> decorate) {
    super(CSVMaker.class, decorate);
  }
 
  @Override
  public String createQuery(Filter... filters) throws QueryException {
    // Adiciona a clausula personalizada
//    super.addClause("t.name IN ('AA', 'BB')");
//    super.addClause("t.number == :number");
//   
//    if (this.hasDecorator()) {
//      // Retorna a chamada para o decorador
//      return super.decorator.createQuery(filters); 
//    }
    // Retorna a chamada para o superior
    return super.createQuery(filters);
  }
 
  public class QueryUserByName extends AbstractJPAQuery<Filter> {

  @SuppressWarnings("unused")
  private AbstractJPAQuery<Filter> decorate;
 
  public QueryUserByName() {
    super(Filter.class, null);
  }
 
  public QueryUserByName(AbstractJPAQuery<Filter> decorate) {
    super(Filter.class, null);
    this.decorate = decorate;
  }
 
  @Override
  public String createQuery(Filter... filters) throws QueryException {
//    addClause("a = b");
//    addClause("asdfasdf");
//    addClause("asdfasdf");
   
//    if (this.decorate != null) {
//      return this.decorate.createQuery(filters); 
//    }
    return super.createQuery(filters);
  }
 
  public static void main(String[] args) {
//    Query q = new QueryUserByName(new QueryUserByAddress());
//   
//    String sql = q.createQuery(new Filter().addFilter("a", "b"));
//   
//    System.out.println(sql);
  }

}

*/ 
TOP

Related Classes of com.im.imjutil.query.AbstractJPAQuery

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.