1 Reply Latest reply on Jan 16, 2008 10:15 PM by Alex Sun

    Share my implementation of EntityQuery by Entity Example, an

    Alex Sun Newbie

      Structure:
      EntityQuery
      ExampleEntityQuery + EntityQueryState
      RestrictedExampleEntityQuery
      Note:
      ExampleEntityQuery used to generate dynamic ejbql at runtime according to the entity class and entity instance ...
      EntityQueryState used to hold query state, include orderby info, page info, example entity...
      RestrictedExampleEntityQuery used to control user permission on this query, by adding more restriction "where" ejbql

      public abstract class ExampleEntityQuery<E> extends EntityQuery {
      
       private static final long serialVersionUID = 4830838552107053677L;
      
       public static final Pattern FROM_PATTERN = Pattern.compile(
       "(^|\\s)(from)\\s", Pattern.CASE_INSENSITIVE);
      
       public static final Pattern ORDER_CLAUSE_PATTERN = Pattern
       .compile("^[\\w\\.,\\s]*$");
      
       public static final Pattern ORDER_PATTERN = Pattern.compile(
       "\\s(order)(\\s)+by\\s", Pattern.CASE_INSENSITIVE);
      
       public static final Pattern WHERE_PATTERN = Pattern.compile(
       "\\s(where)\\s", Pattern.CASE_INSENSITIVE);
      
       @Logger
       private Log log;
      
       // private EntityQueryState<E> state;
       public abstract void setState(EntityQueryState<E> state);
      
       public abstract EntityQueryState<E> getState();
      
       protected String buildCountEjbql() {
       // return super.getCountEjbql();
       String ejbql = getRenderedEjbql();
       boolean distincted = ejbql.startsWith("select distinct");
      
       Matcher fromMatcher = FROM_PATTERN.matcher(ejbql);
       if (!fromMatcher.find()) {
       throw new IllegalArgumentException("no from clause found in query");
       }
       int fromLoc = fromMatcher.start(2);
      
       Matcher orderMatcher = ORDER_PATTERN.matcher(ejbql);
       int orderLoc = orderMatcher.find() ? orderMatcher.start(1) : ejbql
       .length();
      
       String countQl = "select count(*) ";
       if (distincted) {
       Class entityClass = ReflectionsUtils.getClassParameterType(
       getClass(), 0);
       // String entityClassName = entityClass.getSimpleName();
       String entityAliasName = EntityUtils
       .getEntityAliasName(entityClass);
       countQl = "select count(distinct " + entityAliasName + ") ";
       }
       countQl += ejbql.substring(fromLoc, orderLoc);
      
       logQl("Seam ext (Query countEjbql) : " + countQl);
       return countQl;
       }
      
       protected String buildEjbql() {
       Class entityClass = ReflectionsUtils.getClassParameterType(getClass(),
       0);
       String entityClassName = entityClass.getSimpleName();
       String entityAliasName = EntityUtils.getEntityAliasName(entityClass);
      
       StringBuffer joinBuilder = new StringBuffer();
       StringBuffer whereBuilder = new StringBuffer();
       boolean joined = false;
      
       if (getState() != null) {
       if (getState().getExample() != null) {
       for (PropertyDescriptor pd : PropertyUtils
       .getPropertyDescriptors(entityClass)) {
       if (ReflectionsUtils.isInstanceOf(pd.getPropertyType(),
       Collection.class.getName())) {
      
       Field field = ReflectionsUtils.getField(entityClass, pd
       .getName());
       Method fieldGetterMethod = ReflectionsUtils
       .getGetterMethod(entityClass, pd.getName());
       Collection fieldValue = null;
       try {
       fieldValue = (Collection) fieldGetterMethod.invoke(
       getState().getExample(), new Object[] {});
       } catch (Exception e) {
       e.printStackTrace();
       }
      
       if (fieldValue != null && fieldValue.size() > 0) {
       Class propertyEntityClass = ReflectionsUtils
       .getCollectionElementType(field
       .getGenericType());
       String propertyAliasName = EntityUtils
       .getEntityAliasName(propertyEntityClass);
       joinBuilder.append(" left join " + entityAliasName
       + "." + pd.getName() + " "
       + propertyAliasName);
      
       joined = true;
       }
       }
       }
       }
      
       // 如果是针对当�entity的一个property说对应的entity进行查询
       if (getState().getQueryPropertyName() != null) {
       Field field = ReflectionsUtils.getField(entityClass, getState()
       .getQueryPropertyName());
       boolean bCollectionType = ReflectionsUtils.isInstanceOf(field
       .getType(), Collection.class.getName());
      
       Class propertyEntityClass = field.getType();
       if (bCollectionType) {
       propertyEntityClass = ReflectionsUtils
       .getCollectionElementType(field.getGenericType());
       }
      
       String propertyAliasName = EntityUtils
       .getEntityAliasName(propertyEntityClass);
      
       String joinItem = " join " + entityAliasName + "."
       + field.getName() + " " + propertyAliasName;
      
       // TODO:暂时使用粗糙的检测是å�¦å˜åœ¨
       if (joinBuilder.toString().indexOf(joinItem) == -1) {
       if (bCollectionType) {
       joinBuilder.append(" left").append(joinItem);
       } else {
       joinBuilder.append(joinItem);
       }
       whereBuilder.append(propertyAliasName + " is not null");
       joined = true;
       }
       }
       }
      
       StringBuffer selectBuilder = new StringBuffer();
       if (joined) {
       selectBuilder.append("select distinct ");
       } else {
       selectBuilder.append("select ");
       }
      
       if (getState() != null && getState().getQueryPropertyName() != null) {
       Field field = ReflectionsUtils.getField(entityClass, getState()
       .getQueryPropertyName());
       boolean bCollectionType = ReflectionsUtils.isInstanceOf(field
       .getType(), Collection.class.getName());
      
       Class propertyEntityClass = field.getType();
       if (bCollectionType) {
       propertyEntityClass = ReflectionsUtils
       .getCollectionElementType(field.getGenericType());
       }
      
       String propertyAliasName = EntityUtils
       .getEntityAliasName(propertyEntityClass);
       selectBuilder.append(propertyAliasName);
       } else {
       selectBuilder.append(entityAliasName);
       }
      
       selectBuilder.append(" from ").append(entityClassName).append(" ")
       .append(entityAliasName).append(joinBuilder);
       if (whereBuilder.length() > 0) {
       selectBuilder.append(" where ").append(whereBuilder);
       }
      
       logQl("Seam ext (Query ejbql) : " + selectBuilder.toString());
       return selectBuilder.toString();
       }
      
       protected List<QueryJoin> buildJoins() {
       List<QueryJoin> joins = new ArrayList<QueryJoin>();
       return joins;
       }
      
       protected List<String> buildRestrictions() {
       List<String> restrictions = new ArrayList<String>();
       if (getState() != null && getState().getExample() != null) {
       Class entityClass = ReflectionsUtils.getClassParameterType(
       getClass(), 0);
       // String entityClassName = entityClass.getSimpleName();
       String entityAliasName = EntityUtils
       .getEntityAliasName(entityClass);
       String queryComponentName = Seam.getComponentName(getClass());
      
       for (PropertyDescriptor pd : PropertyUtils
       .getPropertyDescriptors(entityClass)) {
       if (!ReflectionsUtils.isInstanceOf(pd.getPropertyType(),
       Class.class.getName())) {
       if (ReflectionsUtils.isInstanceOf(pd.getPropertyType(),
       String.class.getName())) {
       // 如果String类型,则使用 like 查询
       restrictions.add("lower(" + entityAliasName + "."
       + pd.getName() + ") like " + "lower('%'||#{"
       + queryComponentName + ".state.example."
       + pd.getName() + "}||'%')");
       } else if (ReflectionsUtils.isInstanceOf(pd
       .getPropertyType(), Collection.class.getName())) {
       // 如果是Collection,则é…�å�ˆå‰�é�¢çš„left join 使用inå�查询方å¼�
       Field field = ReflectionsUtils.getField(entityClass, pd
       .getName());
      
       Method fieldGetterMethod = ReflectionsUtils
       .getGetterMethod(entityClass, pd.getName());
       Collection fieldValue = null;
       try {
       fieldValue = (Collection) fieldGetterMethod.invoke(
       getState().getExample(), new Object[] {});
       } catch (Exception e) {
       e.printStackTrace();
       }
      
       if (fieldValue != null && fieldValue.size() > 0) {
       Class propertyEntityClass = ReflectionsUtils
       .getCollectionElementType(field
       .getGenericType());
       String propertyAliasName = EntityUtils
       .getEntityAliasName(propertyEntityClass);
      
       restrictions.add(propertyAliasName + " in (select "
       + propertyAliasName + "_ from "
       + propertyEntityClass.getSimpleName() + " "
       + propertyAliasName + "_ where "
       + propertyAliasName + "_ in (#{"
       + queryComponentName + ".state.example."
       + pd.getName() + "}))");
       }
       } else {
       // 其余直接进行 = 查询
       restrictions.add(entityAliasName + "." + pd.getName()
       + " = " + "#{" + queryComponentName
       + ".state.example." + pd.getName() + "}");
       }
       }
       }
       }
      
       return restrictions;
       }
      
       @Override
       public void validate() {
       super.validate();
       if (getState() == null) {
       // throw new IllegalStateException("state is null");
       }
       }
      
       @Override
       protected String getRenderedEjbql() {
       String ql = super.getRenderedEjbql();
       logQl("Seam ext (Query renderedEjbql) : " + ql);
       return ql;
       }
      
       @Override
       protected String getCountEjbql() {
       return buildCountEjbql();
       }
      
       @Override
       public Integer getFirstResult() {
       return getState() == null ? super.getFirstResult() : getState()
       .getCurrentPage();
       }
      
       @Override
       public Integer getMaxResults() {
       return getState() == null ? super.getMaxResults() : getState()
       .getPageSize();
       }
      
       @Override
       public String getOrder() {
       return getState() == null ? super.getOrder() : getState().getOrderBy();
       }
      
       @Override
       protected boolean isRestrictionParameterSet(Object parameterValue) {
       boolean bSet = super.isRestrictionParameterSet(parameterValue);
       if (bSet) {
       if (parameterValue != null && parameterValue instanceof Collection) {
       bSet = ((Collection) parameterValue).size() > 0;
       }
       }
       return bSet;
       }
      
       @Override
       public String getEjbql() {
       return buildEjbql();
       }
      
       @Override
       public List<String> getRestrictions() {
       return buildRestrictions();
       }
      
       public void refreshQuery() {
       // clear the parsed QL
       setEjbql(null);
       setRestrictions(null);
       super.refresh();
       }
      
       private void logQl(String ql) {
       log.info(ql);
       }
      
      }
      
      


      public class EntityQueryState<E> implements Serializable {
      
       private static final long serialVersionUID = 4999435737345385599L;
      
       private E example;
      
       private Integer pageSize;
      
       private Integer currentPage;
      
       private String orderBy;
      
       // 用于标识是�查询当�Entity的�个property(Entity类型)的List
       private String queryPropertyName;
      
       // TODO:how to implement?
       private List<QueryJoin> queryJoins = new ArrayList<QueryJoin>();
      
       public E getExample() {
       return example;
       }
      
       public void setExample(E entity) {
       this.example = entity;
       }
      
       public String getOrderBy() {
       return orderBy;
       }
      
       public void setOrderBy(String orderby) {
       this.orderBy = orderby;
       }
      
       public Integer getPageSize() {
       return pageSize;
       }
      
       public void setPageSize(Integer pageSize) {
       this.pageSize = pageSize;
       }
      
       public Integer getCurrentPage() {
       return currentPage;
       }
      
       public void setCurrentPage(Integer currentPage) {
       this.currentPage = currentPage;
       }
      
       public String getQueryPropertyName() {
       return queryPropertyName;
       }
      
       public void setQueryPropertyName(String propertyName) {
       this.queryPropertyName = propertyName;
       }
      
       public List<QueryJoin> getQueryJoins() {
       return queryJoins;
       }
      
       public void setQueryJoins(List<QueryJoin> queryJoins) {
       this.queryJoins = queryJoins;
       }
      }
      
      



      public abstract class RestrictedExampleEntityQuery<E> extends
       ExampleEntityQuery<E> {
      
       private static final long serialVersionUID = -5768415674705835414L;
      
       @Override
       protected String buildEjbql() {
       /**
       * 由于restriction方�里��能使用固定结构的�且�支�一个�数的�且之间是and关系的 QL
       * å�—æ¤é™�制,暂且将行实例æ�¡ä»¶è¡¨è¾¾å¼�作为主QL的一部分
       */
       StringBuffer builder = new StringBuffer().append(super.buildEjbql());
       if (WHERE_PATTERN.matcher(builder).find()) {
       builder.append(" and ");
       } else {
       builder.append(" where ");
       }
       builder.append(getRestrictedQl());
       return builder.toString();
       }
      
       protected String getRestrictedQl() {
       return EntityQuerySecurityRestriction.getRestrictionQl(ReflectionsUtils
       .getClassParameterType(getClass(), 0));
       }
      }