/* * Copyright (C) 2015 SoftIndex LLC. * * 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. */ package io.datakernel.cube.http; import com.google.gson.Gson; import com.google.gson.JsonParseException; import com.google.gson.TypeAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import io.datakernel.aggregation.AggregationPredicate; import java.io.IOException; import java.lang.reflect.Type; import java.util.List; import java.util.Map; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newLinkedHashMap; import static io.datakernel.aggregation.AggregationPredicates.*; final class AggregationPredicateGsonAdapter extends TypeAdapter<AggregationPredicate> { public static final String EQ = "eq"; public static final String BETWEEN = "between"; public static final String REGEXP = "regexp"; public static final String AND = "and"; public static final String OR = "or"; public static final String NOT = "not"; public static final String TRUE = "true"; public static final String FALSE = "false"; private final Map<String, TypeAdapter<?>> attributeAdapters; private AggregationPredicateGsonAdapter(Map<String, TypeAdapter<?>> attributeAdapters) { this.attributeAdapters = attributeAdapters; } public static AggregationPredicateGsonAdapter create(Gson gson, Map<String, Type> attributeTypes, Map<String, Type> measureTypes) { Map<String, TypeAdapter<?>> attributeAdapters = newLinkedHashMap(); for (String attribute : attributeTypes.keySet()) { TypeToken<?> typeToken = TypeToken.get(attributeTypes.get(attribute)); attributeAdapters.put(attribute, gson.getAdapter(typeToken)); } for (String measure : measureTypes.keySet()) { TypeToken<?> typeToken = TypeToken.get(measureTypes.get(measure)); attributeAdapters.put(measure, gson.getAdapter(typeToken)); } return new AggregationPredicateGsonAdapter(attributeAdapters); } @SuppressWarnings("unchecked") private void writeEq(JsonWriter writer, PredicateEq predicate) throws IOException { writer.name(predicate.getKey()); TypeAdapter typeAdapter = attributeAdapters.get(predicate.getKey()); typeAdapter.write(writer, predicate.getValue()); } @SuppressWarnings("unchecked") private void writeBetween(JsonWriter writer, PredicateBetween predicate) throws IOException { writer.value(predicate.getKey()); TypeAdapter typeAdapter = attributeAdapters.get(predicate.getKey()); typeAdapter.write(writer, predicate.getFrom()); typeAdapter.write(writer, predicate.getTo()); } @SuppressWarnings("unchecked") private void writeRegexp(JsonWriter writer, PredicateRegexp predicate) throws IOException { writer.value(predicate.getKey()); writer.value(predicate.getRegexp()); } @SuppressWarnings("unchecked") private void writeAnd(JsonWriter writer, PredicateAnd predicate) throws IOException { for (AggregationPredicate p : predicate.getPredicates()) { write(writer, p); } } @SuppressWarnings("unchecked") private void writeOr(JsonWriter writer, PredicateOr predicate) throws IOException { for (AggregationPredicate p : predicate.getPredicates()) { write(writer, p); } } @SuppressWarnings("unchecked") private void writeNot(JsonWriter writer, PredicateNot predicate) throws IOException { write(writer, predicate.getPredicate()); } @Override public void write(JsonWriter writer, AggregationPredicate predicate) throws IOException { if (predicate instanceof PredicateEq) { writer.beginObject(); writeEq(writer, (PredicateEq) predicate); writer.endObject(); } else { writer.beginArray(); if (predicate instanceof PredicateBetween) { writer.value(BETWEEN); writeBetween(writer, (PredicateBetween) predicate); } else if (predicate instanceof PredicateRegexp) { writer.value(REGEXP); writeRegexp(writer, (PredicateRegexp) predicate); } else if (predicate instanceof PredicateAnd) { writer.value(AND); writeAnd(writer, (PredicateAnd) predicate); } else if (predicate instanceof PredicateOr) { writer.value(OR); writeOr(writer, (PredicateOr) predicate); } else if (predicate instanceof PredicateNot) { writer.value(NOT); writeNot(writer, (PredicateNot) predicate); } else if (predicate instanceof PredicateAlwaysTrue) { writer.value(TRUE); } else if (predicate instanceof PredicateAlwaysFalse) { writer.value(FALSE); } else throw new IllegalArgumentException(); writer.endArray(); } } private AggregationPredicate readEqOfObject(JsonReader reader) throws IOException { List<AggregationPredicate> predicates = newArrayList(); while (reader.hasNext()) { String field = reader.nextName(); TypeAdapter typeAdapter = attributeAdapters.get(field); Object value = typeAdapter.read(reader); predicates.add(eq(field, value)); } return predicates.size() == 1 ? predicates.get(0) : and(predicates); } private AggregationPredicate readEq(JsonReader reader) throws IOException { String field = reader.nextString(); TypeAdapter typeAdapter = attributeAdapters.get(field); Object value = typeAdapter.read(reader); return eq(field, value); } private AggregationPredicate readBetween(JsonReader reader) throws IOException { String field = reader.nextString(); TypeAdapter typeAdapter = attributeAdapters.get(field); Comparable from = (Comparable) typeAdapter.read(reader); Comparable to = (Comparable) typeAdapter.read(reader); return between(field, from, to); } private AggregationPredicate readRegexp(JsonReader reader) throws IOException { String field = reader.nextString(); String regexp = reader.nextString(); return regexp(field, regexp); } private AggregationPredicate readAnd(JsonReader reader) throws IOException { List<AggregationPredicate> predicates = newArrayList(); while (reader.hasNext()) { AggregationPredicate predicate = read(reader); predicates.add(predicate); } return and(predicates); } private AggregationPredicate readOr(JsonReader reader) throws IOException { List<AggregationPredicate> predicates = newArrayList(); while (reader.hasNext()) { AggregationPredicate predicate = read(reader); predicates.add(predicate); } return or(predicates); } private AggregationPredicate readNot(JsonReader reader) throws IOException { AggregationPredicate predicate = read(reader); return not(predicate); } @Override public AggregationPredicate read(JsonReader reader) throws IOException { AggregationPredicate predicate = null; if (reader.peek() == JsonToken.BEGIN_OBJECT) { reader.beginObject(); predicate = readEqOfObject(reader); reader.endObject(); } else { reader.beginArray(); String type = reader.nextString(); if (EQ.equals(type)) predicate = readEq(reader); if (BETWEEN.equals(type)) predicate = readBetween(reader); if (REGEXP.equals(type)) predicate = readRegexp(reader); if (AND.equals(type)) predicate = readAnd(reader); if (OR.equals(type)) predicate = readOr(reader); if (NOT.equals(type)) predicate = readNot(reader); if (TRUE.equals(type)) predicate = alwaysTrue(); if (FALSE.equals(type)) predicate = alwaysFalse(); if (predicate == null) throw new JsonParseException("Unknown predicate type " + type); reader.endArray(); } return predicate; } }