/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.core.portal.datasource.handler.base;
import java.lang.reflect.Field;
import java.util.Map;
import javax.annotation.Nonnull;
import com.google.common.collect.Maps;
import com.enonic.cms.core.portal.datasource.DataSourceException;
final class ParameterBeanMapper<T>
{
private final Class<T> type;
private final String dsName;
private final Map<String, Field> fields;
private ParameterBeanMapper( final Class<T> type, final String dsName )
{
this.type = type;
this.dsName = dsName;
this.fields = Maps.newHashMap();
initializeMappings();
}
private void initializeMappings()
{
for ( final Field field : this.type.getFields() )
{
this.fields.put( field.getName(), field );
}
}
public T newBean( final Map<String, String> params )
{
final T bean = newParamsBean();
applyParams( bean, params );
checkRequired( bean );
return bean;
}
private T newParamsBean()
{
try
{
return this.type.newInstance();
}
catch ( final Exception e )
{
throw new DataSourceException( "Failed to create params bean for data source [{0}]", this.dsName ).withCause( e );
}
}
private void applyParams( final T bean, final Map<String, String> params )
{
for ( final Map.Entry<String, String> entry : params.entrySet() )
{
applyParam( bean, entry.getKey(), entry.getValue() );
}
}
private void applyParam( final T bean, final String name, final String value )
{
final Field field = this.fields.get( name );
if ( field == null )
{
throw new DataSourceException( "No such parameter [{0}] for data source [{1}]", name, this.dsName );
}
try
{
final Object convertedValue = ParameterConverter.getInstance().convert( value, field.getType() );
field.set( bean, convertedValue );
}
catch ( final Exception e )
{
throw new DataSourceException( "Could not set parameter [{0}] for data source [{1}]", name, this.dsName ).withCause( e );
}
}
private void checkRequired( final T bean )
{
for ( final Field field : this.fields.values() )
{
checkRequired( bean, field );
}
}
private void checkRequired( final T bean, final Field field )
{
final boolean required = field.getAnnotation( Nonnull.class ) != null;
if ( required && isNullValue( bean, field ) )
{
throw new DataSourceException( "Parameter [{0}] is required for data source [{1}]", field.getName(), this.dsName );
}
}
private boolean isNullValue( final T bean, final Field field )
{
try
{
return field.get( bean ) == null;
}
catch ( final Exception e )
{
return false;
}
}
public static <T> ParameterBeanMapper<T> create( final Class<T> type, final String dsName )
{
return new ParameterBeanMapper<T>( type, dsName );
}
}