1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9package com.sleepycat.persist.impl; 10 11import java.io.Serializable; 12import java.util.Comparator; 13import java.util.HashMap; 14import java.util.Map; 15 16/** 17 * The btree comparator for persistent key classes. The serialized form of 18 * this comparator is stored in the BDB JE database descriptor so that the 19 * comparator can be re-created during recovery. 20 * 21 * @author Mark Hayes 22 */ 23public class PersistComparator implements Comparator<byte[]>, Serializable { 24 25 private static final long serialVersionUID = 5221576538843355317L; 26 27 private String keyClassName; 28 private String[] comositeFieldOrder; 29 private Map<String, String[]> fieldFormatData; 30 private transient PersistKeyBinding binding; 31 32 public PersistComparator(PersistKeyBinding binding) { 33 this.binding = binding; 34 /* Save info necessary to recreate binding during deserialization. */ 35 final CompositeKeyFormat format = 36 (CompositeKeyFormat) binding.keyFormat; 37 keyClassName = format.getClassName(); 38 comositeFieldOrder = CompositeKeyFormat.getFieldNameArray 39 (format.getClassMetadata().getCompositeKeyFields()); 40 /* Currently only enum formats have per-class data. */ 41 for (FieldInfo field : format.getFieldInfo()) { 42 Format fieldFormat = field.getType(); 43 if (fieldFormat.isEnum()) { 44 EnumFormat enumFormat = (EnumFormat) fieldFormat; 45 if (fieldFormatData == null) { 46 fieldFormatData = new HashMap<String, String[]>(); 47 } 48 fieldFormatData.put(enumFormat.getClassName(), 49 enumFormat.getFormatData()); 50 } 51 } 52 } 53 54 public int compare(byte[] b1, byte[] b2) { 55 56 /* 57 * The binding will be null after the comparator is deserialized, i.e., 58 * during BDB JE recovery. We must construct it here, without access 59 * to the stored catalog since recovery is not complete. 60 */ 61 if (binding == null) { 62 Catalog catalog = SimpleCatalog.getInstance(); 63 Map<String, Format> enumFormats = null; 64 if (fieldFormatData != null) { 65 enumFormats = new HashMap<String, Format>(); 66 for (Map.Entry<String, String[]> entry : 67 fieldFormatData.entrySet()) { 68 final String fldClassName = entry.getKey(); 69 final String[] enumNames = entry.getValue(); 70 final Class fldClass; 71 try { 72 fldClass = SimpleCatalog.classForName(fldClassName); 73 } catch (ClassNotFoundException e) { 74 throw new IllegalStateException(e); 75 } 76 enumFormats.put(fldClassName, 77 new EnumFormat(fldClass, enumNames)); 78 } 79 catalog = new ComparatorCatalog(enumFormats); 80 for (Format fldFormat : enumFormats.values()) { 81 fldFormat.initializeIfNeeded(catalog, null /*model*/); 82 } 83 } 84 final Class keyClass; 85 try { 86 keyClass = SimpleCatalog.classForName(keyClassName); 87 } catch (ClassNotFoundException e) { 88 throw new IllegalStateException(e); 89 } 90 binding = new PersistKeyBinding(catalog, keyClass, 91 comositeFieldOrder); 92 } 93 94 Comparable k1 = (Comparable) binding.bytesToObject(b1, 0, b1.length); 95 Comparable k2 = (Comparable) binding.bytesToObject(b2, 0, b2.length); 96 97 return k1.compareTo(k2); 98 } 99 100 @Override 101 public String toString() { 102 StringBuilder b = new StringBuilder(); 103 b.append("[DPL comparator "); 104 b.append(" keyClassName = ").append(keyClassName); 105 b.append(" comositeFieldOrder = ["); 106 for (String s : comositeFieldOrder) { 107 b.append(s).append(','); 108 } 109 b.append(']'); 110 b.append(" fieldFormatData = {"); 111 for (Map.Entry<String, String[]> entry : fieldFormatData.entrySet()) { 112 b.append(entry.getKey()).append(": ["); 113 for (String s : entry.getValue()) { 114 b.append(s).append(','); 115 } 116 b.append(']'); 117 } 118 b.append('}'); 119 b.append(']'); 120 return b.toString(); 121 } 122} 123