/*
* 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.exoplatform.services.jcr.impl.core.query.lucene;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.ToStringUtils;
import org.exoplatform.services.jcr.datamodel.IllegalNameException;
import org.exoplatform.services.jcr.datamodel.InternalQName;
import java.io.IOException;
import javax.jcr.RepositoryException;
/**
* <code>NameRangeQuery</code>...
*/
public class NameRangeQuery extends Query
{
/**
* The serial version UID
*/
private static final long serialVersionUID = 3063269883302995392L;
/**
* The lower name. May be <code>null</code> if <code>upperName</code> is not
* <code>null</code>.
*/
private final InternalQName lowerName;
/**
* The upper name. May be <code>null</code> if <code>lowerName</code> is not
* <code>null</code>.
*/
private final InternalQName 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;
/**
* 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(InternalQName lowerName, InternalQName upperName, boolean inclusive,
IndexFormatVersion version, NamespaceMappings nsMappings)
{
if (lowerName == null && upperName == null)
{
throw new IllegalArgumentException("At least one term must be non-null");
}
if (lowerName != null && upperName != null && !lowerName.getNamespace().equals(upperName.getNamespace()))
{
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;
}
/**
* {@inheritDoc}
*/
public Query rewrite(IndexReader reader) throws IOException
{
if (version.getVersion() >= IndexFormatVersion.V3.getVersion())
{
RangeQuery localNames = new RangeQuery(getLowerLocalNameTerm(), getUpperLocalNameTerm(), inclusive);
BooleanQuery query = new BooleanQuery();
query.add(new JcrTermQuery(new Term(FieldNames.NAMESPACE_URI, getNamespaceURI())),
BooleanClause.Occur.MUST);
query.add(localNames, BooleanClause.Occur.MUST);
return query.rewrite(reader);
}
else
{
return new RangeQuery(getLowerTerm(), getUpperTerm(), inclusive).rewrite(reader);
}
}
/**
* {@inheritDoc}
*/
public String toString(String field)
{
StringBuilder buffer = new StringBuilder();
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.getNamespace() : upperName.getNamespace();
}
/**
* @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.getName());
}
}
/**
* @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.getName());
}
}
/**
* @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.getNamespacePrefixByURI(upperName.getNamespace()) + ":";
}
else
{
text = nsMappings.translateName(lowerName);
}
return new Term(FieldNames.LABEL, text);
}
catch (RepositoryException e)
{
throw Util.createIOException(e);
}
catch (IllegalNameException 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.getNamespacePrefixByURI(lowerName.getNamespace()) + ":\uFFFF";
}
else
{
text = nsMappings.translateName(upperName);
}
return new Term(FieldNames.LABEL, text);
}
catch (RepositoryException e)
{
throw Util.createIOException(e);
}
catch (IllegalNameException e)
{
throw Util.createIOException(e);
}
}
}