/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.purap.dataaccess.impl; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.ojb.broker.PersistenceBroker; import org.apache.ojb.broker.metadata.ClassDescriptor; import org.apache.ojb.broker.metadata.CollectionDescriptor; import org.apache.ojb.broker.metadata.FieldDescriptor; import org.apache.ojb.broker.platforms.PlatformMySQLImpl; import org.apache.ojb.broker.query.Query; import org.apache.ojb.broker.query.QueryByCriteria; /** * This class improves the default order by in OJB by enforcing consistency between Oracle and MySQLs handling of Null values in a * 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 * 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 * 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 * like. This could be improved to pass in nullsFirst to decide which way to display but that would be beyond what ojb currently * does */ public class PurapItemQueryCustomizer extends KualiQueryCustomizerDefaultImpl { protected static final String MYSQL_NEGATION = "-"; public final static String ORDER_BY_FIELD = "orderByField."; public final static String ASCENDING = "ASC"; public final static String DESCENDING = "DESC"; /** * In addition to what the referenced method does, this also fixes a mysql order by issue (see class comments) * @see org.apache.ojb.broker.accesslayer.QueryCustomizerDefaultImpl#customizeQuery(java.lang.Object, * org.apache.ojb.broker.PersistenceBroker, org.apache.ojb.broker.metadata.CollectionDescriptor, * org.apache.ojb.broker.query.QueryByCriteria) */ @Override public Query customizeQuery(Object anObject, PersistenceBroker broker, CollectionDescriptor cod, QueryByCriteria query) { boolean platformMySQL = broker.serviceSqlGenerator().getPlatform() instanceof PlatformMySQLImpl; Map<String, String> attributes = getAttributes(); for (String attributeName : attributes.keySet()) { if (!attributeName.startsWith(ORDER_BY_FIELD)) { continue; } String fieldName = attributeName.substring(ORDER_BY_FIELD.length()); ClassDescriptor itemClassDescriptor = broker.getClassDescriptor(cod.getItemClass()); FieldDescriptor orderByFieldDescriptior = itemClassDescriptor.getFieldDescriptorByName(fieldName); // the column to sort on derived from the property name String orderByColumnName = orderByFieldDescriptior.getColumnName(); // ascending or descending String fieldValue = attributes.get(attributeName); boolean ascending = (StringUtils.equals(fieldValue, ASCENDING)); // throw an error if not ascending or descending if (!ascending && StringUtils.equals(fieldValue, DESCENDING)) { throw new RuntimeException("neither ASC nor DESC was specified in ojb file for " + fieldName); } if (platformMySQL) { // by negating the column name in MySQL we can get nulls last (ascending or descending) String mysqlPrefix = (ascending) ? MYSQL_NEGATION : ""; query.addOrderBy(mysqlPrefix + orderByColumnName, false); } else { query.addOrderBy(orderByColumnName, ascending); } } return query; } }