DMOSorter.java
/*
** Module : DMOSorter.java
** Abstract : DMO comparator which uses a list of directional sort criteria
**
** Copyright (c) 2004-2020, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ---------------------------------Description----------------------------------
** 001 ECF 20080510 @38478 Created initial version. DMO comparator which
** uses a list of directional sort criteria.
** 002 ECF 20080708 @39080 Reworked FieldWorker inner class. Fixed CCE
** when FieldWorker was specified for a DMO's
** primary key.
** 003 ECF 20080806 @39322 Added support for 64-bit primary keys.
** Changed primary key sorters to use Long
** instead of Integer.
** 004 CA 20080819 @39455 Support API change in FieldReference.
** 005 ECF 20200906 New ORM implementation.
*/
/*
** 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 may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.persist;
import java.util.*;
/**
* A sorter which orders data model objects (DMOs) according to a list of
* {@link SortCriterion sort criteria}. Each sort criterion specifies an
* individual property of the DMO and the sort direction to be applied to that
* property. As two DMO instances are {@link
* #compare(Record, Record) compared}, the sort criteria are applied
* in order, until a difference in sort order is detected, or the list of
* criteria is exhausted, at which point the DMOs are determined to sort
* equivalently.
*/
public final class DMOSorter
implements Comparator<Record>
{
/** Workers for each sorted DMO property */
private final ArrayList<FieldWorker> workers =
new ArrayList<FieldWorker>();
/**
* Constructor which specifies DMO type and sort criteria.
*
* @param database
* The associated database.
* @param dmoIface
* DMO interface which defines access methods for DMO properties.
* @param sortList
* List of sort criteria which define target properties and sort
* direction for each property.
*/
public DMOSorter(Database database,
Class<? extends DataModelObject> dmoIface,
List<SortCriterion> sortList)
{
Iterator<SortCriterion> iter = sortList.iterator();
while (iter.hasNext())
{
SortCriterion crit = iter.next();
FieldWorker fw = new FieldWorker(database, dmoIface, crit);
workers.add(fw);
}
workers.trimToSize();
}
/**
* Compare two <code>Record</code> instances to determine relative
* sort order, according to the sort criteria specified for this sorter.
* The sort criteria are applied in order, until a difference in sort order
* is detected, or the list of criteria is exhausted, at which point the
* DMOs are determined to sort equivalently.
* <p>
* The comparison of each property uses the natural order of the data,
* except that unknown value always sorts high in an ascending sort. The
* result is inverted for descending sorts (meaning unknown value sorts low
* in a descending sort.
*
* @param p1
* First DMO to compare. Must not be <code>null</code>.
* @param p2
* Second DMO to compare. Must not be <code>null</code>.
*
* @return Positive value if <code>p1</code> > <code>p2</code>;
* negative value if <code>p1</code> < <code>p2</code>;
* <code>0</code> if <code>p1</code> and <code>p2</code> sort
* equivalently.
*/
public int compare(Record p1, Record p2)
{
Iterator<FieldWorker> iter = workers.iterator();
while (iter.hasNext())
{
FieldWorker fw = iter.next();
int result = fw.compare(p1, p2);
if (result != 0)
{
return result;
}
}
return 0;
}
/**
* Helper comparator implementation which compares a particular property of
* a DMO, adjusted for sort direction.
*/
private static class FieldWorker
implements Comparator<Record>
{
/** Ascending primary key sorter */
private static final BasicSorter<Long> ASC_PK_SORTER =
new BasicSorter<Long>(true);
/** Descending primary key sorter */
private static final BasicSorter<Long> DESC_PK_SORTER =
new BasicSorter<Long>(false);
/** Worker object which performs a sort of DMO property data */
private final BasicSorter sorter;
/** Accessor object for DMO property */
private final FieldReference field;
/**
* Constructor which accepts a DMO type and single property sort
* criterion.
*
* @param database
* The associated database.
* @param dmoIface
* DMO type.
* @param criterion
* Sort criterion which specifies property and direction of
* sort.
*/
FieldWorker(Database database, Class<? extends DataModelObject> dmoIface, SortCriterion criterion)
{
boolean ascending = criterion.isAscending();
String property = criterion.getUnqualifiedName();
this.sorter = (criterion.isPrimaryKey()
? (ascending ? ASC_PK_SORTER : DESC_PK_SORTER)
: DataSorter.getInstance(ascending));
this.field = new FieldReference(database, dmoIface, property);
}
/**
* Compare two <code>Record</code> instances to determine relative
* sort order, according to the sort criterion specified for this
* worker. The comparison uses the natural order of the property data,
* except that unknown value always sorts high in an ascending sort.
* The result is inverted for descending sorts (meaning unknown value
* sorts low in a descending sort.
*
* @param p1
* First DMO to compare. Must not be <code>null</code>.
* @param p2
* Second DMO to compare. Must not be <code>null</code>.
*
* @return Positive value if <code>p1</code> > <code>p2</code>;
* negative value if <code>p1</code> < <code>p2</code>;
* <code>0</code> if <code>p1</code> and <code>p2</code> sort
* equivalently.
*/
public int compare(Record p1, Record p2)
{
Comparable c1 = (Comparable) field.get(p1);
Comparable c2 = (Comparable) field.get(p2);
return sorter.compare(c1, c2);
}
}
}