1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 2001-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 /* 21 * $Id: NodeSortRecord.java,v 1.5 2005/09/28 13:48:36 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.dom; 25 26 import java.text.CollationKey; 27 import java.text.Collator; 28 import java.util.Locale; 29 30 import com.sun.org.apache.xalan.internal.xsltc.CollatorFactory; 31 import com.sun.org.apache.xalan.internal.xsltc.DOM; 32 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 33 import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; 34 import com.sun.org.apache.xml.internal.utils.StringComparable; 35 import com.sun.org.apache.xalan.internal.utils.ObjectFactory; 36 import com.sun.org.apache.xalan.internal.utils.SecuritySupport; 37 38 /** 39 * Base class for sort records containing application specific sort keys 40 */ 41 public abstract class NodeSortRecord { 42 public static final int COMPARE_STRING = 0; 43 public static final int COMPARE_NUMERIC = 1; 44 45 public static final int COMPARE_ASCENDING = 0; 46 public static final int COMPARE_DESCENDING = 1; 47 48 /** 49 * A reference to a collator. May be updated by subclass if the stylesheet 50 * specifies a different language (will be updated iff _locale is updated). 51 * @deprecated This field continues to exist for binary compatibility. 52 * New code should not refer to it. 53 */ 54 private static final Collator DEFAULT_COLLATOR = Collator.getInstance(); 55 56 /** 57 * A reference to the first Collator 58 * @deprecated This field continues to exist for binary compatibility. 59 * New code should not refer to it. 60 */ 61 protected Collator _collator = DEFAULT_COLLATOR; 62 protected Collator[] _collators; 63 64 /** 65 * A locale field that might be set by an instance of a subclass. 66 * @deprecated This field continues to exist for binary compatibility. 67 * New code should not refer to it. 68 */ 69 protected Locale _locale; 70 71 protected CollatorFactory _collatorFactory; 72 73 protected SortSettings _settings; 74 75 private DOM _dom = null; 76 private int _node; // The position in the current iterator 77 private int _last = 0; // Number of nodes in the current iterator 78 private int _scanned = 0; // Number of key levels extracted from DOM 79 80 private Object[] _values; // Contains Comparable objects 81 82 /** 83 * This constructor is run by a call to ClassLoader in the 84 * makeNodeSortRecord method in the NodeSortRecordFactory class. Since we 85 * cannot pass any parameters to the constructor in that case we just set 86 * the default values here and wait for new values through initialize(). 87 */ 88 public NodeSortRecord(int node) { 89 _node = node; 90 } 91 92 public NodeSortRecord() { 93 this(0); 94 } 95 96 /** 97 * This method allows the caller to set the values that could not be passed 98 * to the default constructor. 99 */ 100 public final void initialize(int node, int last, DOM dom, 101 SortSettings settings) 102 throws TransletException 103 { 104 _dom = dom; 105 _node = node; 106 _last = last; 107 _settings = settings; 108 109 int levels = settings.getSortOrders().length; 110 _values = new Object[levels]; 111 112 String colFactClassname = null; 113 try { 114 // -- W. Eliot Kimber (eliot@isogen.com) 115 colFactClassname = 116 SecuritySupport.getSystemProperty("com.sun.org.apache.xalan.internal.xsltc.COLLATOR_FACTORY"); 117 } 118 catch (SecurityException e) { 119 // If we can't read the propery, just use default collator 120 } 121 122 if (colFactClassname != null) { 123 try { 124 Object candObj = ObjectFactory.findProviderClass(colFactClassname, true); 125 _collatorFactory = (CollatorFactory)candObj; 126 } catch (ClassNotFoundException e) { 127 throw new TransletException(e); 128 } 129 Locale[] locales = settings.getLocales(); 130 _collators = new Collator[levels]; 131 for (int i = 0; i < levels; i++){ 132 _collators[i] = _collatorFactory.getCollator(locales[i]); 133 } 134 _collator = _collators[0]; 135 } else { 136 _collators = settings.getCollators(); 137 _collator = _collators[0]; 138 } 139 } 140 141 /** 142 * Returns the node for this sort object 143 */ 144 public final int getNode() { 145 return _node; 146 } 147 148 /** 149 * 150 */ 151 public final int compareDocOrder(NodeSortRecord other) { 152 return _node - other._node; 153 } 154 155 /** 156 * Get the string or numeric value of a specific level key for this sort 157 * element. The value is extracted from the DOM if it is not already in 158 * our sort key vector. 159 */ 160 private final Comparable stringValue(int level) { 161 // Get value from our array if possible 162 if (_scanned <= level) { 163 AbstractTranslet translet = _settings.getTranslet(); 164 Locale[] locales = _settings.getLocales(); 165 String[] caseOrder = _settings.getCaseOrders(); 166 167 // Get value from DOM if accessed for the first time 168 final String str = extractValueFromDOM(_dom, _node, level, 169 translet, _last); 170 final Comparable key = 171 StringComparable.getComparator(str, locales[level], 172 _collators[level], 173 caseOrder[level]); 174 _values[_scanned++] = key; 175 return(key); 176 } 177 return((Comparable)_values[level]); 178 } 179 180 private final Double numericValue(int level) { 181 // Get value from our vector if possible 182 if (_scanned <= level) { 183 AbstractTranslet translet = _settings.getTranslet(); 184 185 // Get value from DOM if accessed for the first time 186 final String str = extractValueFromDOM(_dom, _node, level, 187 translet, _last); 188 Double num; 189 try { 190 num = new Double(str); 191 } 192 // Treat number as NaN if it cannot be parsed as a double 193 catch (NumberFormatException e) { 194 num = new Double(Double.NEGATIVE_INFINITY); 195 } 196 _values[_scanned++] = num; 197 return(num); 198 } 199 return((Double)_values[level]); 200 } 201 202 /** 203 * Compare this sort element to another. The first level is checked first, 204 * and we proceed to the next level only if the first level keys are 205 * identical (and so the key values may not even be extracted from the DOM) 206 * 207 * !!!!MUST OPTIMISE - THIS IS REALLY, REALLY SLOW!!!! 208 */ 209 public int compareTo(NodeSortRecord other) { 210 int cmp, level; 211 int[] sortOrder = _settings.getSortOrders(); 212 int levels = _settings.getSortOrders().length; 213 int[] compareTypes = _settings.getTypes(); 214 215 for (level = 0; level < levels; level++) { 216 // Compare the two nodes either as numeric or text values 217 if (compareTypes[level] == COMPARE_NUMERIC) { 218 final Double our = numericValue(level); 219 final Double their = other.numericValue(level); 220 cmp = our.compareTo(their); 221 } 222 else { 223 final Comparable our = stringValue(level); 224 final Comparable their = other.stringValue(level); 225 cmp = our.compareTo(their); 226 } 227 228 // Return inverse compare value if inverse sort order 229 if (cmp != 0) { 230 return sortOrder[level] == COMPARE_DESCENDING ? 0 - cmp : cmp; 231 } 232 } 233 // Compare based on document order if all sort keys are equal 234 return(_node - other._node); 235 } 236 237 /** 238 * Returns the array of Collators used for text comparisons in this object. 239 * May be overridden by inheriting classes 240 */ 241 public Collator[] getCollator() { 242 return _collators; 243 } 244 245 /** 246 * Extract the sort value for a level of this key. 247 */ 248 public abstract String extractValueFromDOM(DOM dom, int current, int level, 249 AbstractTranslet translet, 250 int last); 251 252 }