/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.metadata.index; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.teiid.core.TeiidException; import org.teiid.core.index.IEntryResult; import org.teiid.internal.core.index.Index; /** * IndexUtil */ public class SimpleIndexUtil { //############################################################################################################################ //# Constants # //############################################################################################################################ public static final boolean CASE_SENSITIVE_INDEX_FILE_NAMES = false; //############################################################################################################################ //# Indexing Methods # //############################################################################################################################ /** * Return all index file records that match the specified record prefix * or pattern. The pattern can be constructed from any combination of characters * including the multiple character wildcard '*' and single character * wildcard '?'. The prefix may be constructed from any combination of * characters excluding the wildcard characters. The prefix specifies a fixed * number of characters that the index record must start with. * @param monitor an optional ProgressMonitor * @param indexes the array of MtkIndex instances to query * @param pattern * @return results * @throws MetamatrixCoreException */ public static IEntryResult[] queryIndex(final Index[] indexes, final char[] pattern, final boolean isPrefix, final boolean isCaseSensitive, final boolean returnFirstMatch) throws TeiidException { final List<IEntryResult> queryResult = new ArrayList<IEntryResult>(); try { for (int i = 0; i < indexes.length; i++) { IEntryResult[] partialResults = null; if(isPrefix) { // Query based on prefix. This uses a fast binary search // based on matching the first n characters in the index record. // The index files contain records that are sorted alphabetically // by fullname such that the search algorithm can quickly determine // which index block(s) contain the matching prefixes. partialResults = indexes[i].queryEntries(pattern, isCaseSensitive); } else { // Search for index records matching the specified pattern partialResults = indexes[i].queryEntriesMatching(pattern, isCaseSensitive); } // If any of these IEntryResults represent an index record that is continued // across multiple entries within the index file then we must query for those // records and build the complete IEntryResult if (partialResults != null) { partialResults = addContinuationRecords(indexes[i], partialResults); } // Process these results against the specified pattern and return // only the subset entries that match both criteria if (partialResults != null) { for (int j = 0; j < partialResults.length; j++) { // filter out any continuation records, they should already appended // to index record thet is continued IEntryResult result = partialResults[j]; if(result != null && result.getWord()[0] != MetadataConstants.RECORD_TYPE.RECORD_CONTINUATION) { queryResult.add(partialResults[j]); } } } if (returnFirstMatch && queryResult.size() > 0) { break; } } } catch(IOException e) { throw new TeiidException(RuntimeMetadataPlugin.Event.TEIID80003, e); } return queryResult.toArray(new IEntryResult[queryResult.size()]); } private static IEntryResult[] addContinuationRecords(final Index index, final IEntryResult[] partialResults) throws IOException { final int blockSize = RecordFactory.INDEX_RECORD_BLOCK_SIZE; IEntryResult[] results = partialResults; for (int i = 0; i < results.length; i++) { IEntryResult partialResult = results[i]; char[] word = partialResult.getWord(); // If this IEntryResult is not continued on another record then skip to the next result if (word.length < blockSize || word[blockSize-1] != MetadataConstants.RECORD_TYPE.RECORD_CONTINUATION) { continue; } // Extract the UUID from the IEntryResult to use when creating the prefix string String objectID = RecordFactory.extractUUIDString(partialResult); String patternStr = "" //$NON-NLS-1$ + MetadataConstants.RECORD_TYPE.RECORD_CONTINUATION + word[0] + IndexConstants.RECORD_STRING.RECORD_DELIMITER + objectID + IndexConstants.RECORD_STRING.RECORD_DELIMITER; // Query the index file for any continuation records IEntryResult[] continuationResults = index.queryEntries(patternStr.toCharArray(), true); // If found the continued records then join to the original result and stop searching if (continuationResults != null && continuationResults.length > 0) { results[i] = RecordFactory.joinEntryResults(partialResult, continuationResults, blockSize); } } return results; } }