Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 334   Methods: 16
NCLOC: 165   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
IndexPattern.java 87% 89.3% 75% 87%
coverage coverage
 1    /*
 2    * Licensed to the Apache Software Foundation (ASF) under one or more
 3    * contributor license agreements. See the NOTICE file distributed with
 4    * this work for additional information regarding copyright ownership.
 5    * The ASF licenses this file to You under the Apache License, Version 2.0
 6    * (the "License"); you may not use this file except in compliance with
 7    * the License. You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    *
 17    * $Id: IndexPattern.java 628599 2008-02-18 02:33:55Z natalia $
 18    */
 19   
 20    package org.apache.xindice.core.indexer;
 21   
 22    import org.apache.xindice.core.FaultCodes;
 23    import org.apache.xindice.util.ReadOnlyException;
 24    import org.apache.xindice.xml.NamespaceMap;
 25    import org.apache.xindice.xml.SymbolTable;
 26   
 27    import java.util.Arrays;
 28   
 29    /**
 30    * IndexPattern is the internal representation of a pattern for index
 31    * matching purposes.
 32    *
 33    * @version $Revision: 628599 $, $Date: 2008-02-18 02:33:55 +0000 (Mon, 18 Feb 2008) $
 34    */
 35    public final class IndexPattern {
 36   
 37    public static final int PATTERN_NONE = -1;
 38    public static final int PATTERN_WILDCARD = -2;
 39   
 40    public static final int SCORE_NONE = 0;
 41    public static final int SCORE_WILDCARD = 1;
 42    public static final int SCORE_NATURAL = 3;
 43   
 44   
 45    private SymbolTable symbols;
 46    private boolean absolute;
 47    private String[] elemName;
 48    private short elemID[];
 49    private String attrName;
 50    private short attrID = PATTERN_NONE;
 51   
 52   
 53    /**
 54    * Creates IndexPattern object from a string that represents a path in
 55    * a document to the element/attribute being indexed.<br/>
 56    * <br/>
 57    * Pattern consistes of any number of element names separated by symbol
 58    * '/', optionally following by symbol '@' and an attribute name. Pattern
 59    * path can be either relative or absolute.<br/>
 60    * <br/>
 61    * Any one element name or attribute name can be replaced with wildcard
 62    * '*'.<br/>
 63    * <br/>
 64    * Pattern examples:<code><ul>
 65    * <li>/elem1/elem2</li>
 66    * <li>/elem1/elem2@attr</li>
 67    * <li>elem1/elem2@attr</li>
 68    * <li>&#42;/elem2@*</li>
 69    * </ul></code>
 70    * @param symbols Symbol table
 71    * @param pattern String that represents the pattern
 72    * @param nsMap Namespece map
 73    * @throws IndexerException If collection is read-only and one or more
 74    * elements of the pattern do not exist in the collection
 75    */
 76  1478 public IndexPattern(SymbolTable symbols, String pattern, NamespaceMap nsMap) throws IndexerException {
 77  1478 this.symbols = symbols;
 78   
 79  1478 String ptrn = pattern.trim();
 80  1478 if (ptrn.charAt(0) == '/') {
 81  415 absolute = true;
 82  415 ptrn = ptrn.substring(1);
 83    }
 84   
 85  1478 if (ptrn.length() == 0) {
 86  0 throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
 87    }
 88   
 89  1478 elemName = ptrn.split("/", -1);
 90  1478 elemID = new short[elemName.length];
 91   
 92  1478 try {
 93  1478 for (int i = 0; i < elemName.length; i++) {
 94   
 95  2237 if ("".equals(elemName[i])) {
 96  0 throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
 97    }
 98   
 99  2237 int idx = elemName[i].indexOf('@');
 100  2237 if (idx >= 0) {
 101   
 102  607 if (i == elemName.length - 1) {
 103  607 attrName = elemName[i].substring(idx + 1);
 104  607 if (attrName.equals("*")) {
 105  43 attrID = PATTERN_WILDCARD;
 106    } else {
 107  564 attrID = symbols.getNormalizedSymbol(attrName, nsMap, true);
 108    }
 109    } else {
 110  0 throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
 111    }
 112   
 113  607 elemName[i] = elemName[i].substring(0, idx);
 114    }
 115   
 116  2237 if (elemName[i].equals("*")) {
 117  186 elemID[i] = PATTERN_WILDCARD;
 118    } else {
 119  2051 elemID[i] = symbols.getNormalizedSymbol(elemName[i], nsMap, true);
 120    }
 121    }
 122    } catch (ReadOnlyException e) {
 123  0 throw new IndexerException(FaultCodes.IDX_NOT_SUPPORTED,
 124    "Pattern '" + pattern + "' is not allowed in this collection.", e);
 125    }
 126    }
 127   
 128    /**
 129    * Creates new IndexPattern object with an absolute path that is represented
 130    * by elemID arryay.
 131    * @param symbols Symbol table
 132    * @param elemID Array that holds symbols of elements of the path
 133    */
 134  0 public IndexPattern(SymbolTable symbols, short[] elemID) {
 135  0 this(symbols, elemID, false);
 136    }
 137   
 138    /**
 139    * Creates new IndexPattern object with an absolute path that is represented
 140    * by elemID arryay and attrID.
 141    * @param symbols Symbol table
 142    * @param elemID Array that holds symbols of elements of the path
 143    * @param attrID Attribute symbol
 144    */
 145  4777 public IndexPattern(SymbolTable symbols, short[] elemID, short attrID) {
 146  4777 this(symbols, elemID, attrID, true);
 147    }
 148   
 149    /**
 150    * Creates new IndexPattern object with a relative path that is represented
 151    * by single elemID and attrID.
 152    * @param symbols Symbol table
 153    * @param elemID Element symbol
 154    * @param attrID Attribute symbol
 155    */
 156  17414 public IndexPattern(SymbolTable symbols, short elemID, short attrID) {
 157  17414 this(symbols, new short[] { elemID }, attrID, false);
 158    }
 159   
 160    /**
 161    * Creates new IndexPattern object with a path that is represented by
 162    * elemID arryay.
 163    * @param symbols Symbol table
 164    * @param elemID Array that holds symbols of elements of the path
 165    * @param absolute True if path is absolute, false otherwise
 166    */
 167  0 public IndexPattern(SymbolTable symbols, short[] elemID, boolean absolute) {
 168  0 this(symbols, elemID, (short) PATTERN_NONE, absolute);
 169    }
 170   
 171    /**
 172    * Creates new IndexPattern object with a path that is represented by
 173    * elemID arryay and attrID.
 174    * @param symbols Symbol table
 175    * @param elemID Array that holds symbols of elements of the path
 176    * @param attrID Attribute symbol
 177    * @param absolute True if path is absolute, false otherwise
 178    */
 179  22191 public IndexPattern(SymbolTable symbols, short[] elemID, short attrID, boolean absolute) {
 180  22191 this.symbols = symbols;
 181   
 182  22191 this.elemID = elemID;
 183  22191 this.elemName = new String[elemID.length];
 184  22191 for (int i = 0; i < elemID.length; i++) {
 185  25274 this.elemName[i] = symbols.getName(elemID[i]);
 186    }
 187   
 188  22191 this.attrID = attrID;
 189  22191 this.attrName = symbols.getName(attrID);
 190   
 191  22191 this.absolute = absolute;
 192    }
 193   
 194    /**
 195    * Compares this IndexPattern to argument pattern p. The method checks
 196    * if argument pattern can be used in place of this pattern.<br/>
 197    * <br/>
 198    * It returns the strength of the match between the two patterns that can
 199    * be 0 or more, where 0 means the was no match at all. The maximum value
 200    * of match depends on pattern length and therefore is different for
 201    * different patterns.<br/>
 202    * <br/>
 203    * This method should be called by XPath and SAX patterns to be matched
 204    * against Indexer patterns.
 205    * @param p The pattern to compare
 206    * @return The resulting IndexPattern strength
 207    */
 208  14141 public int getMatchLevel(IndexPattern p) {
 209    // parameter pattern cannot match this pattern
 210  14141 if ((p.absolute && !absolute) || (p.elemID.length > elemID.length) ||
 211    (p.absolute && absolute && p.elemID.length != elemID.length)) {
 212  64 return 0;
 213    }
 214   
 215  14077 int result;
 216   
 217  14077 if (attrID != PATTERN_NONE && p.attrID == PATTERN_WILDCARD) {
 218  3116 result = SCORE_WILDCARD;
 219  10961 } else if (attrID == p.attrID) {
 220  2318 result = SCORE_NATURAL;
 221    } else {
 222  8643 return 0;
 223    }
 224   
 225  5434 int i = elemID.length - 1;
 226  5434 int j = p.elemID.length - 1;
 227  5434 while (i >= 0 && j >=0) {
 228  5483 if (p.elemID[j] == PATTERN_WILDCARD) {
 229  3198 result += (SCORE_WILDCARD << 2);
 230  2285 } else if (elemID[i] == p.elemID[j]) {
 231  1870 result += (SCORE_NATURAL << 2);
 232    } else {
 233  415 result = 0;
 234  415 break;
 235    }
 236  5068 i--;
 237  5068 j--;
 238    }
 239   
 240  5434 return result;
 241    }
 242   
 243  66534 public boolean isAbsolute() {
 244  66534 return absolute;
 245    }
 246   
 247    /**
 248    * getElementID returns the last Element Symbol ID for this pattern if
 249    * there is one, otherwise it returns a negative value.
 250    *
 251    * @return The Element Symbol ID
 252    */
 253  85770 public short getElementID() {
 254  85770 return elemID.length > 0 ? elemID[elemID.length - 1] : PATTERN_NONE;
 255    }
 256   
 257    /**
 258    * getElementID returns the arrays of Element Symbol ID for this pattern.
 259    *
 260    * @return The Element Symbol ID
 261    */
 262  69581 public short[] getElementIDs() {
 263  69581 return elemID;
 264    }
 265   
 266    /**
 267    * getAttributeID returns the Attribute Symbol ID for this pattern
 268    * if there is one, otherwise it returns a negative value.
 269    *
 270    * @return The Attribute Symbol ID
 271    */
 272  44467 public short getAttributeID() {
 273  44467 return attrID;
 274    }
 275   
 276    /**
 277    * getElementNames returns the array of Element Name for this pattern.
 278    *
 279    * @return The Element Name
 280    */
 281  0 public String[] getElementNames() {
 282  0 return elemName;
 283    }
 284   
 285    /**
 286    * getAttributeName returns the Attribute Name for this pattern if
 287    * there is one, otherwise it returns null.
 288    *
 289    * @return The Attribute Name
 290    */
 291  0 public String getAttributeName() {
 292  0 return attrName;
 293    }
 294   
 295  2507 public int hashCode() {
 296  2507 return (getElementID() << 16) + attrID;
 297    }
 298   
 299  813 public boolean equals(Object obj) {
 300  813 if (obj instanceof IndexPattern) {
 301  813 IndexPattern p = (IndexPattern) obj;
 302  813 boolean eq = Arrays.equals(elemID, p.elemID) && attrID == p.attrID && absolute == p.absolute;
 303  813 if (eq && (elemName != null || p.elemName != null)) {
 304  644 eq = elemName != null && p.elemName != null && Arrays.equals(elemName, p.elemName);
 305    }
 306  813 if (eq && (attrName != null || p.attrName != null)) {
 307  232 eq = attrName != null && p.attrName != null && attrName.equals(p.attrName);
 308    }
 309  813 return eq;
 310    } else {
 311  0 return false;
 312    }
 313    }
 314   
 315  9 public String toString() {
 316  9 StringBuffer pattern = new StringBuffer();
 317  9 if (absolute) {
 318  4 pattern.append('/');
 319    }
 320   
 321  9 for (int i = 0; i < elemID.length; i++) {
 322  17 pattern.append(elemName[i]);
 323  17 if (i < elemID.length - 1) {
 324  8 pattern.append('/');
 325    }
 326    }
 327   
 328  9 if (attrID != PATTERN_NONE) {
 329  9 pattern.append('@').append(attrName);
 330    }
 331   
 332  9 return pattern.toString();
 333    }
 334    }