/*##################################################################### * * CLAVIN (Cartographic Location And Vicinity INdexer) * --------------------------------------------------- * * Copyright (C) 2012-2013 Berico Technologies * http://clavin.bericotechnologies.com * * ==================================================================== * * Licensed 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. * * ==================================================================== * * QueryBuilder.java * *###################################################################*/ package com.bericotech.clavin.gazetteer.query; import com.bericotech.clavin.extractor.LocationOccurrence; import com.bericotech.clavin.gazetteer.FeatureCode; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.Set; /** * A Builder class to assist in creating GazetteerQuery configurations. * QueryBuilders can be re-used to create varied queries but are not * thread-safe. */ public class QueryBuilder { private static final int DEFAULT_MAX_RESULTS = 10; private static final FuzzyMode DEFAULT_FUZZY_MODE = FuzzyMode.OFF; private static final AncestryMode DEFAULT_HIERARCHY_MODE = AncestryMode.LAZY; private static final boolean DEFAULT_INCLUDE_HISTORICAL = true; private static final boolean DEFAULT_FILTER_DUPES = false; private static final Set<FeatureCode> COUNTRY_CODES = Collections.unmodifiableSet(EnumSet.of( FeatureCode.PCL, FeatureCode.PCLD, FeatureCode.PCLF, FeatureCode.PCLH, FeatureCode.PCLI, FeatureCode.PCLIX, FeatureCode.PCLS, FeatureCode.TERRI )); private static final Set<FeatureCode> ANCESTRY_ADMIN_CODES = Collections.unmodifiableSet(EnumSet.of( FeatureCode.ADM1, FeatureCode.ADM1H, FeatureCode.ADM2, FeatureCode.ADM2H, FeatureCode.ADM3, FeatureCode.ADM3H, FeatureCode.ADM4, FeatureCode.ADM4H )); private static final Set<FeatureCode> ADMIN_CODES = Collections.unmodifiableSet(EnumSet.of( FeatureCode.ADM1, FeatureCode.ADM1H, FeatureCode.ADM2, FeatureCode.ADM2H, FeatureCode.ADM3, FeatureCode.ADM3H, FeatureCode.ADM4, FeatureCode.ADM4H, FeatureCode.ADM5, FeatureCode.ADMD, FeatureCode.ADMDH, FeatureCode.TERR, FeatureCode.PRSH )); private static final Set<FeatureCode> CITY_CODES = Collections.unmodifiableSet(EnumSet.of( FeatureCode.PPL, FeatureCode.PPLA, FeatureCode.PPLA2, FeatureCode.PPLA3, FeatureCode.PPLA4, FeatureCode.PPLC, FeatureCode.PPLCH, FeatureCode.PPLF, FeatureCode.PPLG, FeatureCode.PPLH, FeatureCode.PPLL, FeatureCode.PPLQ, FeatureCode.PPLR, FeatureCode.PPLS, FeatureCode.PPLW, FeatureCode.PPLX, FeatureCode.STLMT )); private LocationOccurrence location; private int maxResults = DEFAULT_MAX_RESULTS; private FuzzyMode fuzzyMode = DEFAULT_FUZZY_MODE; private AncestryMode ancestryMode = DEFAULT_HIERARCHY_MODE; private boolean includeHistorical = DEFAULT_INCLUDE_HISTORICAL; private boolean filterDupes = DEFAULT_FILTER_DUPES; private Set<Integer> parentIds = new HashSet<Integer>(); private Set<FeatureCode> featureCodes = EnumSet.noneOf(FeatureCode.class); /** * Constructs a query from the current configuration of this Builder. * @return a {@link GazetteerQuery} configuration object */ public GazetteerQuery build() { return new GazetteerQuery(location, maxResults, fuzzyMode, ancestryMode, includeHistorical, filterDupes, parentIds, featureCodes); } /** * Get the currently configured location to query for. * @return the location to query for */ public LocationOccurrence location() { return location; } /** * Set the location to query for. * @param loc the location to query for. * @return this */ public QueryBuilder location(final LocationOccurrence loc) { location = loc; return this; } /** * Convenience method to create a LocationOccurrence at position 0 for * the given location name. * @param locName the name of the location to query for * @return this */ public QueryBuilder location(final String locName) { location = new LocationOccurrence(locName, 0); return this; } /** * Get the current maximum number of results. * @return the maximum number of results */ public int maxResults() { return maxResults; } /** * Set the maximum number of search results. * @param max the maximum number of results * @return this */ public QueryBuilder maxResults(final int max) { maxResults = max; return this; } /** * Get the current fuzzy matching mode. * @return the fuzzy matching mode */ public FuzzyMode fuzzyMode() { return fuzzyMode; } /** * Configure the fuzzy matching mode. * @param mode the fuzzy matching mode * @return this */ public QueryBuilder fuzzyMode(final FuzzyMode mode) { fuzzyMode = mode; return this; } /** * Get the current ancestry loading mode. * @return the ancestry loading mode */ public AncestryMode ancestryMode() { return ancestryMode; } /** * Configure the ancestry loading mode. * @param mode the ancestry loading mode * @return this */ public QueryBuilder ancestryMode(final AncestryMode mode) { ancestryMode = mode; return this; } /** * Does this builder include historical locations? * @return <code>true</code> if this builder is configured to return historical locations */ public boolean includeHistorical() { return includeHistorical; } /** * Indicate whether or not this builder includes historical locations in the search results. * @param incHist <code>true</code> to include historical locations in the results * @return this */ public QueryBuilder includeHistorical(final boolean incHist) { includeHistorical = incHist; return this; } /** * Does this builder filter duplicate results? * @return <code>true</code> if this builder is configured to filter duplicates */ public boolean filterDupes() { return filterDupes; } /** * Indicate whether or not this builder should filter duplicate results. * @param filter <code>true</code> to filter duplicate results * @return this */ public QueryBuilder filterDupes(final boolean filter) { filterDupes = filter; return this; } /** * Get the set of parent IDs that will be used to constrain the query results. This set * may not be modifiable and modifications, if allowed, will not affect the generated * queries. * @return the current set of parent IDs used to constrain the query results */ public Set<Integer> parentIds() { return Collections.unmodifiableSet(parentIds); } /** * Set the parent IDs that will be used to constraint the query results; replacing any * previously configured IDs. Use the addParentIds() and removeParentIds() methods to * modify the existing configuration. * @param ids the new set of parent IDs used to constrain the query results * @return this */ public QueryBuilder parentIds(final Set<Integer> ids) { parentIds = new HashSet<Integer>(); if (ids != null) { parentIds.addAll(ids); } return this; } /** * Add the provided parent ID to the set of query constraints. * @param id the parent ID to add * @return this */ public QueryBuilder addParentIds(final Integer id) { parentIds.add(id); return this; } /** * Add the provided parent IDs to the set of query constraints. * @param id1 the first parent ID to add * @param ids the subsequent parent IDs to add * @return this */ public QueryBuilder addParentIds(final Integer id1, final Integer... ids) { parentIds.add(id1); parentIds.addAll(Arrays.asList(ids)); return this; } /** * Add the provided parent IDs to the set of query constraints. * @param ids the parent IDs to add * @return this */ public QueryBuilder addParentIds(final Collection<Integer> ids) { if (ids != null) { parentIds.addAll(ids); } return this; } /** * Remove the provided parent ID from the set of query constraints. * @param id the parent ID to remove * @return this */ public QueryBuilder removeParentIds(final Integer id) { parentIds.remove(id); return this; } /** * Remove the provided parent IDs from the set of query constraints. * @param id1 the first parent ID to remove * @param ids the subsequent parent IDs to remove * @return this */ public QueryBuilder removeParentIds(final Integer id1, final Integer... ids) { parentIds.remove(id1); parentIds.removeAll(Arrays.asList(ids)); return this; } /** * Remove the provided parent IDs from the set of query constraints. * @param ids the parent IDs to remove * @return this */ public QueryBuilder removeParentIds(final Collection<Integer> ids) { if (ids != null) { parentIds.removeAll(ids); } return this; } /** * Convenience method to remove all current parent ID restrictions. * @return this */ public QueryBuilder clearParentIds() { parentIds = new HashSet<Integer>(); return this; } /** * Get the set of {@link FeatureCode}s that will be used to constrain the query results. This set * may not be modifiable and modifications, if allowed, will not affect the generated * queries. * @return the current set of {@link FeatureCode}s used to constrain the query results */ public Set<FeatureCode> featureCodes() { return Collections.unmodifiableSet(featureCodes); } /** * Set the {@link FeatureCode}s that will be used to constraint the query results; replacing any * previously configured IDs. Use the addFeatureCodes() and removeFeatureCodes() methods to * modify the existing configuration. * @param codes the new set of {@link FeatureCode}s used to constrain the query results * @return this */ public QueryBuilder featureCodes(final Set<FeatureCode> codes) { featureCodes = EnumSet.noneOf(FeatureCode.class); if (codes != null) { featureCodes.addAll(codes); } return this; } /** * Add the provided {@link FeatureCode} to the set of query constraints. * @param code the {@link FeatureCode} to add * @return this */ public QueryBuilder addFeatureCodes(final FeatureCode code) { featureCodes.add(code); return this; } /** * Add the provided {@link FeatureCode}s to the set of query constraints. * @param code1 the first {@link FeatureCode} to add * @param codes the subsequent {@link FeatureCode}s to add * @return this */ public QueryBuilder addFeatureCodes(final FeatureCode code1, final FeatureCode... codes) { featureCodes.add(code1); featureCodes.addAll(Arrays.asList(codes)); return this; } /** * Add the provided {@link FeatureCode}s to the set of query constraints. * @param codes the {@link FeatureCode}s to add * @return this */ public QueryBuilder addFeatureCodes(final Collection<FeatureCode> codes) { if (codes != null) { featureCodes.addAll(codes); } return this; } /** * Remove the provided {@link FeatureCode} from the set of query constraints. * @param code the {@link FeatureCode} to remove * @return this */ public QueryBuilder removeFeatureCodes(final FeatureCode code) { featureCodes.remove(code); return this; } /** * Remove the provided {@link FeatureCode} from the set of query constraints. * @param code1 the first {@link FeatureCode} to remove * @param codes the subsequent {@link FeatureCode}s to remove * @return this */ public QueryBuilder removeFeatureCodes(final FeatureCode code1, final FeatureCode... codes) { featureCodes.remove(code1); featureCodes.removeAll(Arrays.asList(codes)); return this; } /** * Remove the provided {@link FeatureCode}s from the set of query constraints. * @param codes the {@link FeatureCode}s to remove * @return this */ public QueryBuilder removeFeatureCodes(final Collection<FeatureCode> codes) { if (codes != null) { featureCodes.removeAll(codes); } return this; } /** * Convenience method to clear any existing {@link FeatureCode} restrictions. * @return this */ public QueryBuilder clearFeatureCodes() { featureCodes = EnumSet.noneOf(FeatureCode.class); return this; } /** * Convenience method to add the {@link FeatureCode}s representing countries * and similar top-level political entities to the restriction list. This * method modifies the existing set of codes. * @return this */ public QueryBuilder addCountryCodes() { return addFeatureCodes(COUNTRY_CODES); } /** * Convenience method to remove the {@link FeatureCode}s representing countries * and similar top-level political entities from the restriction list. This * method modifies the existing set of codes. * @return this */ public QueryBuilder removeCountryCodes() { return removeFeatureCodes(COUNTRY_CODES); } /** * Convenience method to add the {@link FeatureCode}s representing administrative * divisions to the restriction list. This includes all ADM* codes, territories (TERR) * and parishes (PRSH). This method modifies the existing set of codes. * @return this */ public QueryBuilder addAdminCodes() { return addFeatureCodes(ADMIN_CODES); } /** * Convenience method to remove the {@link FeatureCode}s representing administrative * divisions from the restriction list. This includes all ADM* codes, territories (TERR) * and parishes (PRSH). This method modifies the existing set of codes. * @return this */ public QueryBuilder removeAdminCodes() { return removeFeatureCodes(ADMIN_CODES); } /** * Convenience method to add the {@link FeatureCode}s representing administrative * divisions that can be part of the ancestry tree to the restriction list. This * only includes administrative divisions 1-4 (ADM[1-4]). This method modifies the * existing set of codes. * @return this */ public QueryBuilder addAncestryAdminCodes() { return addFeatureCodes(ANCESTRY_ADMIN_CODES); } /** * Convenience method to remove the {@link FeatureCode}s representing administrative * divisions that can be part of the ancestry tree from the restriction list. This * only includes administrative divisions 1-4 (ADM[1-4]). This method modifies the * existing set of codes. * @return this */ public QueryBuilder removeAncestryAdminCodes() { return removeFeatureCodes(ANCESTRY_ADMIN_CODES); } /** * Convenience method to add the {@link FeatureCode}s representing cities and other * populated places to the restriction list. This method modifies the existing set * of codes. * @return this */ public QueryBuilder addCityCodes() { return addFeatureCodes(CITY_CODES); } /** * Convenience method to remove the {@link FeatureCode}s representing cities and other * populated places from the restriction list. This method modifies the existing set * of codes. * @return this */ public QueryBuilder removeCityCodes() { return removeFeatureCodes(CITY_CODES); } @Override public String toString() { return String.format("loc: %s, maxResults: %s, fuzzyMode: %s, historical? %s, filterDupes? %s, parents: %s, codes: %s", location, maxResults, fuzzyMode, includeHistorical, filterDupes, parentIds, featureCodes); } }