| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.lucene.document; |
| |
| import java.net.InetAddress; |
| |
| import org.apache.lucene.document.RangeFieldQuery.QueryType; |
| import org.apache.lucene.search.Query; |
| import org.apache.lucene.util.BytesRef; |
| import org.apache.lucene.util.FutureArrays; |
| |
| /** |
| * An indexed InetAddress Range Field |
| * <p> |
| * This field indexes an {@code InetAddress} range defined as a min/max pairs. It is single |
| * dimension only (indexed as two 16 byte paired values). |
| * <p> |
| * Multiple values are supported. |
| * |
| * <p> |
| * This field defines the following static factory methods for common search operations over Ip Ranges |
| * <ul> |
| * <li>{@link #newIntersectsQuery newIntersectsQuery()} matches ip ranges that intersect the defined search range. |
| * <li>{@link #newWithinQuery newWithinQuery()} matches ip ranges that are within the defined search range. |
| * <li>{@link #newContainsQuery newContainsQuery()} matches ip ranges that contain the defined search range. |
| * <li>{@link #newCrossesQuery newCrossesQuery()} matches ip ranges that cross the defined search range |
| * </ul> |
| */ |
| public class InetAddressRange extends Field { |
| /** The number of bytes per dimension : sync w/ {@code InetAddressPoint} */ |
| public static final int BYTES = InetAddressPoint.BYTES; |
| |
| private static final FieldType TYPE; |
| static { |
| TYPE = new FieldType(); |
| TYPE.setDimensions(2, BYTES); |
| TYPE.freeze(); |
| } |
| |
| /** |
| * Create a new InetAddressRange from min/max value |
| * @param name field name. must not be null. |
| * @param min range min value; defined as an {@code InetAddress} |
| * @param max range max value; defined as an {@code InetAddress} |
| */ |
| public InetAddressRange(String name, final InetAddress min, final InetAddress max) { |
| super(name, TYPE); |
| setRangeValues(min, max); |
| } |
| |
| /** |
| * Change (or set) the min/max values of the field. |
| * @param min range min value; defined as an {@code InetAddress} |
| * @param max range max value; defined as an {@code InetAddress} |
| */ |
| public void setRangeValues(InetAddress min, InetAddress max) { |
| final byte[] bytes; |
| if (fieldsData == null) { |
| bytes = new byte[BYTES*2]; |
| fieldsData = new BytesRef(bytes); |
| } else { |
| bytes = ((BytesRef)fieldsData).bytes; |
| } |
| encode(min, max, bytes); |
| } |
| |
| /** encode the min/max range into the provided byte array */ |
| private static void encode(final InetAddress min, final InetAddress max, final byte[] bytes) { |
| // encode min and max value (consistent w/ InetAddressPoint encoding) |
| final byte[] minEncoded = InetAddressPoint.encode(min); |
| final byte[] maxEncoded = InetAddressPoint.encode(max); |
| // ensure min is lt max |
| if (FutureArrays.compareUnsigned(minEncoded, 0, BYTES, maxEncoded, 0, BYTES) > 0) { |
| throw new IllegalArgumentException("min value cannot be greater than max value for InetAddressRange field"); |
| } |
| System.arraycopy(minEncoded, 0, bytes, 0, BYTES); |
| System.arraycopy(maxEncoded, 0, bytes, BYTES, BYTES); |
| } |
| |
| /** encode the min/max range and return the byte array */ |
| private static byte[] encode(InetAddress min, InetAddress max) { |
| byte[] b = new byte[BYTES*2]; |
| encode(min, max, b); |
| return b; |
| } |
| |
| /** |
| * Create a query for matching indexed ip ranges that {@code INTERSECT} the defined range. |
| * @param field field name. must not be null. |
| * @param min range min value; provided as an {@code InetAddress} |
| * @param max range max value; provided as an {@code InetAddress} |
| * @return query for matching intersecting ranges (overlap, within, crosses, or contains) |
| * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid |
| */ |
| public static Query newIntersectsQuery(String field, final InetAddress min, final InetAddress max) { |
| return newRelationQuery(field, min, max, QueryType.INTERSECTS); |
| } |
| |
| /** |
| * Create a query for matching indexed ip ranges that {@code CONTAINS} the defined range. |
| * @param field field name. must not be null. |
| * @param min range min value; provided as an {@code InetAddress} |
| * @param max range max value; provided as an {@code InetAddress} |
| * @return query for matching intersecting ranges (overlap, within, crosses, or contains) |
| * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid |
| */ |
| public static Query newContainsQuery(String field, final InetAddress min, final InetAddress max) { |
| return newRelationQuery(field, min, max, QueryType.CONTAINS); |
| } |
| |
| /** |
| * Create a query for matching indexed ip ranges that are {@code WITHIN} the defined range. |
| * @param field field name. must not be null. |
| * @param min range min value; provided as an {@code InetAddress} |
| * @param max range max value; provided as an {@code InetAddress} |
| * @return query for matching intersecting ranges (overlap, within, crosses, or contains) |
| * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid |
| */ |
| public static Query newWithinQuery(String field, final InetAddress min, final InetAddress max) { |
| return newRelationQuery(field, min, max, QueryType.WITHIN); |
| } |
| |
| /** |
| * Create a query for matching indexed ip ranges that {@code CROSS} the defined range. |
| * @param field field name. must not be null. |
| * @param min range min value; provided as an {@code InetAddress} |
| * @param max range max value; provided as an {@code InetAddress} |
| * @return query for matching intersecting ranges (overlap, within, crosses, or contains) |
| * @throws IllegalArgumentException if {@code field} is null, {@code min} or {@code max} is invalid |
| */ |
| public static Query newCrossesQuery(String field, final InetAddress min, final InetAddress max) { |
| return newRelationQuery(field, min, max, QueryType.CROSSES); |
| } |
| |
| /** helper method for creating the desired relational query */ |
| private static Query newRelationQuery(String field, final InetAddress min, final InetAddress max, QueryType relation) { |
| return new RangeFieldQuery(field, encode(min, max), 1, relation) { |
| @Override |
| protected String toString(byte[] ranges, int dimension) { |
| return InetAddressRange.toString(ranges, dimension); |
| } |
| }; |
| } |
| |
| /** |
| * Returns the String representation for the range at the given dimension |
| * @param ranges the encoded ranges, never null |
| * @param dimension the dimension of interest (not used for this field) |
| * @return The string representation for the range at the provided dimension |
| */ |
| private static String toString(byte[] ranges, int dimension) { |
| byte[] min = new byte[BYTES]; |
| System.arraycopy(ranges, 0, min, 0, BYTES); |
| byte[] max = new byte[BYTES]; |
| System.arraycopy(ranges, BYTES, max, 0, BYTES); |
| return "[" + InetAddressPoint.decode(min) + " : " + InetAddressPoint.decode(max) + "]"; |
| } |
| } |