BasicQuery.java :  » XML » wo-flint » org » weborganic » flint » query » Java Open Source

Java Open Source » XML » wo flint 
wo flint » org » weborganic » flint » query » BasicQuery.java
package org.weborganic.flint.query;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.BooleanClause.Occur;
import org.weborganic.flint.util.Beta;

import com.topologi.diffx.xml.XMLWriter;

/**
 * An unmodifiable query based on a base query and a set of additional search parameters.
 * 
 * @param <T> the type of the base query.
 * 
 * @author Christophe Lauret
 * @version 16 August 2010
 */
@Beta
public class BasicQuery<T extends SearchParameter> implements FlintQuery, SearchQuery {

  /**
   * The query to use as a base.
   */
  private final T _base;

  /**
   * A list of query parameters which can be used on top of the base query. 
   */
  private final List<SearchParameter> _parameters;

  /**
   * The Lucene query corresponding to this object. 
   */
  private volatile Query _query = null;

  /**
   * How the results should be sorted.
   */
  private Sort _sort = Sort.RELEVANCE;

  /**
   * Constructs a new query.
   * 
   * <p>For safety and to ensure that the parameters remain unmodifiable, the specified list should
   * be unmodifiable. Use the factory method to ensure create create an unmodifiable list.
   * 
   * @param base       The query to use as a base.
   * @param parameters A list of query parameters which can be used on top of the base query.
   * 
   * @throws NullPointerException if either argument is <code>null</code>.
   */
  BasicQuery(T base, List<SearchParameter> parameters) throws NullPointerException {
    if (base == null) throw new NullPointerException("base");
    if (parameters == null) throw new NullPointerException("parameters");
    this._base = base;
    this._parameters = parameters;
  }

  /**
   * Returns the query used as as base.
   * 
   * @return the query used as as base.
   */
  public final T base() {
    return this._base;
  }

  /**
   * Returns the list of additional search parameters associated with this query.
   * 
   * @return the list of additional search parameters associated with this query.
   */
  public final List<SearchParameter> parameters() {
    return this._parameters;
  }

  /**
   * Defines the sort order.
   * 
   * @param sort The sort order. 
   */
  public void setSort(Sort sort) {
    this._sort = sort; 
  }

  /**
   * Returns the sort order for the results.
   * 
   * @return the sort order for the results (defaults to relevance).
   */
  public final Sort getSort() {
    return this._sort != null? this._sort : Sort.RELEVANCE;
  }

  /**
   * This query is empty if the base query is empty.
   * 
   * @return <code>true</code> if the base query is empty;
   *         <code>false</code> otherwise.
   */
  public final boolean isEmpty() {
    return this._base == null || this._base.isEmpty();
  }

  /**
   * Returns the Lucene query corresponding to this class.
   * 
   * @return the Lucene query corresponding to this class.
   */
  public Query toQuery() {
    if (this._query == null) {
      this._query = toQuery(this._base, this._parameters);
    }
    return this._query;
  }

  /**
   * Generates the XML for this query.
   * 
   * <p>As:
   * <pre>{@code
   * <basic-query empty="[true|false]" query="[lucene query]">
   *   <base>
   *     <!-- The base query using the toXML() method -->
   *   </base>
   *   <parameters>
   *     <!-- Each parameters in order using the toXML() method -->
   *   </parameters>
   * </basic-query>
   * }</pre>
   * 
   * {@inheritDoc}
   */
  public void toXML(XMLWriter xml) throws IOException {
    xml.openElement("basic-query", true);
    xml.attribute("empty", Boolean.toString(isEmpty()));
    if (!isEmpty()) {
      xml.attribute("query", this._query.toString());
      // Base query
      xml.openElement("base", true);
      this._base.toXML(xml);
      xml.closeElement();
      // Parameters
      xml.openElement("parameters", !this.parameters().isEmpty());
      for (SearchParameter p : this._parameters) {
        p.toXML(xml);
      }
      xml.closeElement();
      xml.openElement("sort", this._sort != Sort.RELEVANCE);
      if (this._sort == Sort.RELEVANCE) {
        xml.attribute("by", "relevance");
      } else {
        xml.attribute("by", "fields");
        for (SortField sf : this._sort.getSort()) {
          xml.openElement("sortfield");
          xml.attribute("field", sf.getField());
          xml.attribute("type", sf.getType());
          xml.attribute("reverse", Boolean.toString(sf.getReverse()));
          xml.closeElement();
        }
      }
      xml.closeElement();
    }
    xml.closeElement();
  }

  /**
   * Returns a string representation of this query for human consumption. 
   * 
   * @return a string representation of this query.
   */
  public String toString() {
    StringBuilder s = new StringBuilder();
    s.append(this._base.toString());
    if (this.parameters().size() > 0) {
      s.append(" with (");
      for (Iterator<SearchParameter> i = this._parameters.iterator(); i.hasNext();) {
        s.append(i.next().toString());
        if (i.hasNext()) s.append(" and ");
      }
      s.append(')');
    }
    return s.toString();
  };

  // private helpers 
  // ----------------------------------------------------------------------------------------------

  /**
   * Builds the query for the specified arguments using the base query and 
   * 
   * @param base       the base query
   * @param parameters the parameters
   * 
   * @return the corresponding Lucene Query
   */
  private static Query toQuery(SearchParameter base, List<SearchParameter> parameters) {
    // No parameters, just use the base.
    if (parameters.isEmpty()) return base.toQuery();
    // Make an AND of all parameters
    BooleanQuery query = new BooleanQuery();
    query.add(base.toQuery(), Occur.MUST);
    for (SearchParameter p : parameters) {
      query.add(p.toQuery(), Occur.MUST);
    }
    return query;
  }

  // factory methods 
  // ----------------------------------------------------------------------------------------------

  /**
   * Builds a basic query using only the specified base query. 
   * 
   * @param <X> The type of base query
   * 
   * @param base  the base query
   * 
   * @return the corresponding Lucene Query
   */
  public static <X extends SearchParameter> BasicQuery<X> newBasicQuery(X base) {
    List<SearchParameter> none = Collections.emptyList();
    return new BasicQuery<X>(base, none);
  }

  /**
   * Builds a basic query using only the specified base query. 
   * 
   * @param <X> The type of base query
   * 
   * @param base       the base query
   * @param parameters the parameters
   * 
   * @return the corresponding Lucene Query
   */
  public static <X extends SearchParameter> BasicQuery<X> newBasicQuery(X base, List<SearchParameter> parameters) {
    List<SearchParameter> unmodifiable = Collections.unmodifiableList(new ArrayList<SearchParameter>(parameters));
    return new BasicQuery<X>(base, unmodifiable);
  }

  /**
   * @deprecated Will be removed in future releases
   * @return always <code>null</code>
   */
  @Deprecated public String getField() {
    // TODO Auto-generated method stub
    return null;
  }

  /**
   * @deprecated Will be removed in future releases
   * @return the predicate from the {@link Query} object
   */
  @Deprecated public String getPredicate() {
    return this._query.toString();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.