/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> * * $Id$ */ package org.eclipse.ecr.core.api; import java.text.Collator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import org.eclipse.ecr.core.api.model.PropertyException; /** * DocumentModel comparator. Uses ordering independent of case or accent. If two * values are integers/longs, numbering comparison is used. * * @author Florent Guillaume * @author Anahide Tchertchian */ public class DocumentModelComparator implements Sorter { private static final long serialVersionUID = 1L; public static final String ORDER_ASC = "asc"; static final Collator collator = Collator.getInstance(); static { collator.setStrength(Collator.PRIMARY); // case+accent independent } final String schemaName; final Map<String, String> orderBy; /** * Constructor using a schema and a map of field names to compare on. * * @param schemaName the schema name * @param orderBy map using property names as keys, and "asc" or "desc" as * values. Should be a {@link LinkedHashMap} if order of criteria * matters. */ public DocumentModelComparator(String schemaName, Map<String, String> orderBy) { this.schemaName = schemaName; this.orderBy = orderBy; } /** * Constructor using a map of property names to compare on. * * @param orderBy map using property names as keys, and "asc" or "desc" as * values. Should be a {@link LinkedHashMap} if order of criteria * matters. */ public DocumentModelComparator(Map<String, String> orderBy) { this(null, orderBy); } protected int compare(Object v1, Object v2, boolean asc) { if (v1 == null && v2 == null) { return 0; } else if (v1 == null) { return asc ? -1 : 1; } else if (v2 == null) { return asc ? 1 : -1; } final int cmp; if (v1 instanceof Long && v2 instanceof Long) { cmp = ((Long) v1).compareTo((Long) v2); } else if (v1 instanceof Integer && v2 instanceof Integer) { cmp = ((Integer) v1).compareTo((Integer) v2); } else { cmp = collator.compare(v1.toString(), v2.toString()); } return asc ? cmp : -cmp; } @Override public int compare(DocumentModel doc1, DocumentModel doc2) { if (doc1 == null && doc2 == null) { return 0; } else if (doc1 == null) { return -1; } else if (doc2 == null) { return 1; } int cmp = 0; if (schemaName != null) { DataModel d1 = null; DataModel d2 = null; try { d1 = doc1.getDataModel(schemaName); d2 = doc2.getDataModel(schemaName); } catch (ClientException e1) { throw new ClientRuntimeException(e1); } for (Entry<String, String> e : orderBy.entrySet()) { final String fieldName = e.getKey(); final boolean asc = ORDER_ASC.equals(e.getValue()); Object v1; Object v2; try { v1 = d1.getData(fieldName); v2 = d2.getData(fieldName); } catch (PropertyException e1) { throw new ClientRuntimeException(e1); } cmp = compare(v1, v2, asc); if (cmp != 0) { break; } } } else { for (Entry<String, String> e : orderBy.entrySet()) { final String propertyName = e.getKey(); final boolean asc = ORDER_ASC.equals(e.getValue()); Object v1 = null; try { v1 = doc1.getPropertyValue(propertyName); } catch (PropertyException pe) { v1 = null; } catch (ClientException ce) { throw new ClientRuntimeException(ce); } Object v2 = null; try { v2 = doc2.getPropertyValue(propertyName); } catch (PropertyException pe) { v2 = null; } catch (ClientException ce) { throw new ClientRuntimeException(ce); } cmp = compare(v1, v2, asc); if (cmp != 0) { break; } } } if (cmp == 0) { // everything being equal, provide consistent ordering if (doc1.hashCode() == doc2.hashCode()) { cmp = 0; } else if (doc1.hashCode() < doc2.hashCode()) { cmp = -1; } else { cmp = 1; } } return cmp; } }