Package com.codiform.moo.translator

Source Code of com.codiform.moo.translator.MapTranslator

package com.codiform.moo.translator;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.codiform.moo.TranslationException;
import com.codiform.moo.UnsupportedTranslationException;
import com.codiform.moo.configuration.Configuration;
import com.codiform.moo.property.MapProperty;
import com.codiform.moo.property.source.NoOpSourceProperty;
import com.codiform.moo.property.source.SourceProperty;
import com.codiform.moo.property.source.SourcePropertyFactory;
import com.codiform.moo.session.TranslationSource;

public class MapTranslator {

  private Configuration configuration;
  private Logger log;
  private SourcePropertyFactory sourcePropertyFactory;

  /**
   * Create a map translator.
   *
   * @param configuration
   *            configuration that may be relevant to the map translator
   * @param sourcePropertyFactory
   *            the source property factory used to retrieve source properties
   */
  public MapTranslator( Configuration configuration, SourcePropertyFactory sourcePropertyFactory ) {
    this.configuration = configuration;
    this.sourcePropertyFactory = sourcePropertyFactory;
    this.log = LoggerFactory.getLogger( getClass() );
  }

  public Object translate( Object value, MapProperty property, TranslationSource translationSource ) {
    if ( shouldTranslate( property ) ) {
      return translateMap( value, property, translationSource );
    } else if ( shouldCopy( property ) ) {
      return copy( value, property, translationSource );
    } else {
      if ( isCompatible( value, property ) ) {
        return value;
      } else {
        return copy( value, property, translationSource );
      }
    }
  }

  @SuppressWarnings( "unchecked" )
  private Object translateMap( Object value, MapProperty property, TranslationSource translationSource ) {
    if ( value instanceof Map ) {
      Object target = createTargetMap( value, property, translationSource );
      if ( target instanceof Map ) {
        translateMap( (Map<Object, Object>)value, (Map<Object, Object>)target, property, translationSource );
        return target;
      } else {
        throw new TranslationException( "Cannot translate map to target of type: " + target.getClass().getName() );
      }
    } else {
      throw new TranslationException( "Cannot translate map from type: " + value.getClass().getName() );
    }
  }

  private void translateMap( Map<Object, Object> source, Map<Object, Object> target, MapProperty property, TranslationSource translationSource ) {
    SourceProperty keySourceProperty = getSourceProperty( property.getKeySource() );
    SourceProperty valueSourceProperty = getSourceProperty( property.getValueSource() );
    for ( Map.Entry<Object, Object> entry : source.entrySet() ) {
      Object key, value;

      key = keySourceProperty.getValue( entry.getKey() );
      if ( key == null && !property.allowNullKeys() )
        continue;

      key = getKeyOrTranslation( key, property, translationSource );
      if ( key == null && !property.allowNullKeys() )
        continue;

      value = valueSourceProperty.getValue( entry.getValue() );
      value = getValueOrTranslation( value, property, translationSource );
      target.put( key, value );
    }
  }

  private Object getValueOrTranslation( Object value, MapProperty property, TranslationSource translationSource ) {
    if ( property.getValueClass() == null )
      return value;
    else
      return translationSource.getTranslation( value, property.getValueClass() );
  }

  private Object getKeyOrTranslation( Object key, MapProperty property, TranslationSource translationSource ) {
    if ( property.getKeyClass() == null )
      return key;
    else
      return translationSource.getTranslation( key, property.getKeyClass() );
  }

  @SuppressWarnings( "unchecked" )
  private Object copy( Object value, MapProperty property, TranslationSource translationSource ) {
    if ( value instanceof Map ) {
      Object target = createTargetMap( value, property, translationSource );
      if ( target instanceof Map ) {
        Map<Object, Object> targetMap = (Map<Object, Object>)target;
        targetMap.putAll( (Map<Object, Object>)value );
        return targetMap;
      } else {
        throw new TranslationException( "Cannot translate Map to target of type: " + target.getClass().getName() );
      }
    } else {
      throw new TranslationException( "Cannot translate collection from type: " + value.getClass().getName() );
    }
  }

  private Object createTargetMap( Object value, MapProperty property, TranslationSource cache ) {
    Class<? extends TranslationTargetFactory> factoryType = property.getFactory();
    TranslationTargetFactory factory = cache.getTranslationTargetFactory( factoryType );
    Object targetMap = factory.getTranslationTargetInstance( value, property.getType() );
    log.trace( "Target factory type {} created target map of type {} for source {}", factoryType, targetMap.getClass(), value );
    return targetMap;
  }

  private boolean isCompatible( Object value, MapProperty property ) {
    return property.getType().isInstance( value );
  }

  private boolean shouldCopy( MapProperty property ) {
    return !hasDefaultFactory( property ) || configuration.isPerformingDefensiveCopies();
  }

  private boolean hasDefaultFactory( MapProperty property ) {
    return property.getFactory() == DefaultMapTargetFactory.class;
  }

  private boolean shouldTranslate( MapProperty property ) {
    return property.getKeyClass() != null || property.getValueClass() != null || property.getKeySource() != null
        || property.getValueSource() != null;
  }

  @SuppressWarnings( "unchecked" )
  public void updateMap( Object source, Map<Object, Object> destinationMap, TranslationSource translationSource, MapProperty property ) {
    if ( source instanceof Map ) {
      Map<Object, Object> sourceMap = (Map<Object, Object>)source;
      updateMapByKey( sourceMap, destinationMap, translationSource, property );
    } else {
      throw new UnsupportedTranslationException( "Cannot update Map from " + source.getClass().getName() );
    }
  }

  private void updateMapByKey( Map<Object, Object> sourceMap, Map<Object, Object> destinationMap, TranslationSource translationSource,
      MapProperty property ) {
    SourceProperty keySourceProperty = getSourceProperty( property.getKeySource() );
    SourceProperty valueSourceProperty = getSourceProperty( property.getValueSource() );

    for ( Map.Entry<Object, Object> entry : sourceMap.entrySet() ) {
      Object key = entry.getKey();
      key = keySourceProperty.getValue( key );
      if ( key == null && !property.allowNullKeys() )
        continue;

      key = getKeyOrTranslation( key, property, translationSource );
      if ( key == null && !property.allowNullKeys() )
        continue;

      Object sourceValue = entry.getValue();
      sourceValue = valueSourceProperty.getValue( sourceValue );
      sourceValue = getValueOrTranslation( sourceValue, property, translationSource );

      Object destinationValue = destinationMap.get( key );
      if ( destinationValue != null && sourceValue != null ) {
        translationSource.update( sourceValue, destinationValue );
      } else {
        destinationMap.put( key, sourceValue );
      }
    }

    if ( property.shouldRemoveOrphans() ) {
      removeOrphans( sourceMap, destinationMap );
    }
  }

  private void removeOrphans( Map<Object, Object> sourceMap, Map<Object, Object> destinationMap ) {
    Set<Object> toRemove = new HashSet<Object>( destinationMap.keySet() );
    toRemove.removeAll( sourceMap.keySet() );
    for ( Object key : toRemove ) {
      destinationMap.remove( key );
    }
  }

  private SourceProperty getSourceProperty( String sourceExpression ) {
    if ( sourceExpression == null )
      return new NoOpSourceProperty();
    else
      return sourcePropertyFactory.getSourceProperty( sourceExpression );
  }

}
TOP

Related Classes of com.codiform.moo.translator.MapTranslator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.