Coverage Report - org.kuali.rice.core.jdbc.criteria.Criteria
 
Classes in this File Line Coverage Branch Coverage Complexity
Criteria
0%
0/227
0%
0/122
2.721
Criteria$AndCriteria
0%
0/5
N/A
2.721
Criteria$OrCriteria
0%
0/5
N/A
2.721
 
 1  
 /*
 2  
  * Copyright 2007-2008 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.core.jdbc.criteria;
 17  
 
 18  
 import java.math.BigDecimal;
 19  
 import java.sql.Timestamp;
 20  
 import java.text.ParseException;
 21  
 import java.text.SimpleDateFormat;
 22  
 import java.util.ArrayList;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.LinkedHashMap;
 26  
 import java.util.List;
 27  
 import java.util.Map;
 28  
 
 29  
 import javax.persistence.Query;
 30  
 
 31  
 import org.kuali.rice.core.database.platform.DatabasePlatform;
 32  
 import org.kuali.rice.core.jpa.criteria.QueryByCriteria.QueryByCriteriaType;
 33  
 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
 34  
 import org.kuali.rice.core.util.RiceConstants;
 35  
 import org.kuali.rice.kew.docsearch.DocSearchUtils;
 36  
 import org.kuali.rice.kns.service.DateTimeService;
 37  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 38  
 import org.kuali.rice.kns.util.TypeUtils;
 39  
 import org.kuali.rice.kns.web.format.BooleanFormatter;
 40  
 
 41  
 
 42  
 
 43  
 /**
 44  
  * A criteria builder for JDBC Query strings.
 45  
  *
 46  
  * TODO: Rewrite this class with a better criteria building algorithm.
 47  
  *
 48  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 49  
  */
 50  
 @SuppressWarnings("unchecked")
 51  0
 public class Criteria {
 52  0
         private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(Criteria.class);
 53  
 
 54  
         private Integer searchLimit;
 55  
 
 56  
         private String entityName;
 57  
 
 58  
         private String alias;
 59  
 
 60  
         private int bindParamCount;
 61  
 
 62  0
         private boolean distinct = false;
 63  
 
 64  0
         protected List tokens = new ArrayList();
 65  
 
 66  0
         private List orderByTokens = new ArrayList();
 67  
 
 68  0
         protected Map<String, Object> params = new LinkedHashMap<String, Object>();
 69  
 
 70  0
         DatabasePlatform dbPlatform = null;
 71  
 
 72  
         public Criteria(String entityName) {
 73  0
                 this(entityName, "a");
 74  0
         }
 75  
 
 76  
         public DatabasePlatform getDbPlatform() {
 77  0
             if (dbPlatform == null) {
 78  0
                     dbPlatform = (DatabasePlatform) GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM);
 79  
             }
 80  0
             return dbPlatform;
 81  
     }
 82  
 
 83  
         public void setDbPlatform(DatabasePlatform dbPlatform){
 84  0
                 this.dbPlatform = dbPlatform;
 85  0
         }
 86  
 
 87  0
         public Criteria(String entityName, String alias) {
 88  0
                 this.entityName = entityName;
 89  0
                 this.alias = alias;
 90  0
         }
 91  
 
 92  
         public void between(String attribute, Object value1, Object value2, Class propertyType) {
 93  
 
 94  0
                 String fixedValue1 = this.fixValue(value1, propertyType);
 95  0
                 String fixedValue2= this.fixValue(value2, propertyType);
 96  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 97  0
                         tokens.add(" (" + fix(attribute) + " BETWEEN " + fixedValue1 + " AND " + fixedValue2 + ") ");
 98  
                 } else {
 99  0
                         tokens.add(" (" + alias + "." + attribute + " BETWEEN " + fixedValue1 + " AND " + fixedValue2 + ") ");
 100  
                 }
 101  
 
 102  0
         }
 103  
 
 104  
         private String fixValue(Object value, Class propertyType){
 105  
                 
 106  0
                 if (value == null) {
 107  0
                         return "";
 108  
                 }
 109  
 
 110  0
                 if(TypeUtils.isJoinClass(propertyType)){
 111  0
                         return value.toString();
 112  
                 }
 113  
 
 114  0
                 if(TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)){
 115  0
                         new BigDecimal(value.toString()); // This should throw an exception if the number is invalid.
 116  0
                         return value.toString();
 117  
                 }
 118  0
                 if(TypeUtils.isTemporalClass(propertyType)){
 119  
                         try {
 120  0
                                 if (value instanceof String) {
 121  0
                                         final DateTimeService dateTimeService = KNSServiceLocator.getDateTimeService();
 122  0
                                         value = dateTimeService.convertToSqlTimestamp(value.toString());
 123  
                                 }
 124  0
                                 return getFixedTemporalValue(value);
 125  0
                         } catch (ParseException pe) {
 126  0
                                 LOG.warn("Could not parse "+value.toString()+" as date");
 127  0
                                 throw new RuntimeException("Could not parse "+value.toString()+" as date", pe);
 128  
                         }
 129  
                 }
 130  0
                 if (TypeUtils.isStringClass(propertyType)) {
 131  0
                         return " '" + getDbPlatform().escapeString(value.toString().trim()) + "' ";
 132  
                 }
 133  0
                 if (TypeUtils.isBooleanClass(propertyType)) {
 134  0
                         if (value instanceof String) {
 135  0
                                 value = new BooleanFormatter().convertFromPresentationFormat(value.toString());
 136  
                         }
 137  0
                         boolean bVal = ((Boolean)value).booleanValue();
 138  0
                         if(bVal){return "1";}
 139  0
                         else { return "0";}
 140  
                 }
 141  
 
 142  0
                 return value.toString();
 143  
         }
 144  
         
 145  
         /**
 146  
          * Prepares a temporally classed value for inclusion in criteria
 147  
          * @param value the Timestamp value to convert
 148  
          * @return the fixed SQL version of that value
 149  
          */
 150  
         private String getFixedTemporalValue(Object value) {
 151  0
                 Timestamp ts = (Timestamp)value;
 152  0
                 java.sql.Date dt = new java.sql.Date(ts.getTime());
 153  0
                 SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
 154  0
                 SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
 155  
 
 156  0
                 String sql = getDbPlatform().getDateSQL(sdfDate.format(dt),sdfTime.format(dt)) ;
 157  0
                 return sql;
 158  
         }
 159  
 
 160  
 
 161  
         /**
 162  
          * This method ...
 163  
          *
 164  
          * @param string
 165  
          * @return
 166  
          */
 167  
 /*
 168  
         private String fixAttr(String attr) {
 169  
                 return "?";
 170  
                 //return fixAttr(attr,0);
 171  
         }
 172  
         private String fixAttr(String attr, int cnt) {
 173  
                 String sRet = attr.replace(".", "_");
 174  
 
 175  
                 if(params.containsKey(sRet)){
 176  
                         sRet = fixAttr(attr, ++cnt);
 177  
                 }
 178  
                 return sRet;
 179  
         }
 180  
 */
 181  
         public void eq(String attribute, Object value, Class propertyType) {
 182  
 
 183  0
                 tokens.add(alias + "." + attribute + " = " + fixValue(value, propertyType) + " ");
 184  
 
 185  0
         }
 186  
 
 187  
         public void gt(String attribute, Object value, Class propertyType) {
 188  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 189  0
                         tokens.add(fix(attribute) + " > " + fixValue(value, propertyType) + " ");
 190  
                 } else {
 191  0
                         tokens.add(alias + "." + attribute + " > " + fixValue(value, propertyType) + " ");
 192  
                 }
 193  
 
 194  0
         }
 195  
 
 196  
         public void gte(String attribute, Object value, Class propertyType) {
 197  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 198  0
                         tokens.add(fix(attribute) + " >= " + fixValue(value, propertyType) + " ");
 199  
                 } else {
 200  0
                         tokens.add(alias + "." + attribute + " >= " + fixValue(value, propertyType) + " ");
 201  
                 }
 202  0
         }
 203  
 
 204  
         public void like(String attribute, Object value, Class propertyType, boolean allowWildcards) {
 205  0
                 String fixedValue = fixValue(value, propertyType);
 206  
 
 207  0
                 if(allowWildcards){
 208  0
                         fixedValue = fixWildcards(stripFunctions(fixedValue));
 209  
                 }
 210  
 
 211  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 212  0
                         tokens.add(fix(attribute) + " LIKE " +  fixedValue + " ");
 213  
                 } else {
 214  0
                         tokens.add(alias + "." + attribute + " LIKE " + fixedValue + " ");
 215  
                 }
 216  0
         }
 217  
 
 218  
         public void notLike(String attribute, Object value, Class propertyType, boolean allowWildcards) {
 219  0
                 String fixedValue = fixValue(value, propertyType);
 220  
 
 221  0
                 if(allowWildcards){
 222  0
                         fixedValue = fixWildcards(stripFunctions(fixedValue));
 223  
                 }
 224  
 
 225  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 226  0
                         tokens.add(fix(attribute) + " NOT LIKE " + fixedValue + " ");
 227  
                 } else {
 228  0
                         tokens.add(alias + "." + attribute + " NOT LIKE " + fixedValue + " ");
 229  
                 }
 230  
                 //tokens.add(alias + "." + attribute + " NOT LIKE " + stripFunctions(fixedValue).replaceAll("\\*", "%") + " ");
 231  0
         }
 232  
 
 233  
         private static String fixWildcards(String sIn){
 234  0
                 String sRet = sIn.replaceAll("\\*", "%");
 235  0
                 return sRet.replaceAll("\\?", "_");
 236  
         }
 237  
 
 238  
         public void lt(String attribute, Object value, Class propertyType) {
 239  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 240  0
                         tokens.add(fix(attribute) + " < " + fixValue(value, propertyType) + " ");
 241  
                 } else {
 242  0
                         tokens.add(alias + "." + attribute + " < " + fixValue(value, propertyType) + " ");
 243  
                 }
 244  0
         }
 245  
 
 246  
         public void lte(String attribute, Object value, Class propertyType) {
 247  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 248  0
                         tokens.add(fix(attribute) + " <= " + fixValue(value, propertyType) + " ");
 249  
                 } else {
 250  0
                         tokens.add(alias + "." + attribute + " <= " + fixValue(value, propertyType) + " ");
 251  
                 }
 252  0
         }
 253  
 
 254  
         public void ne(String attribute, Object value, Class propertyType) {
 255  0
                 tokens.add(alias + "." + attribute + " != " + fixValue(value, propertyType) + " ");
 256  0
         }
 257  
 
 258  
         public void isNull(String attribute) {
 259  0
                 tokens.add(alias + "." + attribute + " IS NULL ");
 260  0
         }
 261  
 
 262  
         public void rawJpql(String jpql) {
 263  0
                 tokens.add(" " + jpql + " ");
 264  0
         }
 265  
 
 266  
         public void in(String attribute, List values, Class propertyType) {
 267  0
                 String in = "";
 268  0
                 for (Object object : values) {
 269  0
                         in += fixValue(object, propertyType) + ",";
 270  
                 }
 271  0
                 if (!"".equals(in)) {
 272  0
                         in = in.substring(0, in.length()-1);
 273  
                 }
 274  0
                 tokens.add(alias + "." + attribute + " IN (" + in + ") ");
 275  0
         }
 276  
 
 277  
         public void notIn(String attribute, List values, Class propertyType) {
 278  0
                 String in = "";
 279  0
                 for (Object object : values) {
 280  0
                         in += fixValue(object, propertyType) + ",";
 281  
                 }
 282  0
                 if (!"".equals(in)) {
 283  0
                         in = in.substring(in.length()-1);
 284  
                 }
 285  0
                 tokens.add(alias + "." + attribute + " NOT IN (" + in + ") ");
 286  0
         }
 287  
 
 288  
         public void orderBy(String attribute, boolean sortAscending) {
 289  0
                 String sort = (sortAscending ? "ASC" : "DESC");
 290  0
                 orderByTokens.add(alias + "." + attribute + " " + sort + " ");
 291  0
         }
 292  
 
 293  
         public void and(Criteria and) {
 294  0
                 tokens.add(new AndCriteria(and));
 295  0
         }
 296  
 
 297  
         public void or(Criteria or) {
 298  0
                 tokens.add(new OrCriteria(or));
 299  0
         }
 300  
 
 301  
         public String toQuery(QueryByCriteriaType type) {
 302  0
                 String queryType = type.toString();
 303  0
                 if (type.equals(QueryByCriteriaType.SELECT)) {
 304  0
                         if(distinct){
 305  0
                                 queryType += " " + "DISTINCT";
 306  
                         }
 307  
 
 308  0
                         queryType += " " + alias;
 309  
                 }
 310  0
                 String queryString = queryType + " FROM " + entityName + " AS " + alias;
 311  0
                 if (!tokens.isEmpty()) {
 312  0
                         queryString += " WHERE " + buildWhere();
 313  
                 }
 314  0
                 if (!orderByTokens.isEmpty()) {
 315  0
                         queryString += " ORDER BY ";
 316  0
                         int count = 0;
 317  0
                         for (Iterator iterator = orderByTokens.iterator(); iterator.hasNext();) {
 318  0
                                 Object token = (Object) iterator.next();
 319  0
                                 if (count == 0) {
 320  0
                                         count++;
 321  
                                 } else {
 322  0
                                         queryString += ", ";
 323  
                                 }
 324  0
                                 queryString += (String) token;
 325  0
                         }
 326  
                 }
 327  0
                 return fix(queryString);
 328  
         }
 329  
 
 330  
         public String toCountQuery() {
 331  0
                 String queryString = "SELECT COUNT(*) FROM " + entityName + " AS " + alias;
 332  0
                 if (!tokens.isEmpty()) {
 333  0
                         queryString += " WHERE " + buildWhere();
 334  
                 }
 335  0
                 return fix(queryString);
 336  
         }
 337  
 
 338  
         private String fix(String queryString) {
 339  0
                 queryString = queryString.replaceAll("__JPA_ALIAS__", alias);
 340  0
                 return queryString;
 341  
         }
 342  
 
 343  
         public String buildWhere() {
 344  0
                 return fix(buildWhere(null));
 345  
         }
 346  
 
 347  
         private String buildWhere(Criteria parentCriteria) {
 348  0
                 String queryString = "";
 349  0
                 int i = 0;
 350  0
                 for (Iterator iterator = tokens.iterator(); iterator.hasNext();) {
 351  0
                         Object token = (Object) iterator.next();
 352  0
                         if (token instanceof Criteria) {
 353  0
                                 String logic = "";
 354  0
                                 if (i>0 && token instanceof AndCriteria) {
 355  0
                                         logic = " AND ";
 356  0
                                 } else if (i>0 && token instanceof OrCriteria) {
 357  0
                                         logic = " OR ";
 358  
                                 }
 359  0
                         queryString += logic + " (" + ((Criteria) token).buildWhere(((Criteria) token)) + ") ";
 360  0
                         } else {
 361  0
                                 if(i>0){
 362  0
                                         queryString += " AND " + (String) token;
 363  
                                 }else{
 364  0
                                         queryString += (String) token;
 365  
                                 }
 366  
                         }
 367  0
                         i++;
 368  0
                 }
 369  0
                 return queryString;
 370  
         }
 371  
 
 372  
         // Keep this package access so the QueryByCriteria can call it from this package.
 373  
         void prepareParameters(Query query) {
 374  0
                 prepareParameters(query, tokens, params);
 375  0
         }
 376  
 
 377  
         public List<Object> getParameteres() {
 378  0
                 return getParameteres(tokens, params);
 379  
         }
 380  
 
 381  
         public List<Object> getParameteres(List tokens, Map<String, Object> params) {
 382  
 
 383  0
                 List<Object> mRet = new ArrayList<Object>();
 384  
 
 385  0
                 for (Map.Entry<String, Object> param : params.entrySet()) {
 386  0
                         Object value = param.getValue();
 387  0
                         if (value instanceof BigDecimal) {
 388  0
                                 value = new Long(((BigDecimal)value).longValue());
 389  
                         }
 390  0
                         if (value instanceof String) {
 391  0
                                 value = ((String)value).replaceAll("\\*", "%");
 392  
                         }
 393  0
                         mRet.add(value);
 394  0
                 }
 395  0
                 for (Iterator iterator = tokens.iterator(); iterator.hasNext();) {
 396  0
                         Object token = (Object) iterator.next();
 397  0
                         if (token instanceof Criteria) {
 398  0
                                 mRet.addAll(getParameteres(((Criteria)token).tokens, ((Criteria)token).params));
 399  
                         }
 400  0
                 }
 401  0
                 return mRet;
 402  
         }
 403  
 
 404  
         void prepareParameters(Query query, List tokens, Map<String, Object> params) {
 405  0
                 for (Map.Entry<String, Object> param : params.entrySet()) {
 406  0
                         Object value = param.getValue();
 407  0
                         if (value instanceof BigDecimal) {
 408  0
                                 value = new Long(((BigDecimal)value).longValue());
 409  
                         }
 410  0
                         if (value instanceof String) {
 411  0
                                 value = ((String)value).replaceAll("\\*", "%");
 412  
                         }
 413  0
                         query.setParameter(param.getKey(), value);
 414  0
                 }
 415  0
                 for (Iterator iterator = tokens.iterator(); iterator.hasNext();) {
 416  0
                         Object token = (Object) iterator.next();
 417  0
                         if (token instanceof Criteria) {
 418  0
                                 prepareParameters(query, ((Criteria)token).tokens, ((Criteria)token).params);
 419  
                         }
 420  0
                 }
 421  0
         }
 422  
 
 423  
         private class AndCriteria extends Criteria {
 424  0
                 public AndCriteria(Criteria and) {
 425  0
                         super(and.entityName, and.alias);
 426  0
                         this.tokens = new ArrayList(and.tokens);
 427  0
                         this.params = new HashMap(and.params);
 428  0
                 }
 429  
         }
 430  
 
 431  
         private class OrCriteria extends Criteria {
 432  0
                 public OrCriteria(Criteria or) {
 433  0
                         super(or.entityName, or.alias);
 434  0
                         this.tokens = new ArrayList(or.tokens);
 435  0
                         this.params = new HashMap(or.params);
 436  0
                 }
 437  
         }
 438  
 
 439  
         public Integer getSearchLimit() {
 440  0
                 return this.searchLimit;
 441  
         }
 442  
 
 443  
         public void setSearchLimit(Integer searchLimit) {
 444  0
                 this.searchLimit = searchLimit;
 445  0
         }
 446  
 
 447  
 
 448  
         public void notNull(String attribute) {
 449  0
                 tokens.add(alias + "." + attribute + " IS NOT NULL ");
 450  0
         }
 451  
 
 452  
         public void distinct(boolean distinct){
 453  0
                 this.distinct = distinct;
 454  0
         }
 455  
 
 456  
         /**
 457  
          * This method ...
 458  
          *
 459  
          * @param string
 460  
          * @param timestamp
 461  
          * @param timestamp2
 462  
          */
 463  
         public void notBetween(String attribute, Object value1,
 464  
                         Object value2, Class propertyType) {
 465  0
                 String fixedValue1 = fixValue(value1, propertyType);
 466  0
                 String fixedValue2 = fixValue(value1, propertyType);
 467  0
                 if (attribute.contains("__JPA_ALIAS__")) {
 468  0
                         tokens.add(" (" + fix(attribute) + " NOT BETWEEN " + fixedValue1 + " AND " + fixedValue2 + ") ");
 469  
                 } else {
 470  0
                         tokens.add(" (" + alias + "." + attribute + " NOT BETWEEN " + fixedValue1 + " AND " + fixedValue2 + ") ");
 471  
                 }
 472  
 
 473  0
         }
 474  
 
 475  
         /**
 476  
          * This method ...
 477  
          *
 478  
          * @param string
 479  
          * @param responsibilitySubQuery
 480  
          */
 481  
         public void in(String match, Criteria subQuery, String attribute, Class propertyType) {
 482  0
                 if("a".equals(subQuery.alias)){
 483  0
                         subQuery.alias="b";
 484  
                 }
 485  0
                 String whereClause = "";
 486  0
                 if(subQuery.tokens.isEmpty()){
 487  0
                         whereClause = "WHERE ";
 488  
                 }else{
 489  0
                         whereClause = "AND ";
 490  
                 }
 491  0
                 whereClause += subQuery.alias+"."+attribute + " = " + alias+"."+match;
 492  
 
 493  0
                 tokens.add("EXISTS (" + subQuery.toQuery(QueryByCriteriaType.SELECT) + whereClause + " ) ");
 494  
 
 495  0
         }
 496  
 
 497  
         private String stripFunctions(String attribute) {
 498  0
             int index = attribute.lastIndexOf('(');
 499  0
             if(index != -1) {
 500  0
                 return attribute.substring(index+1, attribute.indexOf(')'));
 501  
             }
 502  
 
 503  0
             return attribute;
 504  
         }
 505  
         public String getAlias(){
 506  0
                 return this.alias;
 507  
         }
 508  
 
 509  
         public String establishDateString(String fromDate, String toDate, String columnDbName, String whereStatementClause) {
 510  0
             DatabasePlatform platform = getDbPlatform();
 511  0
             StringBuffer dateSqlString = new StringBuffer(whereStatementClause).append(" " + platform.escapeString(columnDbName) + " ");
 512  0
         if (fromDate != null && DocSearchUtils.getSqlFormattedDate(fromDate) != null && toDate != null && DocSearchUtils.getSqlFormattedDate(toDate) != null) {
 513  0
             return dateSqlString.append(" >= " + platform.getDateSQL(platform.escapeString(DocSearchUtils.getSqlFormattedDate(fromDate.trim())), null) + " and " + platform.escapeString(columnDbName) + " <= " + platform.getDateSQL(platform.escapeString(DocSearchUtils.getSqlFormattedDate(toDate.trim())), "23:59:59")).toString();
 514  
         } else {
 515  0
             if (fromDate != null && DocSearchUtils.getSqlFormattedDate(fromDate) != null) {
 516  0
                 return dateSqlString.append(" >= " + platform.getDateSQL(platform.escapeString(DocSearchUtils.getSqlFormattedDate(fromDate.trim())), null)).toString();
 517  0
             } else if (toDate != null && DocSearchUtils.getSqlFormattedDate(toDate) != null) {
 518  0
                 return dateSqlString.append(" <= " + platform.getDateSQL(platform.escapeString(DocSearchUtils.getSqlFormattedDate(toDate.trim())), "23:59:59")).toString();
 519  
             } else {
 520  0
                 return "";
 521  
             }
 522  
         }
 523  
     }
 524  
 }