com.jaeksoft.searchlib.request.AbstractSearchRequest.java Source code

Java tutorial

Introduction

Here is the source code for com.jaeksoft.searchlib.request.AbstractSearchRequest.java

Source

/**   
 * License Agreement for OpenSearchServer
 *
 * Copyright (C) 2008-2014 Emmanuel Keller / Jaeksoft
 * 
 * http://www.open-search-server.com
 * 
 * This file is part of OpenSearchServer.
 *
 * OpenSearchServer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 * OpenSearchServer 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenSearchServer. 
 *  If not, see <http://www.gnu.org/licenses/>.
 **/

package com.jaeksoft.searchlib.request;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.xpath.XPathExpressionException;

import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.Version;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.jaeksoft.searchlib.SearchLibException;
import com.jaeksoft.searchlib.analysis.LanguageEnum;
import com.jaeksoft.searchlib.analysis.PerFieldAnalyzer;
import com.jaeksoft.searchlib.authentication.AuthManager;
import com.jaeksoft.searchlib.collapse.CollapseFunctionField;
import com.jaeksoft.searchlib.collapse.CollapseParameters;
import com.jaeksoft.searchlib.collapse.CollapseParameters.Mode;
import com.jaeksoft.searchlib.config.Config;
import com.jaeksoft.searchlib.facet.FacetField;
import com.jaeksoft.searchlib.facet.FacetFieldList;
import com.jaeksoft.searchlib.filter.FilterAbstract;
import com.jaeksoft.searchlib.filter.FilterList;
import com.jaeksoft.searchlib.filter.GeoFilter;
import com.jaeksoft.searchlib.filter.QueryFilter;
import com.jaeksoft.searchlib.filter.RelativeDateFilter;
import com.jaeksoft.searchlib.filter.TermFilter;
import com.jaeksoft.searchlib.function.expression.SyntaxError;
import com.jaeksoft.searchlib.geo.GeoParameters;
import com.jaeksoft.searchlib.geo.GeoParameters.DistanceReturn;
import com.jaeksoft.searchlib.index.ReaderAbstract;
import com.jaeksoft.searchlib.index.ReaderInterface;
import com.jaeksoft.searchlib.join.JoinList;
import com.jaeksoft.searchlib.query.ParseException;
import com.jaeksoft.searchlib.result.AbstractResult;
import com.jaeksoft.searchlib.result.ResultSearchSingle;
import com.jaeksoft.searchlib.schema.Schema;
import com.jaeksoft.searchlib.schema.SchemaField;
import com.jaeksoft.searchlib.schema.SchemaFieldList;
import com.jaeksoft.searchlib.scoring.AdvancedScore;
import com.jaeksoft.searchlib.scoring.AdvancedScoreItem;
import com.jaeksoft.searchlib.snippet.SnippetField;
import com.jaeksoft.searchlib.snippet.SnippetFieldList;
import com.jaeksoft.searchlib.sort.SortField;
import com.jaeksoft.searchlib.sort.SortFieldList;
import com.jaeksoft.searchlib.util.DomUtils;
import com.jaeksoft.searchlib.util.StringUtils;
import com.jaeksoft.searchlib.util.XPathParser;
import com.jaeksoft.searchlib.util.XmlWriter;
import com.jaeksoft.searchlib.web.ServletTransaction;
import com.jaeksoft.searchlib.webservice.query.search.SearchQueryAbstract.OperatorEnum;

