Index: contrib/xml-query-parser/LuceneCoreQuery.dtd
===================================================================
--- contrib/xml-query-parser/LuceneCoreQuery.dtd	(revision 920896)
+++ contrib/xml-query-parser/LuceneCoreQuery.dtd	(working copy)
@@ -54,8 +54,8 @@
 
 <!-- @hidden Define core types of XML elements -->
 <!ENTITY % coreSpanQueries "SpanOr|SpanNear|SpanOrTerms|SpanFirst|SpanNot|SpanTerm|BoostingTermQuery" >
-<!ENTITY % coreQueries "BooleanQuery|UserQuery|FilteredQuery|TermQuery|TermsQuery|MatchAllDocsQuery|ConstantScoreQuery|BoostingTermQuery" >
-<!ENTITY % coreFilters "RangeFilter|CachedFilter" >
+<!ENTITY % coreQueries "BooleanQuery|UserQuery|FilteredQuery|TermQuery|TermsQuery|MatchAllDocsQuery|ConstantScoreQuery|BoostingTermQuery|NumericRangeQuery" >
+<!ENTITY % coreFilters "RangeFilter|NumericRangeFilter|CachedFilter" >
 
 <!-- @hidden Allow for extensions -->
 <!ENTITY % extendedSpanQueries1 " " >
@@ -283,7 +283,60 @@
 <!-- Controls if the upperTerm in the range is part of the allowed set of values -->
 <!ATTLIST RangeFilter includeUpper (true | false) "true">
 
+<!--
+	A Query that matches numeric values within a specified range.
+	@example 
+	        <em>Search for documents about people who are aged 20-25</em>
+	        %	          
+            <NumericRangeQuery fieldName="age" lowerTerm="20" upperTerm="25" />
+	         %
+	-->
+<!ELEMENT NumericRangeQuery EMPTY>
+<!-- fieldName must be defined here or is taken from the most immediate parent XML element that defines a "fieldName" attribute -->	
+<!ATTLIST NumericRangeQuery fieldName CDATA #IMPLIED>
+<!-- The lower-most term value for this field (must be <= upperTerm and a valid native java numeric type) -->
+<!ATTLIST NumericRangeQuery lowerTerm CDATA #REQUIRED>
+<!-- The upper-most term value for this field (must be >= lowerTerm and a valid native java numeric type) -->
+<!ATTLIST NumericRangeQuery upperTerm CDATA #REQUIRED>
+<!-- The numeric type of this field -->
+<!ATTLIST NumericRangeQuery type (int | long | float | double) "int">
+<!-- Controls if the lowerTerm in the range is part of the allowed set of values -->
+<!ATTLIST NumericRangeQuery includeLower (true | false) "true">
+<!-- Controls if the upperTerm in the range is part of the allowed set of values -->
+<!ATTLIST NumericRangeQuery includeUpper (true | false) "true">
+<!-- Lower step values mean more precisions and so more terms in index (and index gets larger). This value must be an integer -->
+<!ATTLIST NumericRangeQuery precisionStep "4">
 
+<!--
+	A Filter that only accepts numeric values within a specified range
+	@example 
+	        <em>Search for documents about people who are aged 20-25</em>
+	        %	          
+            <FilteredQuery>
+               <Query>
+                  <UserQuery>person</UserQuery>
+               </Query>	
+               <Filter>
+                     <NumericRangeFilter fieldName="age" lowerTerm="20" upperTerm="25"/>
+               </Filter>	
+            </FilteredQuery>
+	         %
+	-->
+<!ELEMENT NumericRangeFilter EMPTY>
+<!-- fieldName must be defined here or is taken from the most immediate parent XML element that defines a "fieldName" attribute -->	
+<!ATTLIST NumericRangeFilter fieldName CDATA #IMPLIED>
+<!-- The lower-most term value for this field (must be <= upperTerm and a valid native java numeric type) -->
+<!ATTLIST NumericRangeFilter lowerTerm CDATA #REQUIRED>
+<!-- The upper-most term value for this field (must be >= lowerTerm and a valid native java numeric type) -->
+<!ATTLIST NumericRangeFilter upperTerm CDATA #REQUIRED>
+<!-- The numeric type of this field -->
+<!ATTLIST NumericRangeFilter type (int | long | float | double) "int">
+<!-- Controls if the lowerTerm in the range is part of the allowed set of values -->
+<!ATTLIST NumericRangeFilter includeLower (true | false) "true">
+<!-- Controls if the upperTerm in the range is part of the allowed set of values -->
+<!ATTLIST NumericRangeFilter includeUpper (true | false) "true">
+<!-- Lower step values mean more precisions and so more terms in index (and index gets larger). This value must be an integer -->
+<!ATTLIST NumericRangeFilter precisionStep "4">
 
 <!-- A single term used in a SpanQuery. These clauses are the building blocks for more complex "span" queries which test word proximity
 	@example <em>Find documents using terms close to each other about mining and accidents</em>
