--- /dev/null
+package org.apache.lucene.queryParser.ext;
+
+/**
+ * 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.
+ */
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.queryParser.ext.Extensions.Pair;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.Version;
+
+/**
+ * The {@link ExtendableQueryParser} enables arbitrary query parser extension
+ * based on a customizable field naming scheme. The lucene query syntax allows
+ * implicit and explicit field definitions as query prefix followed by a colon
+ * (':') character. The {@link ExtendableQueryParser} allows to encode extension
+ * keys into the field symbol associated with a registered instance of
+ * {@link ParserExtension}. A customizable separation character separates the
+ * extension key from the actual field symbol. The {@link ExtendableQueryParser}
+ * splits (@see {@link Extensions#splitExtensionField(String, String)}) the
+ * extension key from the field symbol and tries to resolve the associated
+ * {@link ParserExtension}. If the parser can't resolve the key or the field
+ * token does not contain a separation character, {@link ExtendableQueryParser}
+ * yields the same behavior as its super class {@link QueryParser}. Otherwise,
+ * if the key is associated with a {@link ParserExtension} instance, the parser
+ * builds an instance of {@link ExtensionQuery} to be processed by
+ * {@link ParserExtension#parse(ExtensionQuery)}.If a extension field does not
+ * contain a field part the default field for the query will be used.
+ * <p>
+ * To guarantee that an extension field is processed with its associated
+ * extension, the extension query part must escape any special characters like
+ * '*' or '['. If the extension query contains any whitespace characters, the
+ * extension query part must be enclosed in quotes.
+ * Example ('_' used as separation character):
+ * <pre>
+ * title_customExt:"Apache Lucene\?" OR content_customExt:prefix\*
+ * </pre>
+ *
+ * Search on the default field:
+ * <pre>
+ * _customExt:"Apache Lucene\?" OR _customExt:prefix\*
+ * </pre>
+ * </p>
+ * <p>
+ * The {@link ExtendableQueryParser} itself does not implement the logic how
+ * field and extension key are separated or ordered. All logic regarding the
+ * extension key and field symbol parsing is located in {@link Extensions}.
+ * Customized extension schemes should be implemented by sub-classing
+ * {@link Extensions}.
+ * </p>
+ * <p>
+ * For details about the default encoding scheme see {@link Extensions}.
+ * </p>
+ *
+ * @see Extensions
+ * @see ParserExtension
+ * @see ExtensionQuery
+ */
+public class ExtendableQueryParser extends QueryParser {
+
+ private final String defaultField;
+ private final Extensions extensions;
+
+ /**
+ * Default empty extensions instance
+ */
+ private static final Extensions DEFAULT_EXTENSION = new Extensions();
+
+ /**
+ * Creates a new {@link ExtendableQueryParser} instance
+ *
+ * @param matchVersion
+ * the lucene version to use.
+ * @param f
+ * the default query field
+ * @param a
+ * the analyzer used to find terms in a query string
+ */
+ public ExtendableQueryParser(final Version matchVersion, final String f,
+ final Analyzer a) {
+ this(matchVersion, f, a, DEFAULT_EXTENSION);
+
+ }
+
+ /**
+ * Creates a new {@link ExtendableQueryParser} instance
+ *
+ * @param matchVersion
+ * the lucene version to use.
+ * @param f
+ * the default query field
+ * @param a
+ * the analyzer used to find terms in a query string
+ * @param ext
+ * the query parser extensions
+ */
+ public ExtendableQueryParser(final Version matchVersion, final String f,
+ final Analyzer a, final Extensions ext) {
+ super(matchVersion, f, a);
+ this.defaultField = f;
+ this.extensions = ext;
+ }
+
+ /**
+ * Returns the extension field delimiter character.
+ *
+ * @return the extension field delimiter character.
+ */
+ public char getExtensionFieldDelimiter() {
+ return extensions.getExtensionFieldDelimiter();
+ }
+
+ @Override
+ protected Query getFieldQuery(final String field, final String queryText, boolean quoted)
+ throws ParseException {
+ final Pair<String,String> splitExtensionField = this.extensions
+ .splitExtensionField(defaultField, field);
+ final ParserExtension extension = this.extensions
+ .getExtension(splitExtensionField.cud);
+ if (extension != null) {
+ return extension.parse(new ExtensionQuery(this, splitExtensionField.cur,
+ queryText));
+ }
+ return super.getFieldQuery(field, queryText, quoted);
+ }
+
+}