/*******************************************************************************
* Copyright (c) 2014, 2015 IBH SYSTEMS GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBH SYSTEMS GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.packagedrone.repo;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.packagedrone.utils.converter.ConverterManager;
/**
* Helper methods when working with {@link MetaKey}s
*/
public final class MetaKeys
{
private MetaKeys ()
{
}
/**
* Get a string from meta data
* <p>
* If the provided metadata set is <code>null</code>, then the result will
* also be <code>null</code>.
* </p>
*
* @param metadata
* the meta data map, may be <code>null</code>
* @param ns
* the namespace
* @param key
* the key
* @return the value, as string, may be <code>null</code>
*/
public static String getString ( final Map<MetaKey, String> metadata, final String ns, final String key )
{
return getString ( metadata, ns, key, null );
}
/**
* Get a string from meta data
* <p>
* If the provided metadata set is <code>null</code>, then the result will
* also be <code>null</code>.
* </p>
*
* @param metadata
* the meta data map, may be <code>null</code>
* @param ns
* the namespace
* @param key
* the key
* @param defaultValue
* the value returned if either the metadata parmeter is
* <code>null</code> or the metadata does not contain this key or
* the value is <code>null</code>
* @return the value, as string, may be <code>null</code>
*/
public static String getString ( final Map<MetaKey, String> metadata, final String ns, final String key, final String defaultValue )
{
if ( metadata == null )
{
return defaultValue;
}
final String result = metadata.get ( new MetaKey ( ns, key ) );
if ( result == null )
{
return defaultValue;
}
return result;
}
public static <T> T bind ( final T data, final Map<MetaKey, String> metadata ) throws Exception
{
final ConverterManager converter = ConverterManager.create ();
if ( data == null )
{
return null;
}
final List<Field> fields = new LinkedList<> ();
findFields ( data.getClass (), fields );
for ( final Field field : fields )
{
final MetaKeyBinding mkb = field.getAnnotation ( MetaKeyBinding.class );
final String stringValue = metadata.get ( new MetaKey ( mkb.namespace (), mkb.key () ) );
final Object value;
if ( stringValue == null )
{
value = null;
}
else
{
if ( !mkb.converterClass ().isInterface () )
{
value = mkb.converterClass ().newInstance ().decode ( stringValue );
}
else
{
value = converter.convertTo ( stringValue, field.getType () );
}
}
if ( value != null || !mkb.ignoreNull () )
{
setValue ( field, data, value );
}
}
return data;
}
public static final Map<MetaKey, String> unbind ( final Object data ) throws Exception
{
final ConverterManager converter = ConverterManager.create ();
if ( data == null )
{
return null;
}
final List<Field> fields = new LinkedList<> ();
findFields ( data.getClass (), fields );
final Map<MetaKey, String> result = new HashMap<> ( fields.size () );
for ( final Field field : fields )
{
final MetaKeyBinding mkb = field.getAnnotation ( MetaKeyBinding.class );
final Object value = getValue ( field, data );
final String stringValue;
if ( !mkb.converterClass ().isInterface () )
{
final BindingConverter cvt = mkb.converterClass ().newInstance ();
stringValue = cvt.encode ( value );
}
else
{
stringValue = converter.convertTo ( value, String.class );
}
if ( ( stringValue == null || stringValue.isEmpty () ) && mkb.emptyAsNull () )
{
result.put ( new MetaKey ( mkb.namespace (), mkb.key () ), null );
}
else
{
result.put ( new MetaKey ( mkb.namespace (), mkb.key () ), stringValue );
}
}
return result;
}
private static Object getValue ( final Field field, final Object data ) throws IllegalArgumentException, IllegalAccessException
{
if ( field.isAccessible () )
{
return field.get ( data );
}
else
{
field.setAccessible ( true );
try
{
return field.get ( data );
}
finally
{
field.setAccessible ( false );
}
}
}
private static void setValue ( final Field field, final Object target, final Object value ) throws IllegalArgumentException, IllegalAccessException
{
if ( field.isAccessible () )
{
internalSetField ( field, target, value );
}
else
{
field.setAccessible ( true );
try
{
internalSetField ( field, target, value );
}
finally
{
field.setAccessible ( false );
}
}
}
protected static void internalSetField ( final Field field, final Object target, final Object value ) throws IllegalAccessException
{
if ( value != null || !field.getType ().isPrimitive () )
{
field.set ( target, value );
}
}
private static void findFields ( final Class<?> clazz, final List<Field> result ) throws SecurityException
{
if ( clazz == null )
{
return;
}
for ( final Field f : clazz.getDeclaredFields () )
{
if ( f.isAnnotationPresent ( MetaKeyBinding.class ) )
{
result.add ( f );
}
}
findFields ( clazz.getSuperclass (), result );
}
public static Map<MetaKey, String> union ( final Map<MetaKey, String> providedMetaData, final Map<MetaKey, String> extractedMetaData )
{
final int size1 = providedMetaData != null ? providedMetaData.size () : 0;
final int size2 = extractedMetaData != null ? extractedMetaData.size () : 0;
final Map<MetaKey, String> result = new HashMap<> ( size1 + size2 );
if ( extractedMetaData != null )
{
result.putAll ( extractedMetaData );
}
// provided will override
if ( providedMetaData != null )
{
result.putAll ( providedMetaData );
}
return Collections.unmodifiableMap ( result );
}
}