/* * Copyright (c) 2002-2009 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j 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.neo4j.kernel.impl.traversal; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.NotFoundException; import java.io.Serializable; import java.util.Comparator; /** * A <CODE>NodeSortInfo</CODE> class represents a sort operation on a set of * nodes. The client creates a <CODE>NodeSortInfo</CODE> object that can be * passed to {@link java.util.Collections#sort} with a collection of nodes. * <p> * The <CODE>NodeSortInfo</CODE> class is an imlementation of the typsesafe * extensible enum [see Bloch01]. * <p> * <CODE>NodeSortInfo</CODE> contains an inner class <CODE>PropertySortInfo</CODE> * that can be used by a client to sort nodes depending on a node property. Here * is a sample code snippet sorting nodes from a traverser: * <p> * <CODE><PRE> // create the traverser ... Traverser traverser = * TraverserFactory.getFactory().createTraverser( .... ); // sort on property * "title" Traverser sortedTraverser = traverser.sort( new * NodeSortInfo.PropertySortInto( PropertyIndex.index( "title" ) ) ); // get the * nodes sorted by property "title" while ( sortedTraverser.hasNext() ) { Node * node = sortedTraverser.nextNode(); // ... } * * </PRE></CODE> * <p> * @see InternalTraverser * @see java.util.Comparator * @see java.util.Collections */ public abstract class NodeSortInfo<T extends Node> implements Comparator<T>, Serializable { /** * Compares its two arguments for order. Returns a negative integer, zero, * or a positive integer as the first argument is less than, equal to, or * greater than the second. See {@link java.util.Comparator} for more * information. * <p> * <CODE>NodeSortInfo</CODE> is intended to be used on collections of * nodes. A collection containing a non <CODE>Node</CODE> element should * result in a <CODE>ClassCastException</CODE>. * * @param node1 * first argument * @param node2 * second argument * @throws ClassCastException * if argument type is non <CODE>Node</CODE> */ public abstract int compare( Node node1, Node node2 ); /** * Inner class that represents a sort operation using a node property. */ public static class PropertySortInfo<T extends Node> extends NodeSortInfo<T> { private String key = null; private int direction = 1; /** * Creates a <CODE>PropertySortInfo</CODE> object using property * <CODE>index</CODE> for sorting. * * @param index * the node property used when sorting */ public PropertySortInfo( String key ) { this.key = key; } /** * Creates a <CODE>PropertySortInfo</CODE> object using property * <CODE>index</CODE> for sorting. If <CODE>descending</CODE> is set * to true the order will be reversed. * * @param index * the node property used when sorting * @param descending * if true order will be reversed */ public PropertySortInfo( String key, boolean descending ) { this.key = key; if ( descending ) { direction = -1; } } /** * Compares its two arguments, see {@link Comparator#compare} for more * information. * <p> * Both arguments has to be of type <CODE>Node</CODE> or a <CODE>ClassCastException</CODE> * will be thrown. If the first argument lack the property used for * sorting a negative integer will be returned. If the second argument * lacks the property a positive integer will be returned. If both * arguments lack the property zero will be returned. * <p> * If the properties are of the same copmarable type (such as Integer or * String) the <CODE>compareTo</CODE> method on that property will be * invoked passing the second property. If the properties not the same * type (but have the compareTo method) they will be converted to * strings (via toString method) and compared. If the first property * isn't comparable but the second property is a negative integer will * be returned. If both properties aren't comparable zero will be * returned. * * @param obj1 * the first argument * @param obj2 * the second argument * @throws ClassCastException * if argument type is non Node */ public int compare( Node node1, Node node2 ) { Object property1 = null; Object property2 = null; try { property1 = node1.getProperty( key ); } catch ( NotFoundException e ) { // ok, null then } try { property2 = node2.getProperty( key ); } catch ( NotFoundException e ) { // ok, null then } // check if one or both is null if ( property1 == null ) { return (property2 == null ? 0 : -1) * direction; } if ( property2 == null ) { return 1 * direction; } // if property1 Integer or String, compare to property2 if ( property1 instanceof Integer ) { if ( property2 instanceof Integer ) { return ((Integer) property1) .compareTo( (Integer) property2 ) * direction; } else if ( property2 instanceof String ) { // alpha numeric String stringValue = property1.toString(); return stringValue.compareTo( (String) property2 ) * direction; } else { // property1 wins return 1 * direction; } } if ( property1 instanceof String ) { if ( property2 instanceof String ) { return ((String) property1).compareTo( (String) property2 ) * direction; } else if ( property2 instanceof Integer ) { // alpha numeric return ((String) property1) .compareTo( property2.toString() ) * direction; } else { // property1 wins return 1 * direction; } } // if property2 is Integer or String, property2 wins if ( (property2 instanceof Integer) || (property2 instanceof String) ) { // property2 wins return -1 * direction; } // we know nothing about the property types, make them equal return 0; } } }