/* * Copyright (c) 2017 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.magma.datasource.mongodb.converter; import java.util.Collection; import javax.annotation.Nullable; import org.bson.BSONObject; import org.obiba.magma.Coordinate; import org.obiba.magma.MagmaDate; import org.obiba.magma.Value; import org.obiba.magma.ValueType; import org.obiba.magma.Variable; import org.obiba.magma.datasource.mongodb.MongoDBVariable; import org.obiba.magma.type.LineStringType; import org.obiba.magma.type.LocaleType; import org.obiba.magma.type.PointType; import org.obiba.magma.type.PolygonType; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.mongodb.BasicDBList; public class ValueConverter { private ValueConverter() {} public static Object marshall(Variable variable, Value value) { if(value == null || value.isNull()) return null; if(variable.isRepeatable()) { Collection<Object> list = new BasicDBList(); for(Value val : value.asSequence().getValues()) { list.add(marshall(val)); } return list; } return marshall(value); } public static Value unmarshall(MongoDBVariable variable, BSONObject object) { return unmarshall(variable.getValueType(), variable.isRepeatable(), variable.getId(), object); } public static Value unmarshall(ValueType type, boolean repeatable, String field, BSONObject object) { if(object == null || !object.containsField(field)) { return repeatable ? type.nullSequence() : type.nullValue(); } if(repeatable) { Iterable<?> values = (Iterable<?>) object.get(field); if(values == null) return type.nullSequence(); ImmutableList.Builder<Value> list = ImmutableList.builder(); for(Object o : values) { list.add(unmarshall(type, o)); } return type.sequenceOf(list.build()); } return unmarshall(type, object.get(field)); } public static Value unmarshall(ValueType type, Object value) { if(value == null) return type.nullValue(); if(type.isGeo()) { // will be turned to a JSON string return type.valueOf(value.toString()); } return type.valueOf(value); } // // Private methods // private static Object marshall(Value value) { if(value == null || value.isNull()) return null; ValueType type = value.getValueType(); Object rawValue = value.getValue(); if(rawValue instanceof MagmaDate) { return ((MagmaDate) rawValue).asDate(); } if(type.isGeo()) { return marshallGeo(value); } return type.equals(LocaleType.get()) ? type.toString(value) : value.getValue(); } @SuppressWarnings("unchecked") private static Object marshallGeo(Value value) { if(value == null || value.isNull()) return null; ValueType type = value.getValueType(); if(PointType.get().equals(type)) { return marshallPoint((Coordinate) value.getValue()); } if(LineStringType.get().equals(type)) { return marshallLine((Iterable<Coordinate>) value.getValue()); } if(PolygonType.get().equals(type)) { return marshallPolygon((Iterable<Iterable<Coordinate>>) value.getValue()); } throw new RuntimeException("Geo value type expected: " + value.getValueType()); } private static Object marshallPoint(Coordinate point) { return point.toArray(); } private static Iterable<double[]> marshallLine(Iterable<Coordinate> line) { return Iterables.transform(line, new Function<Coordinate, double[]>() { @Nullable @Override public double[] apply(@Nullable Coordinate input) { return input == null ? null : input.toArray(); } }); } private static Object marshallPolygon(Iterable<Iterable<Coordinate>> line) { return Iterables.transform(line, new Function<Iterable<Coordinate>, Iterable<double[]>>() { @Nullable @Override public Iterable<double[]> apply(@Nullable Iterable<Coordinate> input) { return input == null ? null : marshallLine(input); } }); } }