286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: NodeSortRecord.java,v 1.5 2005/09/28 13:48:36 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.dom;
286N/A
286N/Aimport java.text.CollationKey;
286N/Aimport java.text.Collator;
286N/Aimport java.util.Locale;
286N/A
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.CollatorFactory;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.DOM;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.TransletException;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
286N/Aimport com.sun.org.apache.xml.internal.utils.StringComparable;
286N/Aimport com.sun.org.apache.xalan.internal.utils.ObjectFactory;
524N/Aimport com.sun.org.apache.xalan.internal.utils.SecuritySupport;
286N/A
286N/A/**
286N/A * Base class for sort records containing application specific sort keys
286N/A */
286N/Apublic abstract class NodeSortRecord {
286N/A public static final int COMPARE_STRING = 0;
286N/A public static final int COMPARE_NUMERIC = 1;
286N/A
286N/A public static final int COMPARE_ASCENDING = 0;
286N/A public static final int COMPARE_DESCENDING = 1;
286N/A
286N/A /**
286N/A * A reference to a collator. May be updated by subclass if the stylesheet
286N/A * specifies a different language (will be updated iff _locale is updated).
286N/A * @deprecated This field continues to exist for binary compatibility.
286N/A * New code should not refer to it.
286N/A */
286N/A private static final Collator DEFAULT_COLLATOR = Collator.getInstance();
286N/A
286N/A /**
286N/A * A reference to the first Collator
286N/A * @deprecated This field continues to exist for binary compatibility.
286N/A * New code should not refer to it.
286N/A */
286N/A protected Collator _collator = DEFAULT_COLLATOR;
286N/A protected Collator[] _collators;
286N/A
286N/A /**
286N/A * A locale field that might be set by an instance of a subclass.
286N/A * @deprecated This field continues to exist for binary compatibility.
286N/A * New code should not refer to it.
286N/A */
286N/A protected Locale _locale;
286N/A
286N/A protected CollatorFactory _collatorFactory;
286N/A
286N/A protected SortSettings _settings;
286N/A
286N/A private DOM _dom = null;
286N/A private int _node; // The position in the current iterator
286N/A private int _last = 0; // Number of nodes in the current iterator
286N/A private int _scanned = 0; // Number of key levels extracted from DOM
286N/A
286N/A private Object[] _values; // Contains Comparable objects
286N/A
286N/A /**
286N/A * This constructor is run by a call to ClassLoader in the
286N/A * makeNodeSortRecord method in the NodeSortRecordFactory class. Since we
286N/A * cannot pass any parameters to the constructor in that case we just set
286N/A * the default values here and wait for new values through initialize().
286N/A */
286N/A public NodeSortRecord(int node) {
286N/A _node = node;
286N/A }
286N/A
286N/A public NodeSortRecord() {
286N/A this(0);
286N/A }
286N/A
286N/A /**
286N/A * This method allows the caller to set the values that could not be passed
286N/A * to the default constructor.
286N/A */
286N/A public final void initialize(int node, int last, DOM dom,
286N/A SortSettings settings)
286N/A throws TransletException
286N/A {
286N/A _dom = dom;
286N/A _node = node;
286N/A _last = last;
286N/A _settings = settings;
286N/A
286N/A int levels = settings.getSortOrders().length;
286N/A _values = new Object[levels];
286N/A
286N/A String colFactClassname = null;
286N/A try {
286N/A // -- W. Eliot Kimber (eliot@isogen.com)
286N/A colFactClassname =
524N/A SecuritySupport.getSystemProperty("com.sun.org.apache.xalan.internal.xsltc.COLLATOR_FACTORY");
286N/A }
286N/A catch (SecurityException e) {
286N/A // If we can't read the propery, just use default collator
286N/A }
286N/A
286N/A if (colFactClassname != null) {
286N/A try {
286N/A Object candObj = ObjectFactory.findProviderClass(colFactClassname, true);
286N/A _collatorFactory = (CollatorFactory)candObj;
286N/A } catch (ClassNotFoundException e) {
286N/A throw new TransletException(e);
286N/A }
286N/A Locale[] locales = settings.getLocales();
286N/A _collators = new Collator[levels];
286N/A for (int i = 0; i < levels; i++){
286N/A _collators[i] = _collatorFactory.getCollator(locales[i]);
286N/A }
286N/A _collator = _collators[0];
286N/A } else {
286N/A _collators = settings.getCollators();
286N/A _collator = _collators[0];
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Returns the node for this sort object
286N/A */
286N/A public final int getNode() {
286N/A return _node;
286N/A }
286N/A
286N/A /**
286N/A *
286N/A */
286N/A public final int compareDocOrder(NodeSortRecord other) {
286N/A return _node - other._node;
286N/A }
286N/A
286N/A /**
286N/A * Get the string or numeric value of a specific level key for this sort
286N/A * element. The value is extracted from the DOM if it is not already in
286N/A * our sort key vector.
286N/A */
286N/A private final Comparable stringValue(int level) {
286N/A // Get value from our array if possible
286N/A if (_scanned <= level) {
286N/A AbstractTranslet translet = _settings.getTranslet();
286N/A Locale[] locales = _settings.getLocales();
286N/A String[] caseOrder = _settings.getCaseOrders();
286N/A
286N/A // Get value from DOM if accessed for the first time
286N/A final String str = extractValueFromDOM(_dom, _node, level,
286N/A translet, _last);
286N/A final Comparable key =
286N/A StringComparable.getComparator(str, locales[level],
286N/A _collators[level],
286N/A caseOrder[level]);
286N/A _values[_scanned++] = key;
286N/A return(key);
286N/A }
286N/A return((Comparable)_values[level]);
286N/A }
286N/A
286N/A private final Double numericValue(int level) {
286N/A // Get value from our vector if possible
286N/A if (_scanned <= level) {
286N/A AbstractTranslet translet = _settings.getTranslet();
286N/A
286N/A // Get value from DOM if accessed for the first time
286N/A final String str = extractValueFromDOM(_dom, _node, level,
286N/A translet, _last);
286N/A Double num;
286N/A try {
286N/A num = new Double(str);
286N/A }
286N/A // Treat number as NaN if it cannot be parsed as a double
286N/A catch (NumberFormatException e) {
286N/A num = new Double(Double.NEGATIVE_INFINITY);
286N/A }
286N/A _values[_scanned++] = num;
286N/A return(num);
286N/A }
286N/A return((Double)_values[level]);
286N/A }
286N/A
286N/A /**
286N/A * Compare this sort element to another. The first level is checked first,
286N/A * and we proceed to the next level only if the first level keys are
286N/A * identical (and so the key values may not even be extracted from the DOM)
286N/A *
286N/A * !!!!MUST OPTIMISE - THIS IS REALLY, REALLY SLOW!!!!
286N/A */
286N/A public int compareTo(NodeSortRecord other) {
286N/A int cmp, level;
286N/A int[] sortOrder = _settings.getSortOrders();
286N/A int levels = _settings.getSortOrders().length;
286N/A int[] compareTypes = _settings.getTypes();
286N/A
286N/A for (level = 0; level < levels; level++) {
286N/A // Compare the two nodes either as numeric or text values
286N/A if (compareTypes[level] == COMPARE_NUMERIC) {
286N/A final Double our = numericValue(level);
286N/A final Double their = other.numericValue(level);
286N/A cmp = our.compareTo(their);
286N/A }
286N/A else {
286N/A final Comparable our = stringValue(level);
286N/A final Comparable their = other.stringValue(level);
286N/A cmp = our.compareTo(their);
286N/A }
286N/A
286N/A // Return inverse compare value if inverse sort order
286N/A if (cmp != 0) {
286N/A return sortOrder[level] == COMPARE_DESCENDING ? 0 - cmp : cmp;
286N/A }
286N/A }
286N/A // Compare based on document order if all sort keys are equal
286N/A return(_node - other._node);
286N/A }
286N/A
286N/A /**
286N/A * Returns the array of Collators used for text comparisons in this object.
286N/A * May be overridden by inheriting classes
286N/A */
286N/A public Collator[] getCollator() {
286N/A return _collators;
286N/A }
286N/A
286N/A /**
286N/A * Extract the sort value for a level of this key.
286N/A */
286N/A public abstract String extractValueFromDOM(DOM dom, int current, int level,
286N/A AbstractTranslet translet,
286N/A int last);
286N/A
286N/A}