001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 011 * 012 * $Id$ 013 */ 014 015package org.nuxeo.ecm.core.api; 016 017import java.text.Collator; 018import java.util.LinkedHashMap; 019import java.util.Map; 020import java.util.Map.Entry; 021 022/** 023 * DocumentModel comparator. Uses ordering independent of case or accent. If two values are integers/longs, numbering 024 * comparison is used. 025 * 026 * @author Florent Guillaume 027 * @author Anahide Tchertchian 028 */ 029public class DocumentModelComparator implements Sorter { 030 031 private static final long serialVersionUID = 1L; 032 033 public static final String ORDER_ASC = "asc"; 034 035 static final Collator collator = Collator.getInstance(); 036 037 static { 038 collator.setStrength(Collator.PRIMARY); // case+accent independent 039 } 040 041 final String schemaName; 042 043 final Map<String, String> orderBy; 044 045 /** 046 * Constructor using a schema and a map of field names to compare on. 047 * 048 * @param schemaName the schema name 049 * @param orderBy map using property names as keys, and "asc" or "desc" as values. Should be a {@link LinkedHashMap} 050 * if order of criteria matters. 051 */ 052 public DocumentModelComparator(String schemaName, Map<String, String> orderBy) { 053 this.schemaName = schemaName; 054 this.orderBy = orderBy; 055 } 056 057 /** 058 * Constructor using a map of property names to compare on. 059 * 060 * @param orderBy map using property names as keys, and "asc" or "desc" as values. Should be a {@link LinkedHashMap} 061 * if order of criteria matters. 062 */ 063 public DocumentModelComparator(Map<String, String> orderBy) { 064 this(null, orderBy); 065 } 066 067 protected int compare(Object v1, Object v2, boolean asc) { 068 if (v1 == null && v2 == null) { 069 return 0; 070 } else if (v1 == null) { 071 return asc ? -1 : 1; 072 } else if (v2 == null) { 073 return asc ? 1 : -1; 074 } 075 final int cmp; 076 if (v1 instanceof Long && v2 instanceof Long) { 077 cmp = ((Long) v1).compareTo((Long) v2); 078 } else if (v1 instanceof Integer && v2 instanceof Integer) { 079 cmp = ((Integer) v1).compareTo((Integer) v2); 080 } else { 081 cmp = collator.compare(v1.toString(), v2.toString()); 082 } 083 return asc ? cmp : -cmp; 084 } 085 086 @Override 087 public int compare(DocumentModel doc1, DocumentModel doc2) { 088 if (doc1 == null && doc2 == null) { 089 return 0; 090 } else if (doc1 == null) { 091 return -1; 092 } else if (doc2 == null) { 093 return 1; 094 } 095 096 int cmp = 0; 097 if (schemaName != null) { 098 DataModel d1 = doc1.getDataModel(schemaName); 099 DataModel d2 = doc2.getDataModel(schemaName); 100 for (Entry<String, String> e : orderBy.entrySet()) { 101 final String fieldName = e.getKey(); 102 final boolean asc = ORDER_ASC.equals(e.getValue()); 103 Object v1 = d1.getData(fieldName); 104 Object v2 = d2.getData(fieldName); 105 cmp = compare(v1, v2, asc); 106 if (cmp != 0) { 107 break; 108 } 109 } 110 } else { 111 for (Entry<String, String> e : orderBy.entrySet()) { 112 final String propertyName = e.getKey(); 113 final boolean asc = ORDER_ASC.equals(e.getValue()); 114 Object v1 = null; 115 try { 116 v1 = doc1.getPropertyValue(propertyName); 117 } catch (PropertyException pe) { 118 v1 = null; 119 } 120 Object v2 = null; 121 try { 122 v2 = doc2.getPropertyValue(propertyName); 123 } catch (PropertyException pe) { 124 v2 = null; 125 } 126 cmp = compare(v1, v2, asc); 127 if (cmp != 0) { 128 break; 129 } 130 } 131 } 132 if (cmp == 0) { 133 // everything being equal, provide consistent ordering 134 if (doc1.hashCode() == doc2.hashCode()) { 135 cmp = 0; 136 } else if (doc1.hashCode() < doc2.hashCode()) { 137 cmp = -1; 138 } else { 139 cmp = 1; 140 } 141 } 142 return cmp; 143 } 144 145}