/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jackrabbit.core.query.lucene; import org.apache.lucene.search.Query; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.index.Term; import org.apache.lucene.index.IndexReader; import org.apache.lucene.util.ToStringUtils; import org.apache.jackrabbit.spi.Name; import javax.jcr.RepositoryException; import java.io.IOException; /** * <code>NameRangeQuery</code>... */ @SuppressWarnings("serial") public class NameRangeQuery extends Query { /** * The lower name. May be <code>null</code> if <code>upperName</code> is not * <code>null</code>. */ private final Name lowerName; /** * The upper name. May be <code>null</code> if <code>lowerName</code> is not * <code>null</code>. */ private final Name upperName; /** * If <code>true</code> the range interval is inclusive. */ private final boolean inclusive; /** * The index format version. */ private final IndexFormatVersion version; /** * The internal namespace mappings. */ private final NamespaceMappings nsMappings; private final PerQueryCache cache; /** * Creates a new NameRangeQuery. The lower or the upper name may be * <code>null</code>, but not both! * * @param lowerName the lower name of the interval, or <code>null</code> * @param upperName the upper name of the interval, or <code>null</code>. * @param inclusive if <code>true</code> the interval is inclusive. * @param version the index format version. * @param nsMappings the internal namespace mappings. */ public NameRangeQuery(Name lowerName, Name upperName, boolean inclusive, IndexFormatVersion version, NamespaceMappings nsMappings, PerQueryCache cache) { if (lowerName == null && upperName == null) { throw new IllegalArgumentException("At least one term must be non-null"); } if (lowerName != null && upperName != null && !lowerName.getNamespaceURI().equals(upperName.getNamespaceURI())) { throw new IllegalArgumentException("Both names must have the same namespace URI"); } this.lowerName = lowerName; this.upperName = upperName; this.inclusive = inclusive; this.version = version; this.nsMappings = nsMappings; this.cache = cache; } /** * {@inheritDoc} */ public Query rewrite(IndexReader reader) throws IOException { Query q; if (version.getVersion() >= IndexFormatVersion.V3.getVersion()) { RangeQuery localNames = new RangeQuery( getLowerLocalNameTerm(), getUpperLocalNameTerm(), inclusive, cache); BooleanQuery query = new BooleanQuery(); query.add(new JackrabbitTermQuery(new Term(FieldNames.NAMESPACE_URI, getNamespaceURI())), BooleanClause.Occur.MUST); query.add(localNames, BooleanClause.Occur.MUST); q = query; } else { q = new RangeQuery( getLowerTerm(), getUpperTerm(), inclusive, cache); } return q.rewrite(reader); } /** * {@inheritDoc} */ public String toString(String field) { StringBuffer buffer = new StringBuffer(); buffer.append("name():"); buffer.append(inclusive ? "[" : "{"); buffer.append(lowerName != null ? lowerName.toString() : "null"); buffer.append(" TO "); buffer.append(upperName != null ? upperName.toString() : "null"); buffer.append(inclusive ? "]" : "}"); buffer.append(ToStringUtils.boost(getBoost())); return buffer.toString(); } //----------------------------< internal >---------------------------------- /** * @return the namespace URI of this name query. */ private String getNamespaceURI() { return lowerName != null ? lowerName.getNamespaceURI() : upperName.getNamespaceURI(); } /** * @return the local name term of the lower name or <code>null</code> if no * lower name is set. */ private Term getLowerLocalNameTerm() { if (lowerName == null) { return null; } else { return new Term(FieldNames.LOCAL_NAME, lowerName.getLocalName()); } } /** * @return the local name term of the upper name or <code>null</code> if no * upper name is set. */ private Term getUpperLocalNameTerm() { if (upperName == null) { return null; } else { return new Term(FieldNames.LOCAL_NAME, upperName.getLocalName()); } } /** * @return the lower term. Must only be used for IndexFormatVersion < 3. * @throws IOException if a name cannot be translated. */ private Term getLowerTerm() throws IOException { try { String text; if (lowerName == null) { text = nsMappings.getPrefix(upperName.getNamespaceURI()) + ":"; } else { text = nsMappings.translateName(lowerName); } return new Term(FieldNames.LABEL, text); } catch (RepositoryException e) { throw Util.createIOException(e); } } /** * @return the upper term. Must only be used for IndexFormatVersion < 3. * @throws IOException if a name cannot be translated. */ private Term getUpperTerm() throws IOException { try { String text; if (upperName == null) { text = nsMappings.getPrefix(lowerName.getNamespaceURI()) + ":\uFFFF"; } else { text = nsMappings.translateName(upperName); } return new Term(FieldNames.LABEL, text); } catch (RepositoryException e) { throw Util.createIOException(e); } } }