View Javadoc
1   /*
2    * Copyright 2007 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.ole.module.purap.dataaccess.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.ojb.broker.PersistenceBroker;
20  import org.apache.ojb.broker.metadata.ClassDescriptor;
21  import org.apache.ojb.broker.metadata.CollectionDescriptor;
22  import org.apache.ojb.broker.metadata.FieldDescriptor;
23  import org.apache.ojb.broker.platforms.PlatformMySQLImpl;
24  import org.apache.ojb.broker.query.Query;
25  import org.apache.ojb.broker.query.QueryByCriteria;
26  
27  import java.util.Map;
28  
29  /**
30   * This class improves the default order by in OJB by enforcing consistency between Oracle and MySQLs handling of Null values in a
31   * column. Oracle by default sorts nulls last while MySQL does nulls first (i.e. 1,2,3,null MySQL:null,1,2,3; Oracle:1,2,3,null To
32   * get Mysql to sort correctly we need to negate the field that is being Sorted on (i.e. ORDER BY -column DESC = 1,2,3,null while
33   * ORDER BY column DESC = 3,2,1,null) the oracle default for ORDER BY is "NULLS LAST" which the above MySQL tweak should make it
34   * like. This could be improved to pass in nullsFirst to decide which way to display but that would be beyond what ojb currently
35   * does
36   */
37  public class PurapItemQueryCustomizer extends KualiQueryCustomizerDefaultImpl {
38      protected static final String MYSQL_NEGATION = "-";
39      public final static String ORDER_BY_FIELD = "orderByField.";
40      public final static String ASCENDING = "ASC";
41      public final static String DESCENDING = "DESC";
42  
43      /**
44       * In addition to what the referenced method does, this also fixes a mysql order by issue (see class comments)
45       *
46       * @see org.apache.ojb.broker.accesslayer.QueryCustomizerDefaultImpl#customizeQuery(java.lang.Object,
47       *      org.apache.ojb.broker.PersistenceBroker, org.apache.ojb.broker.metadata.CollectionDescriptor,
48       *      org.apache.ojb.broker.query.QueryByCriteria)
49       */
50      @Override
51      public Query customizeQuery(Object anObject, PersistenceBroker broker, CollectionDescriptor cod, QueryByCriteria query) {
52          boolean platformMySQL = broker.serviceSqlGenerator().getPlatform() instanceof PlatformMySQLImpl;
53  
54          Map<String, String> attributes = getAttributes();
55          for (String attributeName : attributes.keySet()) {
56              if (!attributeName.startsWith(ORDER_BY_FIELD)) {
57                  continue;
58              }
59  
60              String fieldName = attributeName.substring(ORDER_BY_FIELD.length());
61              ClassDescriptor itemClassDescriptor = broker.getClassDescriptor(cod.getItemClass());
62              FieldDescriptor orderByFieldDescriptior = itemClassDescriptor.getFieldDescriptorByName(fieldName);
63  
64              // the column to sort on derived from the property name
65              String orderByColumnName = orderByFieldDescriptior.getColumnName();
66  
67              // ascending or descending
68              String fieldValue = attributes.get(attributeName);
69              boolean ascending = (StringUtils.equals(fieldValue, ASCENDING));
70              // throw an error if not ascending or descending
71              if (!ascending && StringUtils.equals(fieldValue, DESCENDING)) {
72                  throw new RuntimeException("neither ASC nor DESC was specified in ojb file for " + fieldName);
73              }
74  
75              if (platformMySQL) {
76                  // by negating the column name in MySQL we can get nulls last (ascending or descending)
77                  String mysqlPrefix = (ascending) ? MYSQL_NEGATION : "";
78                  query.addOrderBy(mysqlPrefix + orderByColumnName, false);
79              } else {
80                  query.addOrderBy(orderByColumnName, ascending);
81              }
82          }
83          return query;
84      }
85  }