/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.usergrid.persistence.index.impl;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import org.apache.usergrid.persistence.model.entity.Entity;
import org.apache.usergrid.persistence.model.field.ArrayField;
import org.apache.usergrid.persistence.model.field.BooleanField;
import org.apache.usergrid.persistence.model.field.ByteArrayField;
import org.apache.usergrid.persistence.model.field.DoubleField;
import org.apache.usergrid.persistence.model.field.EntityObjectField;
import org.apache.usergrid.persistence.model.field.Field;
import org.apache.usergrid.persistence.model.field.FloatField;
import org.apache.usergrid.persistence.model.field.IntegerField;
import org.apache.usergrid.persistence.model.field.ListField;
import org.apache.usergrid.persistence.model.field.LocationField;
import org.apache.usergrid.persistence.model.field.LongField;
import org.apache.usergrid.persistence.model.field.SetField;
import org.apache.usergrid.persistence.model.field.StringField;
import org.apache.usergrid.persistence.model.field.UUIDField;
import org.apache.usergrid.persistence.model.field.value.EntityObject;
import org.apache.usergrid.persistence.model.field.value.Location;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Test utility for creating entities from maps and vice versa.
*/
class EntityIndexMapUtils {
public static Entity fromMap( Map<String, Object> item ) {
return fromMap( null, item );
}
public static Entity fromMap( Entity entity, Map<String, Object> map ) {
if ( entity == null ) {
entity = new Entity();
}
for ( String fieldName : map.keySet() ) {
Object value = map.get( fieldName );
if ( value instanceof String ) {
entity.setField( new StringField( fieldName, (String)value ));
} else if ( value instanceof Boolean ) {
entity.setField( new BooleanField( fieldName, (Boolean)value ));
} else if ( value instanceof Integer ) {
entity.setField( new IntegerField( fieldName, (Integer)value ));
} else if ( value instanceof Double ) {
entity.setField( new DoubleField( fieldName, (Double)value ));
} else if ( value instanceof Float ) {
entity.setField( new FloatField( fieldName, (Float)value ));
} else if ( value instanceof Long ) {
entity.setField( new LongField( fieldName, (Long)value ));
} else if ( value instanceof List) {
entity.setField( listToListField( fieldName, (List)value ));
} else if ( value instanceof UUID) {
entity.setField( new UUIDField( fieldName, (UUID)value ));
} else if ( value instanceof Map ) {
// CpEntityMapUtils.processMapValue(value);
Field field = null;
//TODO remove this and use the code in CpEntityMapUtils.java
// is the map really a location element?
Map<String, Object> m = (Map<String, Object>)value;
if ( m.size() == 2) {
Double lat = null;
Double lon = null;
try {
if ( m.get("latitude") != null && m.get("longitude") != null ) {
lat = Double.parseDouble( m.get("latitude").toString() );
lon = Double.parseDouble( m.get("longitude").toString() );
} else if ( m.get("lat") != null && m.get("lon") != null ) {
lat = Double.parseDouble( m.get("lat").toString() );
lon = Double.parseDouble( m.get("lon").toString() );
}
} catch ( NumberFormatException ignored ) {}
if ( lat != null && lon != null ) {
field = new LocationField( fieldName, new Location( lat, lon ));
}
}
if ( field == null ) {
// not a location element, process it as map
entity.setField( new EntityObjectField( fieldName,
fromMap( (Map<String, Object>)value ))); // recursion
} else {
entity.setField( field );
}
} else if ( value instanceof Object) {
byte[] valueSerialized;
try {
ObjectMapper objectMapper = new ObjectMapper( );
valueSerialized = objectMapper.writeValueAsBytes( value );
}
catch ( JsonProcessingException e ) {
throw new RuntimeException( "Can't serialize object ",e );
}
catch ( IOException e ) {
throw new RuntimeException( "Can't serialize object ",e );
}
ByteBuffer byteBuffer = ByteBuffer.wrap( valueSerialized );
ByteArrayField ba = new ByteArrayField( fieldName, byteBuffer.array(), value.getClass() );
entity.setField( ba );
}
else {
throw new RuntimeException("Unknown type " + value.getClass().getName());
}
}
return entity;
}
private static ListField listToListField( String fieldName, List list ) {
if (list.isEmpty()) {
return new ArrayField( fieldName );
}
Object sample = list.get(0);
if ( sample instanceof Map ) {
return new ArrayField( fieldName, processListForField( list ));
} else if ( sample instanceof List ) {
return new ArrayField<List>( fieldName, processListForField( list ));
} else if ( sample instanceof String ) {
return new ArrayField<String>( fieldName, (List<String>)list );
} else if ( sample instanceof Boolean ) {
return new ArrayField<Boolean>( fieldName, (List<Boolean>)list );
} else if ( sample instanceof Integer ) {
return new ArrayField<Integer>( fieldName, (List<Integer>)list );
} else if ( sample instanceof Double ) {
return new ArrayField<Double>( fieldName, (List<Double>)list );
} else if ( sample instanceof Long ) {
return new ArrayField<Long>( fieldName, (List<Long>)list );
} else {
throw new RuntimeException("Unknown type " + sample.getClass().getName());
}
}
private static List processListForField( List list ) {
if ( list.isEmpty() ) {
return list;
}
Object sample = list.get(0);
if ( sample instanceof Map ) {
List<Entity> newList = new ArrayList<Entity>();
for ( Map<String, Object> map : (List<Map<String, Object>>)list ) {
newList.add( fromMap( map ) );
}
return newList;
} else if ( sample instanceof List ) {
return processListForField( list ); // recursion
} else {
return list;
}
}
/**
* Convert Entity to Map, adding version_ug_field and a {name}_ug_analyzed field for each
* StringField.
*/
public static Map toMap(EntityObject entity) {
Map<String, Object> entityMap = new TreeMap<String,Object>();
for (Object f : entity.getFields().toArray()) {
Field field = (Field) f;
if (f instanceof ListField || f instanceof ArrayField) {
List list = (List) field.getValue();
entityMap.put(field.getName(),
new ArrayList(processCollectionForMap(list)));
} else if (f instanceof SetField) {
Set set = (Set) field.getValue();
entityMap.put(field.getName(),
new ArrayList(processCollectionForMap(set)));
} else if (f instanceof EntityObjectField) {
EntityObject eo = (EntityObject) field.getValue();
entityMap.put(field.getName(), toMap(eo)); // recursion
} else if (f instanceof LocationField) {
LocationField locField = (LocationField) f;
Map<String, Object> locMap = new HashMap<String, Object>();
// field names lat and lon trigger ElasticSearch geo location
locMap.put("lat", locField.getValue().getLatitude());
locMap.put("lon", locField.getValue().getLongitude());
entityMap.put( field.getName(), locMap);
} else if (f instanceof ByteArrayField) {
ByteArrayField ba = ( ByteArrayField ) f;
ByteBuffer byteBuffer = ByteBuffer.wrap( ba.getValue() );
byte[] serilizedObj = byteBuffer.array();
Object o;
try {
ObjectMapper objectMapper = new ObjectMapper( );
o = objectMapper.readValue( serilizedObj, ba.getClassinfo() );
}
catch ( IOException e ) {
throw new RuntimeException( "Can't deserialize object ",e );
}
entityMap.put( ba.getName(), o );
}
else {
entityMap.put(field.getName(), field.getValue());
}
}
return entityMap;
}
private static Collection processCollectionForMap(Collection c) {
if (c.isEmpty()) {
return c;
}
List processed = new ArrayList();
Object sample = c.iterator().next();
if (sample instanceof Entity) {
for (Object o : c.toArray()) {
Entity e = (Entity) o;
processed.add(toMap(e));
}
} else if (sample instanceof List) {
for (Object o : c.toArray()) {
List list = (List) o;
processed.add(processCollectionForMap(list)); // recursion;
}
} else if (sample instanceof Set) {
for (Object o : c.toArray()) {
Set set = (Set) o;
processed.add(processCollectionForMap(set)); // recursion;
}
} else {
for (Object o : c.toArray()) {
processed.add(o);
}
}
return processed;
}
}