Index: contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java
===================================================================
--- contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java	(revision 920896)
+++ contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/CoreParser.java	(working copy)
@@ -70,13 +70,14 @@
 		this.parser=parser;
 		filterFactory = new FilterBuilderFactory();
 		filterFactory.addBuilder("RangeFilter",new RangeFilterBuilder());
+		filterFactory.addBuilder("NumericRangeFilter",new NumericRangeFilterBuilder());
 		
-		
 		queryFactory = new QueryBuilderFactory();
 		queryFactory.addBuilder("TermQuery",new TermQueryBuilder());
 		queryFactory.addBuilder("TermsQuery",new TermsQueryBuilder(analyzer));
 		queryFactory.addBuilder("MatchAllDocsQuery",new MatchAllDocsQueryBuilder());
 		queryFactory.addBuilder("BooleanQuery",new BooleanQueryBuilder(queryFactory));
+		queryFactory.addBuilder("NumericRangeQuery",new NumericRangeQueryBuilder());
 		if(parser!=null)
 		{
 			queryFactory.addBuilder("UserQuery",new UserInputQueryBuilder(parser));
Index: contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java
===================================================================
--- contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java	(revision 0)
+++ contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeFilterBuilder.java	(revision 0)
@@ -0,0 +1,164 @@
+package org.apache.lucene.xmlparser.builders;
+
+/**
+ * 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 java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.NumericRangeFilter;
+import org.apache.lucene.xmlparser.DOMUtils;
+import org.apache.lucene.xmlparser.FilterBuilder;
+import org.apache.lucene.xmlparser.ParserException;
+import org.w3c.dom.Element;
+
+/**
+ * Creates a {@link NumericRangeFilter}. The table below specifies the required
+ * attributes and the defaults if optional attributes are omitted. For more
+ * detail on what each of the attributes actually do, consult the documentation
+ * for {@link NumericRangeFilter}:
+ * <table>
+ * <tr>
+ * <th>Attribute name</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * <th>Default</th>
+ * </tr>
+ * <tr>
+ * <td>fieldName</td>
+ * <td>String</td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>lowerTerm</td>
+ * <td>Specified by <tt>type</tt></td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>upperTerm</td>
+ * <td>Specified by <tt>type</tt></td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>type</td>
+ * <td>int, long, float, double</td>
+ * <td>No</td>
+ * <td>int</td>
+ * </tr>
+ * <tr>
+ * <td>includeLower</td>
+ * <td>true, false</td>
+ * <td>No</td>
+ * <td>true</td>
+ * </tr>
+ * <tr>
+ * <td>includeUpper</td>
+ * <td>true, false</td>
+ * <td>No</td>
+ * <td>true</td>
+ * </tr>
+ * <tr>
+ * <td>precisionStep</td>
+ * <td>Integer</td>
+ * <td>No</td>
+ * <td>4</td>
+ * </tr>
+ * </table>
+ * <p>
+ * If an error occurs parsing the supplied <tt>lowerTerm</tt> or
+ * <tt>upperTerm</tt> into the numeric type specified by <tt>type</tt>, then the
+ * error will be silently ignored and the resulting filter will not match any
+ * documents.
+ */
+public class NumericRangeFilterBuilder implements FilterBuilder {
+	private static final NoMatchFilter NO_MATCH_FILTER = new NoMatchFilter();
+
+	private boolean strictMode = false;
+
+	/**
+	 * Specifies how this {@link NumericRangeFilterBuilder} will handle errors.
+	 * <p>
+	 * If this is set to true, {@link #getFilter(Element)} will throw a
+	 * {@link ParserException} if it is unable to parse the lowerTerm or upperTerm
+	 * into the appropriate numeric type. If this is set to false, then this
+	 * exception will be silently ignored and the resulting filter will not match
+	 * any documents.
+	 * <p>
+	 * Defaults to false.
+	 * 
+	 * @param strictMode
+	 */
+	public void setStrictMode(boolean strictMode) {
+		this.strictMode = strictMode;
+	}
+
+	public Filter getFilter(Element e) throws ParserException {
+		String field = DOMUtils.getAttributeWithInheritanceOrFail(e, "fieldName");
+		String lowerTerm = DOMUtils.getAttributeOrFail(e, "lowerTerm");
+		String upperTerm = DOMUtils.getAttributeOrFail(e, "upperTerm");
+		boolean lowerInclusive = DOMUtils.getAttribute(e, "includeLower", true);
+		boolean upperInclusive = DOMUtils.getAttribute(e, "includeUpper", true);
+		int precisionStep = DOMUtils.getAttribute(e, "precisionStep", 4);
+
+		String type = DOMUtils.getAttribute(e, "type", "int");
+		try {
+			Filter filter;
+			if (type.equalsIgnoreCase("int")) {
+				filter = NumericRangeFilter.newIntRange(field, precisionStep, Integer
+						.valueOf(lowerTerm), Integer.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("long")) {
+				filter = NumericRangeFilter.newLongRange(field, precisionStep, Long
+						.valueOf(lowerTerm), Long.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("double")) {
+				filter = NumericRangeFilter.newDoubleRange(field, precisionStep, Double
+						.valueOf(lowerTerm), Double.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("float")) {
+				filter = NumericRangeFilter.newFloatRange(field, precisionStep, Float
+						.valueOf(lowerTerm), Float.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else {
+				throw new ParserException(
+						"type attribute must be one of: [long, int, double, float]");
+			}
+			return filter;
+		} catch (NumberFormatException nfe) {
+			if (strictMode) {
+				throw new ParserException(
+						"Could not parse lowerTerm or upperTerm into a number", nfe);
+			}
+			return NO_MATCH_FILTER;
+		}
+	}
+
+	static class NoMatchFilter extends Filter {
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		public DocIdSet getDocIdSet(IndexReader reader) throws IOException {
+			return null;
+		}
+
+	}
+}
Index: contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java
===================================================================
--- contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java	(revision 0)
+++ contrib/xml-query-parser/src/java/org/apache/lucene/xmlparser/builders/NumericRangeQueryBuilder.java	(revision 0)
@@ -0,0 +1,131 @@
+package org.apache.lucene.xmlparser.builders;
+
+/**
+ * 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 java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.NumericRangeQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.xmlparser.DOMUtils;
+import org.apache.lucene.xmlparser.ParserException;
+import org.apache.lucene.xmlparser.QueryBuilder;
+import org.w3c.dom.Element;
+
+/**
+ * Creates a {@link NumericRangeQuery}. The table below specifies the required
+ * attributes and the defaults if optional attributes are omitted. For more
+ * detail on what each of the attributes actually do, consult the documentation
+ * for {@link NumericRangeQuery}:
+ * <table>
+ * <tr>
+ * <th>Attribute name</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * <th>Default</th>
+ * </tr>
+ * <tr>
+ * <td>fieldName</td>
+ * <td>String</td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>lowerTerm</td>
+ * <td>Specified by <tt>type</tt></td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>upperTerm</td>
+ * <td>Specified by <tt>type</tt></td>
+ * <td>Yes</td>
+ * <td>N/A</td>
+ * </tr>
+ * <tr>
+ * <td>type</td>
+ * <td>int, long, float, double</td>
+ * <td>No</td>
+ * <td>int</td>
+ * </tr>
+ * <tr>
+ * <td>includeLower</td>
+ * <td>true, false</td>
+ * <td>No</td>
+ * <td>true</td>
+ * </tr>
+ * <tr>
+ * <td>includeUpper</td>
+ * <td>true, false</td>
+ * <td>No</td>
+ * <td>true</td>
+ * </tr>
+ * <tr>
+ * <td>precisionStep</td>
+ * <td>Integer</td>
+ * <td>No</td>
+ * <td>4</td>
+ * </tr>
+ * </table>
+ * <p>
+ * A {@link ParserException} will be thrown if an error occurs parsing the
+ * supplied <tt>lowerTerm</tt> or <tt>upperTerm</tt> into the numeric type
+ * specified by <tt>type</tt>.
+ */
+public class NumericRangeQueryBuilder implements QueryBuilder {
+
+	public Query getQuery(Element e) throws ParserException {
+		String field = DOMUtils.getAttributeWithInheritanceOrFail(e, "fieldName");
+		String lowerTerm = DOMUtils.getAttributeOrFail(e, "lowerTerm");
+		String upperTerm = DOMUtils.getAttributeOrFail(e, "upperTerm");
+		boolean lowerInclusive = DOMUtils.getAttribute(e, "includeLower", true);
+		boolean upperInclusive = DOMUtils.getAttribute(e, "includeUpper", true);
+		int precisionStep = DOMUtils.getAttribute(e, "precisionStep", 4);
+
+		String type = DOMUtils.getAttribute(e, "type", "int");
+		try {
+			Query filter;
+			if (type.equalsIgnoreCase("int")) {
+				filter = NumericRangeQuery.newIntRange(field, precisionStep, Integer
+						.valueOf(lowerTerm), Integer.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("long")) {
+				filter = NumericRangeQuery.newLongRange(field, precisionStep, Long
+						.valueOf(lowerTerm), Long.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("double")) {
+				filter = NumericRangeQuery.newDoubleRange(field, precisionStep, Double
+						.valueOf(lowerTerm), Double.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else if (type.equalsIgnoreCase("float")) {
+				filter = NumericRangeQuery.newFloatRange(field, precisionStep, Float
+						.valueOf(lowerTerm), Float.valueOf(upperTerm), lowerInclusive,
+						upperInclusive);
+			} else {
+				throw new ParserException(
+						"type attribute must be one of: [long, int, double, float]");
+			}
+			return filter;
+		} catch (NumberFormatException nfe) {
+			throw new ParserException(
+					"Could not parse lowerTerm or upperTerm into a number", nfe);
+		}
+	}
+}
Index: contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java
===================================================================
--- contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java	(revision 0)
+++ contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeFilterBuilderTestCase.java	(revision 0)
@@ -0,0 +1,216 @@
+package com.apache.lucene.xmlparser.builders;
+
+/**
+ * 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 java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriter.MaxFieldLength;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.NumericRangeFilter;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.xmlparser.ParserException;
+import org.apache.lucene.xmlparser.builders.NumericRangeFilterBuilder;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class NumericRangeFilterBuilderTestCase extends TestCase {
+
+	public void testGetFilterHandleNumericParseErrorStrict() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(true);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='int' lowerTerm='-1' upperTerm='NaN'/>";
+		Document doc = getDocumentFromString(xml);
+		try {
+			filterBuilder.getFilter(doc.getDocumentElement());
+		} catch (ParserException e) {
+			return;
+		}
+		fail("Expected to throw " + ParserException.class);
+	}
+
+	public void testGetFilterHandleNumericParseError() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(false);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='int' lowerTerm='-1' upperTerm='NaN'/>";
+		Document doc = getDocumentFromString(xml);
+		Filter filter = filterBuilder.getFilter(doc.getDocumentElement());
+
+		RAMDirectory ramDir = new RAMDirectory();
+		IndexWriter writer = new IndexWriter(ramDir, null, MaxFieldLength.UNLIMITED);
+		try
+		{
+			IndexReader reader = IndexReader.open(ramDir, true);
+			try
+			{
+				assertNull(filter.getDocIdSet(reader));
+			}
+			finally
+			{
+				reader.close();
+			}
+		}
+		finally
+		{
+			writer.commit();
+			writer.close();
+		}
+	}
+
+	public void testGetFilterInt() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(true);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='int' lowerTerm='-1' upperTerm='10'/>";
+		Document doc = getDocumentFromString(xml);
+		Filter filter = filterBuilder.getFilter(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Integer> numRangeFilter = (NumericRangeFilter<Integer>) filter;
+		assertEquals(Integer.valueOf(-1), numRangeFilter.getMin());
+		assertEquals(Integer.valueOf(10), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeFilter fieldName='AGE' type='int' lowerTerm='-1' upperTerm='10' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Integer> numRangeFilter2 = (NumericRangeFilter) filter2;
+		assertEquals(Integer.valueOf(-1), numRangeFilter2.getMin());
+		assertEquals(Integer.valueOf(10), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterLong() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(true);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='LoNg' lowerTerm='-2321' upperTerm='60000000'/>";
+		Document doc = getDocumentFromString(xml);
+		Filter filter = filterBuilder.getFilter(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Long> numRangeFilter = (NumericRangeFilter) filter;
+		assertEquals(Long.valueOf(-2321L), numRangeFilter.getMin());
+		assertEquals(Long.valueOf(60000000L), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeFilter fieldName='AGE' type='LoNg' lowerTerm='-2321' upperTerm='60000000' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Long> numRangeFilter2 = (NumericRangeFilter) filter2;
+		assertEquals(Long.valueOf(-2321L), numRangeFilter2.getMin());
+		assertEquals(Long.valueOf(60000000L), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterDouble() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(true);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='doubLe' lowerTerm='-23.21' upperTerm='60000.00023'/>";
+		Document doc = getDocumentFromString(xml);
+
+		Filter filter = filterBuilder.getFilter(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Double> numRangeFilter = (NumericRangeFilter) filter;
+		assertEquals(Double.valueOf(-23.21d), numRangeFilter.getMin());
+		assertEquals(Double.valueOf(60000.00023d), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeFilter fieldName='AGE' type='doubLe' lowerTerm='-23.21' upperTerm='60000.00023' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Double> numRangeFilter2 = (NumericRangeFilter) filter2;
+		assertEquals(Double.valueOf(-23.21d), numRangeFilter2.getMin());
+		assertEquals(Double.valueOf(60000.00023d), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterFloat() throws Exception {
+		NumericRangeFilterBuilder filterBuilder = new NumericRangeFilterBuilder();
+		filterBuilder.setStrictMode(true);
+
+		String xml = "<NumericRangeFilter fieldName='AGE' type='FLOAT' lowerTerm='-2.321432' upperTerm='32432.23'/>";
+		Document doc = getDocumentFromString(xml);
+
+		Filter filter = filterBuilder.getFilter(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Float> numRangeFilter = (NumericRangeFilter) filter;
+		assertEquals(Float.valueOf(-2.321432f), numRangeFilter.getMin());
+		assertEquals(Float.valueOf(32432.23f), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeFilter fieldName='AGE' type='FLOAT' lowerTerm='-2.321432' upperTerm='32432.23' includeUpper='false' precisionStep='2' />";
+		Document doc2 = getDocumentFromString(xml2);
+
+		Filter filter2 = filterBuilder.getFilter(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeFilter<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeFilter<Float> numRangeFilter2 = (NumericRangeFilter) filter2;
+		assertEquals(Float.valueOf(-2.321432f), numRangeFilter2.getMin());
+		assertEquals(Float.valueOf(32432.23f), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	private static Document getDocumentFromString(String str)
+			throws SAXException, IOException, ParserConfigurationException {
+		InputStream is = new ByteArrayInputStream(str.getBytes());
+		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+		factory.setNamespaceAware(true);
+		DocumentBuilder builder = factory.newDocumentBuilder();
+		Document doc = builder.parse(is);
+		is.close();
+		return doc;
+	}
+
+}
Index: contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java
===================================================================
--- contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java	(revision 0)
+++ contrib/xml-query-parser/src/test/com/apache/lucene/xmlparser/builders/NumericRangeQueryBuilderTestCase.java	(revision 0)
@@ -0,0 +1,178 @@
+package com.apache.lucene.xmlparser.builders;
+
+/**
+ * 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 java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.search.NumericRangeQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.xmlparser.ParserException;
+import org.apache.lucene.xmlparser.builders.NumericRangeQueryBuilder;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class NumericRangeQueryBuilderTestCase extends TestCase {
+
+	public void testGetFilterHandleNumericParseErrorStrict() throws Exception {
+		NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder();
+
+		String xml = "<NumericRangeQuery fieldName='AGE' type='int' lowerTerm='-1' upperTerm='NaN'/>";
+		Document doc = getDocumentFromString(xml);
+		try {
+			filterBuilder.getQuery(doc.getDocumentElement());
+		} catch (ParserException e) {
+			return;
+		}
+		fail("Expected to throw " + ParserException.class);
+	}
+
+	public void testGetFilterInt() throws Exception {
+		NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder();
+
+		String xml = "<NumericRangeQuery fieldName='AGE' type='int' lowerTerm='-1' upperTerm='10'/>";
+		Document doc = getDocumentFromString(xml);
+		Query filter = filterBuilder.getQuery(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Integer> numRangeFilter = (NumericRangeQuery<Integer>) filter;
+		assertEquals(Integer.valueOf(-1), numRangeFilter.getMin());
+		assertEquals(Integer.valueOf(10), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeQuery fieldName='AGE' type='int' lowerTerm='-1' upperTerm='10' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Integer> numRangeFilter2 = (NumericRangeQuery) filter2;
+		assertEquals(Integer.valueOf(-1), numRangeFilter2.getMin());
+		assertEquals(Integer.valueOf(10), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterLong() throws Exception {
+		NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder();
+
+		String xml = "<NumericRangeQuery fieldName='AGE' type='LoNg' lowerTerm='-2321' upperTerm='60000000'/>";
+		Document doc = getDocumentFromString(xml);
+		Query filter = filterBuilder.getQuery(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Long> numRangeFilter = (NumericRangeQuery) filter;
+		assertEquals(Long.valueOf(-2321L), numRangeFilter.getMin());
+		assertEquals(Long.valueOf(60000000L), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeQuery fieldName='AGE' type='LoNg' lowerTerm='-2321' upperTerm='60000000' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Long> numRangeFilter2 = (NumericRangeQuery) filter2;
+		assertEquals(Long.valueOf(-2321L), numRangeFilter2.getMin());
+		assertEquals(Long.valueOf(60000000L), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterDouble() throws Exception {
+		NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder();
+
+		String xml = "<NumericRangeQuery fieldName='AGE' type='doubLe' lowerTerm='-23.21' upperTerm='60000.00023'/>";
+		Document doc = getDocumentFromString(xml);
+
+		Query filter = filterBuilder.getQuery(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Double> numRangeFilter = (NumericRangeQuery) filter;
+		assertEquals(Double.valueOf(-23.21d), numRangeFilter.getMin());
+		assertEquals(Double.valueOf(60000.00023d), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeQuery fieldName='AGE' type='doubLe' lowerTerm='-23.21' upperTerm='60000.00023' includeUpper='false'/>";
+		Document doc2 = getDocumentFromString(xml2);
+		Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Double> numRangeFilter2 = (NumericRangeQuery) filter2;
+		assertEquals(Double.valueOf(-23.21d), numRangeFilter2.getMin());
+		assertEquals(Double.valueOf(60000.00023d), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	public void testGetFilterFloat() throws Exception {
+		NumericRangeQueryBuilder filterBuilder = new NumericRangeQueryBuilder();
+
+		String xml = "<NumericRangeQuery fieldName='AGE' type='FLOAT' lowerTerm='-2.321432' upperTerm='32432.23'/>";
+		Document doc = getDocumentFromString(xml);
+
+		Query filter = filterBuilder.getQuery(doc.getDocumentElement());
+		assertTrue(filter instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Float> numRangeFilter = (NumericRangeQuery) filter;
+		assertEquals(Float.valueOf(-2.321432f), numRangeFilter.getMin());
+		assertEquals(Float.valueOf(32432.23f), numRangeFilter.getMax());
+		assertEquals("AGE", numRangeFilter.getField());
+		assertTrue(numRangeFilter.includesMin());
+		assertTrue(numRangeFilter.includesMax());
+
+		String xml2 = "<NumericRangeQuery fieldName='AGE' type='FLOAT' lowerTerm='-2.321432' upperTerm='32432.23' includeUpper='false' precisionStep='2' />";
+		Document doc2 = getDocumentFromString(xml2);
+
+		Query filter2 = filterBuilder.getQuery(doc2.getDocumentElement());
+		assertTrue(filter2 instanceof NumericRangeQuery<?>);
+		@SuppressWarnings("unchecked")
+		NumericRangeQuery<Float> numRangeFilter2 = (NumericRangeQuery) filter2;
+		assertEquals(Float.valueOf(-2.321432f), numRangeFilter2.getMin());
+		assertEquals(Float.valueOf(32432.23f), numRangeFilter2.getMax());
+		assertEquals("AGE", numRangeFilter2.getField());
+		assertTrue(numRangeFilter2.includesMin());
+		assertFalse(numRangeFilter2.includesMax());
+	}
+
+	private static Document getDocumentFromString(String str)
+			throws SAXException, IOException, ParserConfigurationException {
+		InputStream is = new ByteArrayInputStream(str.getBytes());
+		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+		factory.setNamespaceAware(true);
+		DocumentBuilder builder = factory.newDocumentBuilder();
+		Document doc = builder.parse(is);
+		is.close();
+		return doc;
+	}
+
+}
Index: contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml
===================================================================
--- contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml	(revision 0)
+++ contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeFilterQuery.xml	(revision 0)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FilteredQuery>
+	<Query>
+		<BooleanQuery fieldName="contents">
+			<Clause occurs="should">
+				<TermQuery>merger</TermQuery>
+			</Clause>
+			<Clause occurs="mustnot">
+				<TermQuery >sumitomo</TermQuery>		
+			</Clause>
+			<Clause occurs="must">
+				<TermQuery>bank</TermQuery>
+			</Clause>
+		</BooleanQuery>
+	</Query>
+	
+	<Filter>
+		<NumericRangeFilter fieldName="date2" lowerTerm="19870409" upperTerm="19870412"/>
+	</Filter>
+	
+</FilteredQuery>
Index: contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml
===================================================================
--- contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml	(revision 0)
+++ contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/NumericRangeQueryQuery.xml	(revision 0)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BooleanQuery fieldName="contents">
+	<Clause occurs="should">
+		<TermQuery>merger</TermQuery>
+	</Clause>
+	<Clause occurs="mustnot">
+		<TermQuery >sumitomo</TermQuery>		
+	</Clause>
+	<Clause occurs="must">
+		<TermQuery>bank</TermQuery>
+	</Clause>
+	<Clause occurs="must">
+		<NumericRangeQuery fieldName="date2" lowerTerm="19870409" upperTerm="19870412"/>
+	</Clause>
+</BooleanQuery>
Index: contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java
===================================================================
--- contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java	(revision 920896)
+++ contrib/xml-query-parser/src/test/org/apache/lucene/xmlparser/TestParser.java	(working copy)
@@ -10,6 +10,7 @@
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.apache.lucene.document.Field;
+import org.apache.lucene.document.NumericField;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.search.IndexSearcher;
@@ -73,6 +74,9 @@
 				org.apache.lucene.document.Document doc =new org.apache.lucene.document.Document();
 				doc.add(new Field("date",date,Field.Store.YES,Field.Index.ANALYZED));
 				doc.add(new Field("contents",content,Field.Store.YES,Field.Index.ANALYZED));
+				NumericField numericField = new NumericField("date2");
+				numericField.setIntValue(Integer.valueOf(date));
+				doc.add(numericField);
 				writer.addDocument(doc);
 				line=d.readLine();
 			}			
@@ -194,6 +198,18 @@
 			assertEquals("DuplicateFilterQuery should produce 1 result ", 1,h);
 	}
 	
+	public void testNumericRangeFilterQueryXML() throws ParserException, IOException
+	{
+			Query q=parse("NumericRangeFilterQuery.xml");
+			dumpResults("NumericRangeFilter", q, 5);
+	}
+	
+	public void testNumericRangeQueryQueryXML() throws ParserException, IOException
+	{
+			Query q=parse("NumericRangeQueryQuery.xml");
+			dumpResults("NumericRangeQuery", q, 5);
+	}
+	
 
 
 	//================= Helper methods ===================================