public abstract class AbstractSearchRequest extends AbstractRequest
        implements RequestInterfaces.ReturnedFieldInterface, RequestInterfaces.FilterListInterface {

    private transient Query boostedComplexQuery;
    private transient Query snippetSimpleQuery;

    protected transient PerFieldAnalyzer analyzer;

    protected transient QueryParser queryParser;

    private FilterList filterList;
    private JoinList joinList;
    private boolean allowLeadingWildcard;
    protected int phraseSlop;
    protected OperatorEnum defaultOperator;
    private SnippetFieldList snippetFieldList;
    private ReturnFieldList returnFieldList;
    private FacetFieldList facetFieldList;
    private List<BoostQuery> boostingQueries;
    private SortFieldList sortFieldList;
    private String collapseField;
    private int collapseMax;
    private CollapseParameters.Mode collapseMode;
    private CollapseParameters.Type collapseType;
    private Set<CollapseFunctionField> collapseFunctionFields;
    private int start;
    private int rows;
    private LanguageEnum lang;
    private String queryString;
    private AdvancedScore advancedScore;
    private String queryParsed;
    private boolean withSortValues;
    protected boolean emptyReturnsAll;
    private final GeoParameters geoParameters = new GeoParameters();

    protected AbstractSearchRequest(Config config, RequestTypeEnum type) {
        super(config, type);
    }

    @Override
    protected void setDefaultValues() {
        super.setDefaultValues();
        this.queryParser = null;
        this.queryParsed = null;
        this.filterList = new FilterList(this.config);
        this.joinList = new JoinList(this.config);
        this.allowLeadingWildcard = false;
        this.phraseSlop = 10;
        this.defaultOperator = OperatorEnum.OR;
        this.snippetFieldList = new SnippetFieldList();
        this.returnFieldList = new ReturnFieldList();
        this.sortFieldList = new SortFieldList();
        this.facetFieldList = new FacetFieldList();
        this.boostingQueries = new ArrayList<BoostQuery>(0);

        this.collapseField = null;
        this.collapseMax = 2;
        this.collapseMode = CollapseParameters.Mode.OFF;
        this.collapseType = CollapseParameters.Type.OPTIMIZED;
        this.collapseFunctionFields = null;

        this.start = 0;
        this.rows = 10;
        this.lang = null;
        this.snippetSimpleQuery = null;
        this.boostedComplexQuery = null;
        this.analyzer = null;
        this.queryString = null;
        this.advancedScore = null;
        this.withSortValues = false;
        this.queryParsed = null;
        this.emptyReturnsAll = true;
    }

    @Override
    public void copyFrom(AbstractRequest request) {
        super.copyFrom(request);
        AbstractSearchRequest searchRequest = (AbstractSearchRequest) request;
        this.filterList = new FilterList(searchRequest.filterList);
        this.joinList = new JoinList(searchRequest.joinList);
        this.allowLeadingWildcard = searchRequest.allowLeadingWildcard;
        this.phraseSlop = searchRequest.phraseSlop;
        this.defaultOperator = searchRequest.defaultOperator;
        this.snippetFieldList = new SnippetFieldList(searchRequest.snippetFieldList);
        this.returnFieldList = new ReturnFieldList(searchRequest.returnFieldList);
        this.sortFieldList = new SortFieldList(searchRequest.sortFieldList);
        this.facetFieldList = new FacetFieldList(searchRequest.facetFieldList);
        this.boostingQueries = new ArrayList<BoostQuery>(searchRequest.boostingQueries.size());
        for (BoostQuery boostQuery : searchRequest.boostingQueries)
            this.boostingQueries.add(new BoostQuery(boostQuery));

        this.collapseField = searchRequest.collapseField;
        this.collapseMax = searchRequest.collapseMax;
        this.collapseMode = searchRequest.collapseMode;
        this.collapseType = searchRequest.collapseType;
        this.collapseFunctionFields = CollapseFunctionField.duplicate(searchRequest.collapseFunctionFields);
        this.geoParameters.set(searchRequest.geoParameters);

        this.withSortValues = searchRequest.withSortValues;
        this.start = searchRequest.start;
        this.rows = searchRequest.rows;
        this.lang = searchRequest.lang;
        this.snippetSimpleQuery = null;
        this.boostedComplexQuery = null;
        this.analyzer = null;
        this.queryString = searchRequest.queryString;
        this.advancedScore = AdvancedScore.copy(searchRequest.advancedScore);
        this.queryParsed = null;
        this.emptyReturnsAll = searchRequest.emptyReturnsAll;
    }

    @Override
    protected void resetNoLock() {
        this.queryParser = null;
        this.queryParsed = null;
        this.snippetSimpleQuery = null;
        this.boostedComplexQuery = null;
        this.analyzer = null;
        if (snippetFieldList != null)
            for (SnippetField snippetField : snippetFieldList)
                snippetField.reset();
    }

    private PerFieldAnalyzer checkAnalyzer() throws SearchLibException {
        if (analyzer == null)
            analyzer = config.getSchema().getQueryPerFieldAnalyzer(lang);
        return analyzer;
    }

    public PerFieldAnalyzer getAnalyzer() throws SearchLibException {
        rwl.r.lock();
        try {
            if (analyzer != null)
                return analyzer;
        } finally {
            rwl.r.unlock();
        }
        rwl.w.lock();
        try {
            checkAnalyzer();
            return analyzer;
        } finally {
            rwl.w.unlock();
        }
    }

    public int getPhraseSlop() {
        rwl.r.lock();
        try {
            return phraseSlop;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setPhraseSlop(int value) {
        rwl.w.lock();
        try {
            phraseSlop = value;
        } finally {
            rwl.w.unlock();
        }
    }

    public boolean getEmptyReturnsAll() {
        rwl.r.lock();
        try {
            return emptyReturnsAll;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setEmptyReturnsAll(boolean value) {
        rwl.w.lock();
        try {
            emptyReturnsAll = value;
        } finally {
            rwl.w.unlock();
        }
    }

    protected abstract Query newSnippetQuery(String queryString)
            throws IOException, ParseException, SyntaxError, SearchLibException;

    public Query getSnippetQuery() throws IOException, ParseException, SyntaxError, SearchLibException {
        rwl.r.lock();
        try {
            if (snippetSimpleQuery != null)
                return snippetSimpleQuery;
        } finally {
            rwl.r.unlock();
        }
        rwl.w.lock();
        try {
            if (snippetSimpleQuery != null)
                return snippetSimpleQuery;
            getQueryParser();
            checkAnalyzer();
            snippetSimpleQuery = newSnippetQuery(queryString);
            return snippetSimpleQuery;
        } finally {
            rwl.w.unlock();
        }
    }

    protected abstract Query newComplexQuery(String queryString)
            throws ParseException, SyntaxError, SearchLibException, IOException;

    @Override
    public Query getQuery() throws ParseException, SyntaxError, SearchLibException, IOException {
        rwl.r.lock();
        try {
            if (boostedComplexQuery != null)
                return boostedComplexQuery;
        } finally {
            rwl.r.unlock();
        }
        rwl.w.lock();
        try {
            if (boostedComplexQuery != null)
                return boostedComplexQuery;
            getQueryParser();
            checkAnalyzer();
            boostedComplexQuery = newComplexQuery(queryString);
            if (boostedComplexQuery == null)
                boostedComplexQuery = new BooleanQuery();
            for (BoostQuery boostQuery : boostingQueries)
                boostedComplexQuery = boostQuery.getNewQuery(boostedComplexQuery, queryParser);
            queryParsed = boostedComplexQuery.toString();
            return boostedComplexQuery;
        } finally {
            rwl.w.unlock();
        }
    }

    private QueryParser getQueryParser() throws ParseException, SearchLibException {
        if (queryParser != null)
            return queryParser;
        Schema schema = getConfig().getSchema();
        SchemaField field = schema.getFieldList().getDefaultField();
        if (field == null)
            throw new SearchLibException("Please select a default field in the schema");
        queryParser = new QueryParser(Version.LUCENE_36, field.getName(), checkAnalyzer());
        queryParser.setAllowLeadingWildcard(allowLeadingWildcard);
        queryParser.setPhraseSlop(phraseSlop);
        queryParser.setDefaultOperator(defaultOperator.lucop);
        queryParser.setLowercaseExpandedTerms(false);
        return queryParser;
    }

    public void setBoostedComplexQuery(Query query) {
        rwl.w.lock();
        try {
            boostedComplexQuery = query;
        } finally {
            rwl.w.unlock();
        }
    }

    public String getQueryString() {
        rwl.r.lock();
        try {
            return queryString;
        } finally {
            rwl.r.unlock();
        }
    }

    final public String getQueryParsed() throws ParseException, SyntaxError, SearchLibException, IOException {
        rwl.r.lock();
        try {
            getQuery();
            return queryParsed;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setQueryString(String q) {
        rwl.w.lock();
        try {
            queryString = q;
            boostedComplexQuery = null;
            snippetSimpleQuery = null;
        } finally {
            rwl.w.unlock();
        }
    }

    public AdvancedScore getAdvancedScore() {
        rwl.r.lock();
        try {
            return advancedScore;
        } finally {
            rwl.r.unlock();
        }
    }

    final public void addAdvancedScore(final AdvancedScoreItem scoreItem) {
        if (scoreItem == null)
            return;
        rwl.w.lock();
        try {
            if (advancedScore == null)
                advancedScore = new AdvancedScore();
            advancedScore.addItem(scoreItem);
        } finally {
            rwl.w.unlock();
        }
    }

    final public void removeAdvancedScore(final AdvancedScoreItem scoreItem) {
        if (scoreItem == null)
            return;
        rwl.w.lock();
        try {
            if (advancedScore == null)
                return;
            advancedScore.removeItem(scoreItem);
        } finally {
            rwl.w.unlock();
        }
    }

    public JoinList getJoinList() {
        rwl.r.lock();
        try {
            return this.joinList;
        } finally {
            rwl.r.unlock();
        }
    }

    @Override
    public FilterList getFilterList() {
        rwl.r.lock();
        try {
            return this.filterList;
        } finally {
            rwl.r.unlock();
        }
    }

    @Override
    public void addFilter(String req, boolean negative) throws ParseException {
        rwl.w.lock();
        try {
            this.filterList.add(new QueryFilter(req, negative, FilterAbstract.Source.REQUEST, null));
        } finally {
            rwl.w.unlock();
        }
    }

    public void addTermFilter(String field, String term, boolean negative) {
        rwl.w.lock();
        try {
            this.filterList.add(new TermFilter(field, term, negative, FilterAbstract.Source.REQUEST, null));
        } finally {
            rwl.w.unlock();
        }

    }

    final public void removeFilterSource(FilterAbstract.Source source) {
        rwl.w.lock();
        try {
            List<FilterAbstract<?>> toRemoveList = new ArrayList<FilterAbstract<?>>(0);
            for (FilterAbstract<?> filterAbstract : filterList)
                if (filterAbstract.getSource() == source)
                    toRemoveList.add(filterAbstract);
            for (FilterAbstract<?> filterAbstract : toRemoveList)
                filterList.remove(filterAbstract);
        } finally {
            rwl.w.unlock();
        }
    }

    public SnippetFieldList getSnippetFieldList() {
        rwl.r.lock();
        try {
            return this.snippetFieldList;
        } finally {
            rwl.r.unlock();
        }
    }

    @Override
    public ReturnFieldList getReturnFieldList() {
        rwl.r.lock();
        try {
            return this.returnFieldList;
        } finally {
            rwl.r.unlock();
        }
    }

    private SchemaField getCheckSchemaField(SchemaFieldList schemaFieldList, String fieldName)
            throws SearchLibException {
        SchemaField schemaField = schemaFieldList.get(fieldName);
        if (schemaField == null)
            throw new SearchLibException("Returned field: The field: " + fieldName + " does not exist");
        return schemaField;
    }

    private void addReturnFieldNoLock(SchemaFieldList schemaFieldList, String fieldName) throws SearchLibException {
        returnFieldList.put(new ReturnField(getCheckSchemaField(schemaFieldList, fieldName).getName()));
    }

    @Override
    public void addReturnField(String fieldName) throws SearchLibException {
        rwl.w.lock();
        try {
            addReturnFieldNoLock(config.getSchema().getFieldList(), fieldName);
        } finally {
            rwl.w.unlock();
        }
    }

    public SortFieldList getSortFieldList() {
        rwl.r.lock();
        try {
            return this.sortFieldList;
        } finally {
            rwl.r.unlock();
        }
    }

    public boolean isScoreRequired() {
        rwl.r.lock();
        try {
            if (sortFieldList.isScore())
                return true;
            if (advancedScore != null)
                if (advancedScore.getScoreWeight() > 0)
                    return true;
            return false;
        } finally {
            rwl.r.unlock();
        }
    }

    public boolean isDistanceRequired() {
        rwl.r.lock();
        try {
            if (geoParameters != null)
                if (geoParameters.getDistanceReturn() != DistanceReturn.NO_DISTANCE)
                    return true;
            if (sortFieldList.isDistance())
                return true;
            if (filterList != null)
                if (filterList.isDistance())
                    return true;
            if (advancedScore != null)
                if (advancedScore.isDistance())
                    return true;
            return false;
        } finally {
            rwl.r.unlock();
        }
    }

    public boolean isJoin() {
        rwl.r.lock();
        try {
            if (joinList == null)
                return false;
            return joinList.size() > 0;
        } finally {
            rwl.r.unlock();
        }
    }

    public boolean isDocIdRequired() {
        rwl.r.lock();
        try {
            if (returnFieldList.size() > 0)
                return true;
            if (snippetFieldList.size() > 0)
                return true;
            if (isJoin())
                return true;
            if (isCollapsing())
                return true;
            if (isFacet())
                return true;
            return true;
        } finally {
            rwl.r.unlock();
        }
    }

    public void addSort(final int joinNumber, final String fieldName, final boolean desc, final boolean nullFirst) {
        rwl.w.lock();
        try {
            sortFieldList.put(new SortField(joinNumber, fieldName, desc, nullFirst));
        } finally {
            rwl.w.unlock();
        }
    }

    public FacetFieldList getFacetFieldList() {
        rwl.r.lock();
        try {
            return this.facetFieldList;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setCollapseField(String collapseField) {
        rwl.w.lock();
        try {
            this.collapseField = collapseField;
        } finally {
            rwl.w.unlock();
        }
    }

    public void setCollapseMax(int collapseMax) {
        rwl.w.lock();
        try {
            this.collapseMax = collapseMax;
        } finally {
            rwl.w.unlock();
        }
    }

    public String getCollapseField() {
        rwl.r.lock();
        try {
            return this.collapseField;
        } finally {
            rwl.r.unlock();
        }
    }

    public int getCollapseMax() {
        rwl.r.lock();
        try {
            return this.collapseMax;
        } finally {
            rwl.r.unlock();
        }
    }

    public Collection<CollapseFunctionField> getCollapseFunctionFields() {
        rwl.r.lock();
        try {
            return this.collapseFunctionFields;
        } finally {
            rwl.r.unlock();
        }
    }

    public void addCollapseFunctionField(CollapseFunctionField functionField) {
        if (functionField == null)
            return;
        rwl.w.lock();
        try {
            if (collapseFunctionFields == null)
                collapseFunctionFields = new HashSet<CollapseFunctionField>();
            collapseFunctionFields.add(new CollapseFunctionField(functionField));
        } finally {
            rwl.w.unlock();
        }
    }

    public void removeCollapseFunctionField(CollapseFunctionField functionField) {
        rwl.w.lock();
        try {
            collapseFunctionFields.remove(functionField);
            if (collapseFunctionFields.size() == 0)
                collapseFunctionFields = null;
        } finally {
            rwl.w.unlock();
        }
    }

    public int getStart() {
        rwl.r.lock();
        try {
            return this.start;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setStart(int start) {
        rwl.w.lock();
        try {
            this.start = start;
        } finally {
            rwl.w.unlock();
        }
    }

    public boolean isWithSortValues() {
        rwl.r.lock();
        try {
            return withSortValues;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setWithSortValues(boolean withSortValues) {
        rwl.w.lock();
        try {
            this.withSortValues = withSortValues;
        } finally {
            rwl.w.unlock();
        }
    }

    public int getRows() {
        rwl.r.lock();
        try {
            return this.rows;
        } finally {
            rwl.r.unlock();
        }
    }

    public LanguageEnum getLang() {
        rwl.r.lock();
        try {
            return this.lang;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setRows(int rows) {
        rwl.w.lock();
        try {
            this.rows = rows;
        } finally {
            rwl.w.unlock();
        }
    }

    public int getEnd() {
        rwl.r.lock();
        try {
            return this.start + this.rows;
        } finally {
            rwl.r.unlock();
        }
    }

    @Override
    public String toString() {
        rwl.r.lock();
        try {
            StringBuilder sb = new StringBuilder();
            sb.append("RequestName: ");
            sb.append(getRequestName());
            sb.append(" DefaultOperator: ");
            sb.append(defaultOperator);
            sb.append(" Start: ");
            sb.append(start);
            sb.append(" Rows: ");
            sb.append(rows);
            sb.append(" Query: ");
            sb.append(boostedComplexQuery);
            sb.append(" Facet: " + getFacetFieldList().toString());
            if (getCollapseMode() != CollapseParameters.Mode.OFF)
                sb.append(" Collapsing Mode: " + getCollapseMode() + " Type: " + getCollapseType() + " Field: "
                        + getCollapseField() + "(" + getCollapseMax() + ")");
            return sb.toString();
        } finally {
            rwl.r.unlock();
        }
    }

    public void setLang(LanguageEnum lang) {
        rwl.w.lock();
        try {
            if (this.lang == lang)
                return;
            this.lang = lang;
            analyzer = null;
        } finally {
            rwl.w.unlock();
        }
    }

    public String getDefaultOperator() {
        rwl.r.lock();
        try {
            return defaultOperator.toString();
        } finally {
            rwl.r.unlock();
        }
    }

    public void setDefaultOperator(String value) {
        setDefaultOperator(OperatorEnum.find(value));
    }

    public void setDefaultOperator(OperatorEnum operator) {
        rwl.w.lock();
        try {
            defaultOperator = operator;
        } finally {
            rwl.w.unlock();
        }
    }

    public void setCollapseMode(CollapseParameters.Mode mode) {
        rwl.w.lock();
        try {
            this.collapseMode = mode;
        } finally {
            rwl.w.unlock();
        }
    }

    public CollapseParameters.Mode getCollapseMode() {
        rwl.r.lock();
        try {
            return this.collapseMode;
        } finally {
            rwl.r.unlock();
        }
    }

    public void setCollapseType(CollapseParameters.Type type) {
        rwl.w.lock();
        try {
            this.collapseType = type;
        } finally {
            rwl.w.unlock();
        }
    }

    public CollapseParameters.Type getCollapseType() {
        rwl.r.lock();
        try {
            return this.collapseType;
        } finally {
            rwl.r.unlock();
        }
    }

    final public GeoParameters getGeoParameters() {
        return geoParameters;
    }

    public boolean isFacet() {
        rwl.r.lock();
        try {
            if (facetFieldList == null)
                return false;
            return facetFieldList.size() > 0;
        } finally {
            rwl.r.unlock();
        }
    }

    public boolean isCollapsing() {
        rwl.r.lock();
        try {
            if (collapseMode == Mode.OFF)
                return false;
            if (StringUtils.isEmpty(collapseField))
                return false;
            return true;
        } finally {
            rwl.r.unlock();
        }
    }

    public BoostQuery[] getBoostingQueries() {
        rwl.r.lock();
        try {
            BoostQuery[] queries = new BoostQuery[boostingQueries.size()];
            return boostingQueries.toArray(queries);
        } finally {
            rwl.r.unlock();
        }
    }

    public void setBoostingQuery(BoostQuery oldOne, BoostQuery newOne) {
        rwl.w.lock();
        try {
            if (oldOne != null) {
                if (newOne == null)
                    boostingQueries.remove(oldOne);
                else
                    oldOne.copyFrom(newOne);
            } else {
                if (newOne != null)
                    boostingQueries.add(newOne);
            }
        } finally {
            rwl.w.unlock();
        }
    }

    @Override
    protected void fromXmlConfigNoLock(Config config, XPathParser xpp, Node requestNode)
            throws XPathExpressionException, InstantiationException, IllegalAccessException, DOMException,
            ParseException, ClassNotFoundException {
        super.fromXmlConfigNoLock(config, xpp, requestNode);
        allowLeadingWildcard = "yes"
                .equalsIgnoreCase(XPathParser.getAttributeString(requestNode, "allowLeadingWildcard"));
        setPhraseSlop(XPathParser.getAttributeValue(requestNode, "phraseSlop"));
        setDefaultOperator(XPathParser.getAttributeString(requestNode, "defaultOperator"));
        setStart(XPathParser.getAttributeValue(requestNode, "start"));
        setRows(XPathParser.getAttributeValue(requestNode, "rows"));
        setLang(LanguageEnum.findByCode(XPathParser.getAttributeString(requestNode, "lang")));
        setEmptyReturnsAll(!"no".equalsIgnoreCase(DomUtils.getAttributeText(requestNode, "emtpyReturnsAll")));

        AdvancedScore advancedScore = AdvancedScore.fromXmlConfig(xpp, requestNode);
        if (advancedScore != null)
            this.advancedScore = advancedScore;

        setCollapseMode(
                CollapseParameters.Mode.valueOfLabel(XPathParser.getAttributeString(requestNode, "collapseMode")));
        setCollapseType(
                CollapseParameters.Type.valueOfLabel(XPathParser.getAttributeString(requestNode, "collapseType")));
        setCollapseField(XPathParser.getAttributeString(requestNode, "collapseField"));
        setCollapseMax(XPathParser.getAttributeValue(requestNode, "collapseMax"));

        NodeList nodes = xpp.getNodeList(requestNode, "collapseFunction");
        for (int i = 0; i < nodes.getLength(); i++)
            addCollapseFunctionField(CollapseFunctionField.fromXmlConfig(nodes.item(i)));

        Node geoNode = xpp.getNode(requestNode, "geoParameters");
        if (geoNode != null)
            geoParameters.set(geoNode);

        Node bqNode = xpp.getNode(requestNode, "boostingQueries");
        if (bqNode != null)
            BoostQuery.loadFromXml(xpp, bqNode, boostingQueries);

        SchemaFieldList fieldList = config.getSchema().getFieldList();
        returnFieldList.filterCopy(fieldList, xpp.getNodeString(requestNode, "returnFields"));
        nodes = xpp.getNodeList(requestNode, "returnFields/field");
        for (int i = 0; i < nodes.getLength(); i++) {
            ReturnField field = ReturnField.fromXmlConfig(nodes.item(i));
            if (field != null)
                returnFieldList.put(field);
        }

        nodes = xpp.getNodeList(requestNode, "snippet/field");
        for (int i = 0; i < nodes.getLength(); i++)
            SnippetField.copySnippetFields(nodes.item(i), fieldList, snippetFieldList);

        nodes = xpp.getNodeList(requestNode, "facetFields/facetField");
        for (int i = 0; i < nodes.getLength(); i++)
            FacetField.copyFacetFields(nodes.item(i), fieldList, facetFieldList);

        nodes = xpp.getNodeList(requestNode, "filters/*");
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            String nodeName = node.getNodeName();
            if ("filter".equals(nodeName))
                filterList.add(new QueryFilter(xpp, node));
            else if ("geofilter".equals(nodeName))
                filterList.add(new GeoFilter(xpp, node));
            else if ("relativeDateFilter".equals(nodeName))
                filterList.add(new RelativeDateFilter(xpp, node));
        }

        nodes = xpp.getNodeList(requestNode, "joins/join");
        for (int i = 0; i < nodes.getLength(); i++)
            joinList.add(xpp, nodes.item(i));

        nodes = xpp.getNodeList(requestNode, "sort/field");
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            String textNode = xpp.getNodeString(node, false);
            if (textNode != null && textNode.length() > 0)
                sortFieldList.put(new SortField(0, textNode, false, false));
            else
                sortFieldList.put(new SortField(node));
        }
    }

    protected abstract void writeSubXmlConfig(XmlWriter xmlWriter) throws SAXException;

    @Override
    public final void writeXmlConfig(XmlWriter xmlWriter) throws SAXException {
        rwl.r.lock();
        try {
            xmlWriter.startElement(XML_NODE_REQUEST, XML_ATTR_NAME, getRequestName(), XML_ATTR_TYPE,
                    getType().name(), "phraseSlop", Integer.toString(phraseSlop), "defaultOperator",
                    getDefaultOperator(), "start", Integer.toString(start), "rows", Integer.toString(rows), "lang",
                    lang != null ? lang.getCode() : null, "collapseMode", collapseMode.getLabel(), "collapseType",
                    collapseType.getLabel(), "collapseField", collapseField, "collapseMax",
                    Integer.toString(collapseMax), "emptyReturnsAll", emptyReturnsAll ? "yes" : "no");

            if (collapseFunctionFields != null)
                for (CollapseFunctionField functionField : collapseFunctionFields)
                    functionField.writeXmlConfig(xmlWriter, "collapseFunction");

            geoParameters.writeXmlConfig(xmlWriter, "geoParameters");

            if (boostingQueries.size() > 0) {
                xmlWriter.startElement("boostingQueries");
                for (BoostQuery boostQuery : boostingQueries)
                    boostQuery.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            writeSubXmlConfig(xmlWriter);

            if (returnFieldList.size() > 0) {
                xmlWriter.startElement("returnFields");
                returnFieldList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (snippetFieldList.size() > 0) {
                xmlWriter.startElement("snippet");
                snippetFieldList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (facetFieldList.size() > 0) {
                xmlWriter.startElement("facetFields");
                facetFieldList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (sortFieldList.size() > 0) {
                xmlWriter.startElement("sort");
                sortFieldList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (filterList.size() > 0) {
                xmlWriter.startElement("filters");
                filterList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (joinList.size() > 0) {
                xmlWriter.startElement("joins");
                joinList.writeXmlConfig(xmlWriter);
                xmlWriter.endElement();
            }

            if (advancedScore != null)
                advancedScore.writeXmlConfig(xmlWriter);

            xmlWriter.endElement();
        } finally {
            rwl.r.unlock();
        }
    }

    @Override
    public void setFromServletNoLock(final ServletTransaction transaction, final String prefix)
            throws SyntaxError, SearchLibException {
        super.setFromServletNoLock(transaction, prefix);

        String p;
        Integer i;

        SchemaFieldList schemaFieldList = config.getSchema().getFieldList();

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "query"))) != null)
            setQueryString(p);
        else if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "q"))) != null)
            setQueryString(p);

        if ((i = transaction.getParameterInteger(StringUtils.fastConcat(prefix, "start"))) != null)
            setStart(i);

        if ((i = transaction.getParameterInteger(StringUtils.fastConcat(prefix, "rows"))) != null)
            setRows(i);

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "lang"))) != null)
            setLang(LanguageEnum.findByCode(p));

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "collapse.mode"))) != null)
            setCollapseMode(CollapseParameters.Mode.valueOfLabel(p));

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "collapse.type"))) != null)
            setCollapseType(CollapseParameters.Type.valueOfLabel(p));

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "collapse.field"))) != null)
            setCollapseField(schemaFieldList.get(p).getName());

        if ((i = transaction.getParameterInteger(StringUtils.fastConcat(prefix, "collapse.max"))) != null)
            setCollapseMax(i);

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "log"))) != null)
            setLogReport(true);

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "operator"))) != null)
            setDefaultOperator(p);

        if (joinList != null)
            joinList.setFromServlet(transaction, prefix);

        if (filterList != null)
            filterList.setFromServlet(transaction, prefix);

        if (isLogReport()) {
            for (int j = 1; j <= 10; j++) {
                p = transaction.getParameterString(StringUtils.fastConcat(prefix, "log", j));
                if (p == null)
                    break;
                addCustomLog(p);
            }
        }

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "timer.minTime"))) != null)
            setTimerMinTime(Integer.parseInt(p));

        if ((p = transaction.getParameterString(StringUtils.fastConcat(prefix, "timer.maxDepth"))) != null)
            setTimerMaxDepth(Integer.parseInt(p));

        String[] values;

        filterList.addFromServlet(transaction, prefix);

        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "rf"))) != null) {
            for (String value : values)
                if (value != null) {
                    value = value.trim();
                    if (value.length() > 0)
                        addReturnFieldNoLock(schemaFieldList, value.trim());
                }
        }

        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "hl"))) != null) {
            for (String value : values)
                snippetFieldList.put(new SnippetField(getCheckSchemaField(schemaFieldList, value).getName()));
        }

        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "fl"))) != null) {
            for (String value : values)
                returnFieldList.put(new ReturnField(getCheckSchemaField(schemaFieldList, value).getName()));
        }

        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "sort"))) != null) {
            for (String value : values)
                sortFieldList.put(new SortField(value));
        }

        for (int j = 1; j <= 10; j++) {
            p = transaction.getParameterString(StringUtils.fastConcat(prefix, "sort", j));
            if (p == null)
                break;
            sortFieldList.put(new SortField(p));
        }

        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "facet"))) != null) {
            for (String value : values)
                facetFieldList.put(FacetField.buildFacetField(value, false, false));
        }
        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "facet.collapse"))) != null) {
            for (String value : values)
                facetFieldList.put(FacetField.buildFacetField(value, false, true));
        }
        if ((values = transaction.getParameterValues(StringUtils.fastConcat(prefix, "facet.multi"))) != null) {
            for (String value : values)
                facetFieldList.put(FacetField.buildFacetField(value, true, false));
        }
        if ((values = transaction
                .getParameterValues(StringUtils.fastConcat(prefix, "facet.multi.collapse"))) != null) {
            for (String value : values)
                facetFieldList.put(FacetField.buildFacetField(value, true, true));
        }

        geoParameters.setFromServlet(transaction, prefix);
    }

    @Override
    public AbstractResult<?> execute(ReaderInterface reader) throws SearchLibException {
        try {
            AuthManager authManager = config.getAuthManager();
            if (authManager.isEnabled() && !(this instanceof SearchFilterRequest))
                getFilterList().addAuthFilter();
            return new ResultSearchSingle((ReaderAbstract) reader, this);
        } catch (IOException e) {
            throw new SearchLibException(e);
        } catch (ParseException e) {
            throw new SearchLibException(e);
        } catch (SyntaxError e) {
            throw new SearchLibException(e);
        } catch (SearchLibException e) {
            throw new SearchLibException(e);
        } catch (InstantiationException e) {
            throw new SearchLibException(e);
        } catch (IllegalAccessException e) {
            throw new SearchLibException(e);
        } catch (ClassNotFoundException e) {
            throw new SearchLibException(e);
        }
    }

    @Override
    public abstract String getInfo();

}