Java tutorial
/* * 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.usergrid.mq; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonTokenStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.usergrid.persistence.CounterResolution; import org.apache.usergrid.persistence.Entity; import org.apache.usergrid.persistence.Identifier; import org.apache.usergrid.persistence.Results; import org.apache.usergrid.persistence.Results.Level; import org.apache.usergrid.utils.JsonUtils; import org.springframework.util.Assert; import org.apache.commons.lang.StringUtils; import static org.apache.commons.codec.binary.Base64.decodeBase64; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.split; import static org.apache.usergrid.persistence.Schema.PROPERTY_TYPE; import static org.apache.usergrid.persistence.Schema.PROPERTY_UUID; import static org.apache.usergrid.utils.ClassUtils.cast; import static org.apache.usergrid.utils.ConversionUtils.uuid; import static org.apache.usergrid.utils.ListUtils.first; import static org.apache.usergrid.utils.ListUtils.firstBoolean; import static org.apache.usergrid.utils.ListUtils.firstInteger; import static org.apache.usergrid.utils.ListUtils.firstLong; import static org.apache.usergrid.utils.ListUtils.firstUuid; import static org.apache.usergrid.utils.ListUtils.isEmpty; import static org.apache.usergrid.utils.MapUtils.toMapList; public class Query { private static final Logger logger = LoggerFactory.getLogger(Query.class); public static final int DEFAULT_LIMIT = 10; protected String type; protected List<SortPredicate> sortPredicates = new ArrayList<SortPredicate>(); protected List<FilterPredicate> filterPredicates = new ArrayList<FilterPredicate>(); protected UUID startResult; protected String cursor; protected int limit = 0; protected boolean limitSet = false; protected Map<String, String> selectSubjects = new LinkedHashMap<String, String>(); protected boolean mergeSelectResults = false; protected Level level = Level.ALL_PROPERTIES; protected String connection; protected List<String> permissions; protected boolean reversed; protected boolean reversedSet = false; protected Long startTime; protected Long finishTime; protected boolean pad; protected CounterResolution resolution = CounterResolution.ALL; protected List<Identifier> users; protected List<Identifier> groups; protected List<Identifier> identifiers; protected List<String> categories; protected List<CounterFilterPredicate> counterFilters; public Query() { } public Query(String type) { this.type = type; } public Query(Query q) { if (q != null) { type = q.type; sortPredicates = q.sortPredicates != null ? new ArrayList<SortPredicate>(q.sortPredicates) : null; filterPredicates = q.filterPredicates != null ? new ArrayList<FilterPredicate>(q.filterPredicates) : null; startResult = q.startResult; cursor = q.cursor; limit = q.limit; limitSet = q.limitSet; selectSubjects = q.selectSubjects != null ? new LinkedHashMap<String, String>(q.selectSubjects) : null; mergeSelectResults = q.mergeSelectResults; level = q.level; connection = q.connection; permissions = q.permissions != null ? new ArrayList<String>(q.permissions) : null; reversed = q.reversed; reversedSet = q.reversedSet; startTime = q.startTime; finishTime = q.finishTime; resolution = q.resolution; pad = q.pad; users = q.users != null ? new ArrayList<Identifier>(q.users) : null; groups = q.groups != null ? new ArrayList<Identifier>(q.groups) : null; identifiers = q.identifiers != null ? new ArrayList<Identifier>(q.identifiers) : null; categories = q.categories != null ? new ArrayList<String>(q.categories) : null; counterFilters = q.counterFilters != null ? new ArrayList<CounterFilterPredicate>(q.counterFilters) : null; } } public static Query fromQL(String ql) { if (ql == null) { return null; } ql = ql.trim(); String qlt = ql.toLowerCase(); if (!qlt.startsWith("select") && !qlt.startsWith("insert") && !qlt.startsWith("update") && !qlt.startsWith("delete")) { if (qlt.startsWith("order by")) { ql = "select * " + ql; } else { ql = "select * where " + ql; } } try { ANTLRStringStream in = new ANTLRStringStream(ql.trim()); QueryFilterLexer lexer = new QueryFilterLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); QueryFilterParser parser = new QueryFilterParser(tokens); Query q = parser.ql(); return q; } catch (Exception e) { logger.error("Unable to parse \"" + ql + "\"", e); } return null; } public static Query newQueryIfNull(Query query) { if (query == null) { query = new Query(); } return query; } public static Query fromJsonString(String json) { Object o = JsonUtils.parse(json); if (o instanceof Map) { @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, List<String>> params = cast(toMapList((Map) o)); return fromQueryParams(params); } return null; } public static Query fromQueryParams(Map<String, List<String>> params) { String type = null; Query q = null; String ql = null; String connection = null; UUID start = null; String cursor = null; Integer limit = null; List<String> permissions = null; Boolean reversed = null; Long startTime = null; Long finishTime = null; Boolean pad = null; CounterResolution resolution = null; List<Identifier> users = null; List<Identifier> groups = null; List<Identifier> identifiers = null; List<String> categories = null; List<CounterFilterPredicate> counterFilters = null; List<String> l = null; ql = first(params.get("ql")); type = first(params.get("type")); reversed = firstBoolean(params.get("reversed")); connection = first(params.get("connection")); start = firstUuid(params.get("start")); cursor = first(params.get("cursor")); limit = firstInteger(params.get("limit")); permissions = params.get("permission"); startTime = firstLong(params.get("start_time")); finishTime = firstLong(params.get("end_time")); l = params.get("resolution"); if (!isEmpty(l)) { resolution = CounterResolution.fromString(l.get(0)); } users = Identifier.fromList(params.get("user")); groups = Identifier.fromList(params.get("group")); categories = params.get("category"); l = params.get("counter"); if (!isEmpty(l)) { counterFilters = CounterFilterPredicate.fromList(l); } pad = firstBoolean(params.get("pad")); for (Entry<String, List<String>> param : params.entrySet()) { if ((param.getValue() == null) || (param.getValue().size() == 0)) { Identifier identifier = Identifier.from(param.getKey()); if (identifier != null) { if (identifiers == null) { identifiers = new ArrayList<Identifier>(); } identifiers.add(identifier); } } } if (ql != null) { q = Query.fromQL(ql); } l = params.get("filter"); if (!isEmpty(l)) { q = newQueryIfNull(q); for (String s : l) { q.addFilter(s); } } l = params.get("sort"); if (!isEmpty(l)) { q = newQueryIfNull(q); for (String s : l) { q.addSort(s); } } if (type != null) { q = newQueryIfNull(q); q.setEntityType(type); } if (connection != null) { q = newQueryIfNull(q); q.setConnectionType(connection); } if (permissions != null) { q = newQueryIfNull(q); q.setPermissions(permissions); } if (start != null) { q = newQueryIfNull(q); q.setStartResult(start); } if (cursor != null) { q = newQueryIfNull(q); q.setCursor(cursor); } if (limit != null) { q = newQueryIfNull(q); q.setLimit(limit); } if (startTime != null) { q = newQueryIfNull(q); q.setStartTime(startTime); } if (finishTime != null) { q = newQueryIfNull(q); q.setFinishTime(finishTime); } if (resolution != null) { q = newQueryIfNull(q); q.setResolution(resolution); } if (categories != null) { q = newQueryIfNull(q); q.setCategories(categories); } if (counterFilters != null) { q = newQueryIfNull(q); q.setCounterFilters(counterFilters); } if (pad != null) { q = newQueryIfNull(q); q.setPad(pad); } if (users != null) { q = newQueryIfNull(q); q.setUsers(users); } if (groups != null) { q = newQueryIfNull(q); q.setGroups(groups); } if (identifiers != null) { q = newQueryIfNull(q); q.setIdentifiers(identifiers); } if (reversed != null) { q = newQueryIfNull(q); q.setReversed(reversed); } return q; } public static Query searchForProperty(String propertyName, Object propertyValue) { Query q = new Query(); q.addEqualityFilter(propertyName, propertyValue); return q; } public static Query findForProperty(String propertyName, Object propertyValue) { Query q = new Query(); q.addEqualityFilter(propertyName, propertyValue); q.setLimit(1); return q; } public static Query fromUUID(UUID uuid) { Query q = new Query(); q.addIdentifier(Identifier.fromUUID(uuid)); return q; } public static Query fromName(String name) { Query q = new Query(); q.addIdentifier(Identifier.fromName(name)); return q; } public static Query fromEmail(String email) { Query q = new Query(); q.addIdentifier(Identifier.fromEmail(email)); return q; } public static Query fromIdentifier(Object id) { Query q = new Query(); q.addIdentifier(Identifier.from(id)); return q; } public boolean isIdsOnly() { if ((selectSubjects.size() == 1) && selectSubjects.containsKey(PROPERTY_UUID)) { level = Level.IDS; return true; } return false; } public void setIdsOnly(boolean idsOnly) { if (idsOnly) { selectSubjects = new LinkedHashMap<String, String>(); selectSubjects.put(PROPERTY_UUID, PROPERTY_UUID); level = Level.IDS; } else if (isIdsOnly()) { selectSubjects = new LinkedHashMap<String, String>(); level = Level.ALL_PROPERTIES; } } public Level getResultsLevel() { isIdsOnly(); return level; } public void setResultsLevel(Level level) { setIdsOnly(level == Level.IDS); this.level = level; } public Query withResultsLevel(Level level) { setIdsOnly(level == Level.IDS); this.level = level; return this; } public String getEntityType() { return type; } public void setEntityType(String type) { this.type = type; } public Query withEntityType(String type) { this.type = type; return this; } public String getConnectionType() { return connection; } public void setConnectionType(String connection) { this.connection = connection; } public Query withConnectionType(String connection) { this.connection = connection; return this; } public List<String> getPermissions() { return permissions; } public void setPermissions(List<String> permissions) { this.permissions = permissions; } public Query withPermissions(List<String> permissions) { this.permissions = permissions; return this; } public Query addSelect(String select) { return addSelect(select, null); } public Query addSelect(String select, String output) { // be paranoid with the null checks because // the query parser sometimes flakes out if (select == null) { return this; } select = select.trim(); if (select.equals("*")) { return this; } mergeSelectResults = StringUtils.isNotEmpty(output); if (output == null) { output = ""; } selectSubjects.put(select, output); return this; } public boolean hasSelectSubjects() { return !selectSubjects.isEmpty(); } public Set<String> getSelectSubjects() { return selectSubjects.keySet(); } public Map<String, String> getSelectAssignments() { return selectSubjects; } public void setMergeSelectResults(boolean mergeSelectResults) { this.mergeSelectResults = mergeSelectResults; } public Query withMergeSelectResults(boolean mergeSelectResults) { this.mergeSelectResults = mergeSelectResults; return this; } public boolean isMergeSelectResults() { return mergeSelectResults; } public Query addSort(String propertyName) { if (isBlank(propertyName)) { return this; } propertyName = propertyName.trim(); if (propertyName.indexOf(',') >= 0) { String[] propertyNames = split(propertyName, ','); for (String s : propertyNames) { addSort(s); } return this; } SortDirection direction = SortDirection.ASCENDING; if (propertyName.indexOf(' ') >= 0) { String[] parts = split(propertyName, ' '); if (parts.length > 1) { propertyName = parts[0]; direction = SortDirection.find(parts[1]); } } else if (propertyName.startsWith("-")) { propertyName = propertyName.substring(1); direction = SortDirection.DESCENDING; } else if (propertyName.startsWith("+")) { propertyName = propertyName.substring(1); direction = SortDirection.ASCENDING; } return addSort(propertyName, direction); } public Query addSort(String propertyName, SortDirection direction) { if (isBlank(propertyName)) { return this; } propertyName = propertyName.trim(); for (SortPredicate s : sortPredicates) { if (s.getPropertyName().equals(propertyName)) { logger.error( "Attempted to set sort order for " + s.getPropertyName() + " more than once, discardng..."); return this; } } sortPredicates.add(new SortPredicate(propertyName, direction)); return this; } public Query addSort(SortPredicate sort) { if (sort == null) { return this; } for (SortPredicate s : sortPredicates) { if (s.getPropertyName().equals(sort.getPropertyName())) { logger.error( "Attempted to set sort order for " + s.getPropertyName() + " more than once, discardng..."); return this; } } sortPredicates.add(sort); return this; } public List<SortPredicate> getSortPredicates() { return sortPredicates; } public boolean hasSortPredicates() { return !sortPredicates.isEmpty(); } public Query addEqualityFilter(String propertyName, Object value) { return addFilter(propertyName, FilterOperator.EQUAL, value); } public Query addFilter(String propertyName, FilterOperator operator, Object value) { if ((propertyName == null) || (operator == null) || (value == null)) { return this; } if (PROPERTY_TYPE.equalsIgnoreCase(propertyName) && (value != null)) { if (operator == FilterOperator.EQUAL) { type = value.toString(); } } else if ("connection".equalsIgnoreCase(propertyName) && (value != null)) { if (operator == FilterOperator.EQUAL) { connection = value.toString(); } } else { for (FilterPredicate f : filterPredicates) { if (f.getPropertyName().equals(propertyName) && f.getValue().equals(value) && "*".equals(value)) { logger.error("Attempted to set wildcard wilder for " + f.getPropertyName() + " more than once, discardng..."); return this; } } filterPredicates.add(FilterPredicate.normalize(new FilterPredicate(propertyName, operator, value))); } return this; } public Query addFilter(String filterStr) { if (filterStr == null) { return this; } FilterPredicate filter = FilterPredicate.valueOf(filterStr); if ((filter != null) && (filter.propertyName != null) && (filter.operator != null) && (filter.value != null)) { if (PROPERTY_TYPE.equalsIgnoreCase(filter.propertyName)) { if (filter.operator == FilterOperator.EQUAL) { type = filter.value.toString(); } } else if ("connection".equalsIgnoreCase(filter.propertyName)) { if (filter.operator == FilterOperator.EQUAL) { connection = filter.value.toString(); } } else { for (FilterPredicate f : filterPredicates) { if (f.getPropertyName().equals(filter.getPropertyName()) && f.getValue().equals(filter.getValue()) && "*".equals(filter.getValue())) { logger.error("Attempted to set wildcard wilder for " + f.getPropertyName() + " more than once, discardng..."); return this; } } filterPredicates.add(filter); } } else { logger.error("Unable to add filter to query: " + filterStr); } return this; } public Query addFilter(FilterPredicate filter) { filter = FilterPredicate.normalize(filter); if ((filter != null) && (filter.propertyName != null) && (filter.operator != null) && (filter.value != null)) { if (PROPERTY_TYPE.equalsIgnoreCase(filter.propertyName)) { if (filter.operator == FilterOperator.EQUAL) { type = filter.value.toString(); } } else if ("connection".equalsIgnoreCase(filter.propertyName)) { if (filter.operator == FilterOperator.EQUAL) { connection = filter.value.toString(); } } else { filterPredicates.add(filter); } } return this; } public List<FilterPredicate> getFilterPredicates() { return filterPredicates; } public boolean hasFilterPredicates() { return !filterPredicates.isEmpty(); } public Map<String, Object> getEqualityFilters() { Map<String, Object> map = new LinkedHashMap<String, Object>(); for (FilterPredicate f : filterPredicates) { if (f.operator == FilterOperator.EQUAL) { Object val = f.getStartValue(); if (val != null) { map.put(f.getPropertyName(), val); } } } return map.size() > 0 ? map : null; } public boolean hasFiltersForProperty(String name) { return hasFiltersForProperty(FilterOperator.EQUAL, name); } public boolean hasFiltersForProperty(FilterOperator operator, String name) { return getFilterForProperty(operator, name) != null; } public FilterPredicate getFilterForProperty(FilterOperator operator, String name) { if (name == null) { return null; } ListIterator<FilterPredicate> iterator = filterPredicates.listIterator(); while (iterator.hasNext()) { FilterPredicate f = iterator.next(); if (f.propertyName.equalsIgnoreCase(name)) { if (operator != null) { if (operator == f.operator) { return f; } } else { return f; } } } return null; } public void removeFiltersForProperty(String name) { if (name == null) { return; } ListIterator<FilterPredicate> iterator = filterPredicates.listIterator(); while (iterator.hasNext()) { FilterPredicate f = iterator.next(); if (f.propertyName.equalsIgnoreCase(name)) { iterator.remove(); } } } public void setStartResult(UUID startResult) { this.startResult = startResult; } public Query withStartResult(UUID startResult) { this.startResult = startResult; return this; } public UUID getStartResult() { if ((startResult == null) && (cursor != null)) { byte[] cursorBytes = decodeBase64(cursor); if ((cursorBytes != null) && (cursorBytes.length == 16)) { startResult = uuid(cursorBytes); } } return startResult; } public String getCursor() { return cursor; } public void setCursor(String cursor) { if (cursor != null) { if (cursor.length() == 22) { byte[] cursorBytes = decodeBase64(cursor); if ((cursorBytes != null) && (cursorBytes.length == 16)) { startResult = uuid(cursorBytes); cursor = null; } } } this.cursor = cursor; } public Query withCursor(String cursor) { setCursor(cursor); return this; } public int getLimit() { return getLimit(DEFAULT_LIMIT); } public int getLimit(int defaultLimit) { if (limit <= 0) { if (defaultLimit > 0) { return defaultLimit; } else { return DEFAULT_LIMIT; } } return limit; } public void setLimit(int limit) { limitSet = true; this.limit = limit; } public Query withLimit(int limit) { limitSet = true; this.limit = limit; return this; } public boolean isLimitSet() { return limitSet; } public boolean isReversed() { return reversed; } public void setReversed(boolean reversed) { reversedSet = true; this.reversed = reversed; } public boolean isReversedSet() { return reversedSet; } public Long getStartTime() { return startTime; } public void setStartTime(Long startTime) { this.startTime = startTime; } public Long getFinishTime() { return finishTime; } public void setFinishTime(Long finishTime) { this.finishTime = finishTime; } public boolean isPad() { return pad; } public void setPad(boolean pad) { this.pad = pad; } public void setResolution(CounterResolution resolution) { this.resolution = resolution; } public CounterResolution getResolution() { return resolution; } public List<Identifier> getUsers() { return users; } public void addUser(Identifier user) { if (users == null) { users = new ArrayList<Identifier>(); } users.add(user); } public void setUsers(List<Identifier> users) { this.users = users; } public List<Identifier> getGroups() { return groups; } public void addGroup(Identifier group) { if (groups == null) { groups = new ArrayList<Identifier>(); } groups.add(group); } public void setGroups(List<Identifier> groups) { this.groups = groups; } public List<Identifier> getIdentifiers() { return identifiers; } public void addIdentifier(Identifier identifier) { if (identifiers == null) { identifiers = new ArrayList<Identifier>(); } identifiers.add(identifier); } public void setIdentifiers(List<Identifier> identifiers) { this.identifiers = identifiers; } public boolean containsUuidIdentifersOnly() { if (hasFilterPredicates()) { return false; } if ((identifiers == null) || identifiers.isEmpty()) { return false; } for (Identifier identifier : identifiers) { if (!identifier.isUUID()) { return false; } } return true; } public boolean containsSingleUuidIdentifier() { return containsUuidIdentifersOnly() && (identifiers.size() == 1); } public List<UUID> getUuidIdentifiers() { if ((identifiers == null) || identifiers.isEmpty()) { return null; } List<UUID> ids = new ArrayList<UUID>(); for (Identifier identifier : identifiers) { if (identifier.isUUID()) { ids.add(identifier.getUUID()); } } return ids; } public UUID getSingleUuidIdentifier() { if (!containsSingleUuidIdentifier()) { return null; } return (identifiers.get(0).getUUID()); } public boolean containsNameIdentifiersOnly() { if (hasFilterPredicates()) { return false; } if ((identifiers == null) || identifiers.isEmpty()) { return false; } for (Identifier identifier : identifiers) { if (!identifier.isName()) { return false; } } return true; } public boolean containsSingleNameIdentifier() { return containsNameIdentifiersOnly() && (identifiers.size() == 1); } public List<String> getNameIdentifiers() { if ((identifiers == null) || identifiers.isEmpty()) { return null; } List<String> names = new ArrayList<String>(); for (Identifier identifier : identifiers) { if (identifier.isName()) { names.add(identifier.getName()); } } return names; } public String getSingleNameIdentifier() { if (!containsSingleNameIdentifier()) { return null; } return (identifiers.get(0).toString()); } public boolean containsEmailIdentifiersOnly() { if (hasFilterPredicates()) { return false; } if ((identifiers == null) || identifiers.isEmpty()) { return false; } for (Identifier identifier : identifiers) { if (identifier.isEmail()) { return false; } } return true; } public boolean containsSingleEmailIdentifier() { return containsEmailIdentifiersOnly() && (identifiers.size() == 1); } public List<String> getEmailIdentifiers() { if ((identifiers == null) || identifiers.isEmpty()) { return null; } List<String> emails = new ArrayList<String>(); for (Identifier identifier : identifiers) { if (identifier.isEmail()) { emails.add(identifier.getEmail()); } } return emails; } public String getSingleEmailIdentifier() { if (!containsSingleEmailIdentifier()) { return null; } return (identifiers.get(0).toString()); } public boolean containsNameOrEmailIdentifiersOnly() { if (hasFilterPredicates()) { return false; } if ((identifiers == null) || identifiers.isEmpty()) { return false; } for (Identifier identifier : identifiers) { if (!identifier.isEmail() && !identifier.isName()) { return false; } } return true; } public boolean containsSingleNameOrEmailIdentifier() { return containsNameOrEmailIdentifiersOnly() && (identifiers.size() == 1); } public List<String> getNameAndEmailIdentifiers() { if ((identifiers == null) || identifiers.isEmpty()) { return null; } List<String> ids = new ArrayList<String>(); for (Identifier identifier : identifiers) { if (identifier.isEmail()) { ids.add(identifier.getEmail()); } else if (identifier.isName()) { ids.add(identifier.getName()); } } return ids; } public String getSingleNameOrEmailIdentifier() { if (!containsSingleNameOrEmailIdentifier()) { return null; } return (identifiers.get(0).toString()); } public List<String> getCategories() { return categories; } public void addCategory(String category) { if (categories == null) { categories = new ArrayList<String>(); } categories.add(category); } public void setCategories(List<String> categories) { this.categories = categories; } public List<CounterFilterPredicate> getCounterFilters() { return counterFilters; } public void addCounterFilter(String counter) { CounterFilterPredicate p = CounterFilterPredicate.fromString(counter); if (p == null) { return; } if (counterFilters == null) { counterFilters = new ArrayList<CounterFilterPredicate>(); } counterFilters.add(p); } public void setCounterFilters(List<CounterFilterPredicate> counterFilters) { this.counterFilters = counterFilters; } @Override public String toString() { if (selectSubjects.isEmpty() && filterPredicates.isEmpty()) { return ""; } StringBuilder s = new StringBuilder("select "); if (type == null) { if (selectSubjects.isEmpty()) { s.append("*"); } else { if (mergeSelectResults) { s.append("{ "); boolean first = true; for (Map.Entry<String, String> select : selectSubjects.entrySet()) { if (!first) { s.append(", "); } s.append(select.getValue() + " : " + select.getKey()); first = false; } s.append(" }"); } else { boolean first = true; for (String select : selectSubjects.keySet()) { if (!first) { s.append(", "); } s.append(select); first = false; } } } } else { s.append(type); } if (!filterPredicates.isEmpty()) { s.append(" where "); boolean first = true; for (FilterPredicate f : filterPredicates) { if (!first) { s.append(" and "); } s.append(f.toString()); first = false; } } return s.toString(); } public static enum FilterOperator { LESS_THAN("<", "lt"), LESS_THAN_OR_EQUAL("<=", "lte"), GREATER_THAN(">", "gt"), GREATER_THAN_OR_EQUAL(">=", "gte"), EQUAL("=", "eq"), NOT_EQUAL("!=", "ne"), IN("in", null), CONTAINS("contains", null), WITHIN("within", null); private final String shortName; private final String textName; FilterOperator(String shortName, String textName) { this.shortName = shortName; this.textName = textName; } static Map<String, FilterOperator> nameMap = new ConcurrentHashMap<String, FilterOperator>(); static { for (FilterOperator op : EnumSet.allOf(FilterOperator.class)) { if (op.shortName != null) { nameMap.put(op.shortName, op); } if (op.textName != null) { nameMap.put(op.textName, op); } } } public static FilterOperator find(String s) { if (s == null) { return null; } return nameMap.get(s); } @Override public String toString() { return shortName; } } public static enum SortDirection { ASCENDING, DESCENDING; public static SortDirection find(String s) { if (s == null) { return ASCENDING; } s = s.toLowerCase(); if (s.startsWith("asc")) { return ASCENDING; } if (s.startsWith("des")) { return DESCENDING; } if (s.equals("+")) { return ASCENDING; } if (s.equals("-")) { return DESCENDING; } return ASCENDING; } } public static final class SortPredicate implements Serializable { private static final long serialVersionUID = 1L; private final String propertyName; private final Query.SortDirection direction; public SortPredicate(String propertyName, Query.SortDirection direction) { if (propertyName == null) { throw new NullPointerException("Property name was null"); } if (direction == null) { direction = SortDirection.ASCENDING; } this.propertyName = propertyName.trim(); this.direction = direction; } public SortPredicate(String propertyName, String direction) { this(propertyName, SortDirection.find(direction)); } public String getPropertyName() { return propertyName; } public Query.SortDirection getDirection() { return direction; } public FilterPredicate toFilter() { return new FilterPredicate(propertyName, FilterOperator.EQUAL, "*"); } @Override public boolean equals(Object o) { if (this == o) { return true; } if ((o == null) || (super.getClass() != o.getClass())) { return false; } SortPredicate that = (SortPredicate) o; if (direction != that.direction) { return false; } return (propertyName.equals(that.propertyName)); } @Override public int hashCode() { int result = propertyName.hashCode(); result = (31 * result) + direction.hashCode(); return result; } @Override public String toString() { return propertyName + ((direction == Query.SortDirection.DESCENDING) ? " DESC" : ""); } } public static final class FilterPredicate implements Serializable { private static final long serialVersionUID = 1L; private final String propertyName; private final Query.FilterOperator operator; private final Object value; private String cursor; @SuppressWarnings({ "rawtypes", "unchecked" }) public FilterPredicate(String propertyName, Query.FilterOperator operator, Object value) { Assert.notNull(propertyName, "Property name was null"); Assert.notNull(operator, "Operator was null"); if ((operator == Query.FilterOperator.IN) || (operator == Query.FilterOperator.WITHIN)) { if ((!(value instanceof Collection)) && (value instanceof Iterable)) { List newValue = new ArrayList(); for (Object val : ((Iterable) value)) { newValue.add(val); } value = newValue; } // DataTypeUtils.checkSupportedValue(propertyName, value, true, // true); } else { // DataTypeUtils.checkSupportedValue(propertyName, value, false, // false); } this.propertyName = propertyName; this.operator = operator; this.value = value; } public FilterPredicate(String propertyName, String operator, String value, String secondValue, String thirdValue) { this.propertyName = propertyName; this.operator = FilterOperator.find(operator); Object first_obj = parseValue(value, 0); Object second_obj = parseValue(secondValue, 0); Object third_obj = parseValue(thirdValue, 0); if (second_obj != null) { if (third_obj != null) { this.value = Arrays.asList(first_obj, second_obj, third_obj); } else { this.value = Arrays.asList(first_obj, second_obj); } } else { this.value = first_obj; } } public FilterPredicate(String propertyName, String operator, String value, int valueType, String secondValue, int secondValueType, String thirdValue, int thirdValueType) { this.propertyName = propertyName; this.operator = FilterOperator.find(operator); Object first_obj = parseValue(value, valueType); Object second_obj = parseValue(secondValue, secondValueType); Object third_obj = parseValue(thirdValue, thirdValueType); if (second_obj != null) { if (third_obj != null) { this.value = Arrays.asList(first_obj, second_obj, third_obj); } else { this.value = Arrays.asList(first_obj, second_obj); } } else { this.value = first_obj; } } private static Object parseValue(String val, int valueType) { if (val == null) { return null; } if (val.startsWith("'") && (val.length() > 1)) { return val.substring(1, val.length() - 1); } if (val.equalsIgnoreCase("true") || val.equalsIgnoreCase("false")) { return Boolean.valueOf(val); } if (val.length() == 36) { try { return UUID.fromString(val); } catch (IllegalArgumentException e) { } } try { return Long.valueOf(val); } catch (NumberFormatException e) { } try { return Float.valueOf(val); } catch (NumberFormatException e) { } return null; } public static FilterPredicate valueOf(String str) { if (str == null) { return null; } try { ANTLRStringStream in = new ANTLRStringStream(str.trim()); QueryFilterLexer lexer = new QueryFilterLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); QueryFilterParser parser = new QueryFilterParser(tokens); FilterPredicate filter = parser.filter(); return normalize(filter); } catch (Exception e) { logger.error("Unable to parse \"" + str + "\"", e); } return null; } public static FilterPredicate normalize(FilterPredicate p) { if (p == null) { return null; } if (p.operator == FilterOperator.CONTAINS) { String propertyName = appendSuffix(p.propertyName, "keywords"); return new FilterPredicate(propertyName, FilterOperator.EQUAL, p.value); } else if (p.operator == FilterOperator.WITHIN) { String propertyName = appendSuffix(p.propertyName, "coordinates"); return new FilterPredicate(propertyName, FilterOperator.WITHIN, p.value); } return p; } private static String appendSuffix(String str, String suffix) { if (StringUtils.isNotEmpty(str)) { if (!str.endsWith("." + suffix)) { str += "." + suffix; } } else { str = suffix; } return str; } public String getPropertyName() { return propertyName; } public Query.FilterOperator getOperator() { return operator; } public Object getValue() { return value; } @SuppressWarnings("unchecked") public Object getStartValue() { if (value instanceof List) { List<Object> l = (List<Object>) value; return l.get(0); } if ((operator == FilterOperator.GREATER_THAN) || (operator == FilterOperator.GREATER_THAN_OR_EQUAL) || (operator == FilterOperator.EQUAL)) { return value; } else { return null; } } @SuppressWarnings("unchecked") public Object getFinishValue() { if (value instanceof List) { List<Object> l = (List<Object>) value; if (l.size() > 1) { return l.get(1); } return null; } if ((operator == FilterOperator.LESS_THAN) || (operator == FilterOperator.LESS_THAN_OR_EQUAL) || (operator == FilterOperator.EQUAL)) { return value; } else { return null; } } public void setCursor(String cursor) { this.cursor = cursor; } public String getCursor() { return cursor; } @Override public int hashCode() { final int prime = 31; int result = 1; result = (prime * result) + ((operator == null) ? 0 : operator.hashCode()); result = (prime * result) + ((propertyName == null) ? 0 : propertyName.hashCode()); result = (prime * result) + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FilterPredicate other = (FilterPredicate) obj; if (operator != other.operator) { return false; } if (propertyName == null) { if (other.propertyName != null) { return false; } } else if (!propertyName.equals(other.propertyName)) { return false; } if (value == null) { if (other.value != null) { return false; } } else if (!value.equals(other.value)) { return false; } return true; } @Override public String toString() { String valueStr = "\'\'"; if (value != null) { if (value instanceof String) { valueStr = "\'" + value + "\'"; } else { valueStr = value.toString(); } } return propertyName + " " + operator.toString() + " " + valueStr; } } public static final class CounterFilterPredicate implements Serializable { private static final long serialVersionUID = 1L; private final String name; private final Identifier user; private final Identifier group; private final String queue; private final String category; public CounterFilterPredicate(String name, Identifier user, Identifier group, String queue, String category) { this.name = name; this.user = user; this.group = group; this.queue = queue; this.category = category; } public Identifier getUser() { return user; } public Identifier getGroup() { return group; } public String getQueue() { return queue; } public String getCategory() { return category; } public String getName() { return name; } public static CounterFilterPredicate fromString(String s) { Identifier user = null; Identifier group = null; String category = null; String name = null; String[] l = split(s, ':'); if (l.length > 0) { if (!"*".equals(l[0])) { name = l[0]; } } if (l.length > 1) { if (!"*".equals(l[1])) { user = Identifier.from(l[1]); } } if (l.length > 2) { if (!"*".equals(l[2])) { group = Identifier.from(l[3]); } } if (l.length > 3) { if (!"*".equals(l[3])) { category = l[3]; } } if ((user == null) && (group == null) && (category == null) && (name == null)) { return null; } return new CounterFilterPredicate(name, user, group, null, category); } public static List<CounterFilterPredicate> fromList(List<String> l) { if ((l == null) || (l.size() == 0)) { return null; } List<CounterFilterPredicate> counterFilters = new ArrayList<CounterFilterPredicate>(); for (String s : l) { CounterFilterPredicate filter = CounterFilterPredicate.fromString(s); if (filter != null) { counterFilters.add(filter); } } if (counterFilters.size() == 0) { return null; } return counterFilters; } } public List<Object> getSelectionResults(Results rs) { List<Entity> entities = rs.getEntities(); if (entities == null) { return null; } if (!hasSelectSubjects()) { return cast(entities); } List<Object> results = new ArrayList<Object>(); for (Entity entity : entities) { if (isMergeSelectResults()) { boolean include = false; Map<String, Object> result = new LinkedHashMap<String, Object>(); Map<String, String> selects = getSelectAssignments(); for (Map.Entry<String, String> select : selects.entrySet()) { Object obj = JsonUtils.select(entity, select.getKey(), false); if (obj == null) { obj = ""; } else { include = true; } result.put(select.getValue(), obj); } if (include) { results.add(result); } } else { boolean include = false; List<Object> result = new ArrayList<Object>(); Set<String> selects = getSelectSubjects(); for (String select : selects) { Object obj = JsonUtils.select(entity, select); if (obj == null) { obj = ""; } else { include = true; } result.add(obj); } if (include) { results.add(result); } } } if (results.size() == 0) { return null; } return results; } public Object getSelectionResult(Results rs) { List<Object> r = getSelectionResults(rs); if ((r != null) && (r.size() > 0)) { return r.get(0); } return null; } }