All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.oneandone.troilus.UDTValueMapper Maven / Gradle / Ivy

There is a newer version: 0.18
Show newest version
/*
 * Copyright 1&1 Internet AG, https://github.com/1and1/
 * 
 * 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 net.oneandone.troilus;



import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;

import com.datastax.driver.core.DataType;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.TupleType;
import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType;
import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;



class UDTValueMapper {

    private final ProtocolVersion protocolVersion;
    private final BeanMapper beanMapper;
    
    UDTValueMapper(ProtocolVersion protocolVersion, BeanMapper beanMapper) {
        this.protocolVersion = protocolVersion;
        this.beanMapper = beanMapper;
    }
    
    
    
    private UserType getUserType(LoadingCache userTypeCache, String usertypeName) {
        try {
            return userTypeCache.get(usertypeName);
        } catch (ExecutionException e) {
            throw new RuntimeException(e.getCause());
        }
    }
    


    static boolean isBuildInType(DataType dataType) {        
        if (dataType.isCollection()) {
            for (DataType type : dataType.getTypeArguments()) {
                if (!isBuildInType(type)) {
                    return false;
                }
            }
            return true;

        } else {
            return DataType.allPrimitiveTypes().contains(dataType) || (TupleType.class.isAssignableFrom(dataType.getClass()));
        }
    }
    
    
    
    /**
     * @param datatype   the db datatype
     * @param udtValue   the udt value
     * @param fieldtype1 the field 1 type
     * @param fieldtype2 the field 2 type
     * @param fieldname  the fieldname
     * @return the mapped value or null
     */
    public Object fromUdtValue(DataType datatype, 
                               UDTValue udtValue,
                               Class fieldtype1, 
                               Class fieldtype2,
                               String fieldname) {
        
        // build-in type 
        if (isBuildInType(datatype)) {
            return datatype.deserialize(udtValue.getBytesUnsafe(fieldname), protocolVersion);
        
            
        // udt collection    
        } else if (datatype.isCollection()) {
            Class type = datatype.getName().asJavaClass();
           
            // set
            if (Set.class.isAssignableFrom(type)) {
                return fromUdtValues(datatype.getTypeArguments().get(0), 
                                     ImmutableSet.copyOf(udtValue.getSet(fieldname, UDTValue.class)), 
                                     fieldtype1); 
                
            // list
            } else if (List.class.isAssignableFrom(type)) {
                return fromUdtValues(datatype.getTypeArguments().get(0), 
                                     ImmutableList.copyOf(udtValue.getList(fieldname, UDTValue.class)),
                                     fieldtype1); 

            // map
            } else {
                if (isBuildInType(datatype.getTypeArguments().get(0))) {
                    return fromUdtValues(datatype.getTypeArguments().get(0), 
                                         datatype.getTypeArguments().get(1), 
                                         ImmutableMap.copyOf(udtValue.getMap(fieldname, fieldtype1, UDTValue.class)), 
                                         fieldtype1, 
                                         fieldtype2);

                } else if (isBuildInType(datatype.getTypeArguments().get(1))) {
                    return fromUdtValues(datatype.getTypeArguments().get(0), 
                                         datatype.getTypeArguments().get(1), 
                                         ImmutableMap.copyOf(udtValue.getMap(fieldname, UDTValue.class, fieldtype2)), 
                                         fieldtype1, 
                                         fieldtype2);
                    
                } else {
                    return fromUdtValues(datatype.getTypeArguments().get(0), 
                                         datatype.getTypeArguments().get(1), 
                                         ImmutableMap.copyOf(udtValue.getMap(fieldname, UDTValue.class, UDTValue.class)),
                                         fieldtype1, 
                                         fieldtype2);
                }
            }
                        
        // udt    
        } else {
            return fromUdtValue(datatype, udtValue, fieldtype1);
        }
    }
    

    
    public  T fromUdtValue(final DataType datatype, final UDTValue udtValue, Class type) {
        
        PropertiesSource propsSource = new PropertiesSource() {
            
            @Override
            public  Optional read(String name, Class clazz1) {
                return read(name, clazz1, Object.class);
            }
            
            @SuppressWarnings("unchecked")
            @Override
            public  Optional read(String name, Class clazz1, Class clazz2) {
                return Optional.fromNullable((E) fromUdtValue(((UserType) datatype).getFieldType(name), udtValue, clazz1, clazz2, name));
            }
        };
        
        return beanMapper.fromValues(type, propsSource, ImmutableSet.of());
    }

    
    public  ImmutableSet fromUdtValues(final DataType datatype, ImmutableSet udtValues, Class type) {
        return ImmutableSet.copyOf(fromUdtValues(datatype, (ImmutableCollection) udtValues, type));
    }

    
    public  ImmutableList fromUdtValues(final DataType datatype, ImmutableList udtValues, Class type) {
        return fromUdtValues(datatype, (ImmutableCollection) udtValues, type);
    }

    
    private  ImmutableList fromUdtValues(final DataType datatype, ImmutableCollection udtValues, Class type) {
        List elements = Lists.newArrayList();
        
        for (UDTValue elementUdtValue : udtValues) {
            
            final UDTValue elementUdtVal = elementUdtValue;
            
            PropertiesSource propsSource = new PropertiesSource() {
                
                @Override
                public  Optional read(String name, Class clazz1) {
                    return read(name, clazz1, Object.class);
                }
                
                @SuppressWarnings("unchecked")
                @Override
                public  Optional  read(String name, Class clazz1, Class clazz2) {
                    return Optional.fromNullable((E) fromUdtValue(((UserType) datatype).getFieldType(name), elementUdtVal, clazz1, clazz2, name));
                }
            };

            
            T element = beanMapper.fromValues(type, propsSource, ImmutableSet.of());
            elements.add(element);
        }
        
        return ImmutableList.copyOf(elements);
    }
    
    
    
    @SuppressWarnings("unchecked")
    public  ImmutableMap fromUdtValues(final DataType keyDatatype, final DataType valueDatatype, ImmutableMap udtValues, Class keystype, Class valuesType) {
        
        Map elements = Maps.newHashMap();

        for (Entry entry : udtValues.entrySet()) {
        
            K keyElement;
            if (keystype.isAssignableFrom(entry.getKey().getClass())) {
                keyElement = (K) entry.getKey(); 
                
            } else {
                final UDTValue keyUdtValue = (UDTValue) entry.getKey();
                
                PropertiesSource propsSource = new PropertiesSource() {
                    
                    @Override
                    public  Optional read(String name, Class clazz1) {
                        return read(name, clazz1, Object.class);
                    }
                    
                    @Override
                    public  Optional read(String name, Class clazz1, Class clazz2) {
                        return Optional.fromNullable((T) fromUdtValue(((UserType) keyDatatype).getFieldType(name), keyUdtValue, clazz1, clazz2, name));
                    }
                };

                keyElement = beanMapper.fromValues(keystype, propsSource, ImmutableSet.of());
            }
            
            
            
            V valueElement;
            if (valuesType.isAssignableFrom(entry.getValue().getClass())) {
                valueElement = (V) entry.getValue();
                
            } else {
                final UDTValue valueUdtValue = (UDTValue) entry.getValue();

                PropertiesSource propsSource = new PropertiesSource() {
                    
                    @Override
                    public  Optional read(String name, Class clazz1) {
                        return read(name, clazz1, Object.class);
                    }
                    
                    @Override
                    public  Optional read(String name, Class clazz1, Class clazz2) {
                        return Optional.fromNullable((T) fromUdtValue(((UserType) valueDatatype).getFieldType(name), valueUdtValue, clazz1, clazz2, name));
                    }
                };
                
                valueElement = beanMapper.fromValues(valuesType, propsSource, ImmutableSet.of());
            }

            elements.put(keyElement, valueElement);
        }
        
        return ImmutableMap.copyOf(elements);
    }
    
    
    @SuppressWarnings("unchecked")
    public Object toUdtValue(LoadingCache userTypeCache, 
                             DataType datatype, 
                             Object value) {
        
        // build-in type (will not be converted)
        if (isBuildInType(datatype)) {
            return value;
            
        // udt collection
        } else if (datatype.isCollection()) {
           
           // set 
           if (Set.class.isAssignableFrom(datatype.getName().asJavaClass())) {
               DataType elementDataType = datatype.getTypeArguments().get(0);
               
               Set udt = Sets.newHashSet();
               if (value != null) {
                   for (Object element : (Set) value) {
                       udt.add(toUdtValue(userTypeCache, elementDataType, element));
                   }
               }
               
               return ImmutableSet.copyOf(udt);
               
           // list 
           } else if (List.class.isAssignableFrom(datatype.getName().asJavaClass())) {
               DataType elementDataType = datatype.getTypeArguments().get(0);
               
               List udt = Lists.newArrayList();
               if (value != null) {
                   for (Object element : (List) value) {
                       udt.add(toUdtValue(userTypeCache, elementDataType, element));
                   }
               }
               
               return ImmutableList.copyOf(udt);
              
           // map
           } else {
               DataType keyDataType = datatype.getTypeArguments().get(0);
               DataType valueDataType = datatype.getTypeArguments().get(1);
               
               Map udt = Maps.newHashMap();
               if (value != null) {
                   for (Entry entry : ((Map) value).entrySet()) {
                         udt.put(toUdtValue(userTypeCache, keyDataType, entry.getKey()), 
                                 toUdtValue(userTypeCache, valueDataType, entry.getValue()));
                   }
               
               }
               return ImmutableMap.copyOf(udt);  
           }
    
           
        // udt
        } else {
            if (value == null) {
                return value;
                
            } else {
                UserType usertype = getUserType(userTypeCache, ((UserType) datatype).getTypeName());
                UDTValue udtValue = usertype.newValue();
                
                for (Entry> entry : beanMapper.toValues(value, ImmutableSet.of()).entrySet()) {
                    if (!entry.getValue().isPresent()) {
                        return null;
                    }

                    DataType fieldType = usertype.getFieldType(entry.getKey());
                    Object vl = entry.getValue().get();
                    
                    if (!isBuildInType(usertype.getFieldType(entry.getKey()))) {
                        vl = toUdtValue(userTypeCache, fieldType, vl);
                    }
                    
                    udtValue.setBytesUnsafe(entry.getKey(), fieldType.serialize(vl, protocolVersion));
                }
                
                return udtValue;
            }
        }
    }
}