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