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 }