454 lines
16 KiB
C#
454 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
namespace com.itac.mes.imsapi
|
|
{
|
|
/// <summary>
|
|
/// tool fuer das automatische Mapping von Werten in Strukturen nach String-Arrays und umgekehrt
|
|
///
|
|
/// Prinzip uebernommen aus dem ImsInterfaces, Klasse ImsApiMapTool
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
public class ImsApiMapTool<T>
|
|
{
|
|
|
|
// von einem Typ
|
|
private static Dictionary<Type, Dictionary<String, FieldInfo>> fieldMapperTable = new Dictionary<Type, Dictionary<String, FieldInfo>>();
|
|
private static Dictionary<Type, Dictionary<String, PropertyInfo>> propertyMapperTable = new Dictionary<Type, Dictionary<String, PropertyInfo>>();
|
|
|
|
public static void clearClassCache(Type clazz)
|
|
{
|
|
Dictionary<String, FieldInfo> fieldKeyMapper = null;
|
|
if (fieldMapperTable.ContainsKey(clazz))
|
|
{
|
|
fieldKeyMapper = fieldMapperTable[clazz];
|
|
fieldMapperTable.Remove(clazz);
|
|
}
|
|
Dictionary<String, PropertyInfo> propertyKeyMapper = null;
|
|
if (propertyMapperTable.ContainsKey(clazz))
|
|
{
|
|
propertyKeyMapper = propertyMapperTable[clazz];
|
|
propertyMapperTable.Remove(clazz);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// eine Abbildungstabelle fuer einen Typ ermitteln (Namen von Feldern und IMSAPI-Keys)
|
|
/// </summary>
|
|
/// <param name="clazz"></param>
|
|
/// <returns></returns>
|
|
protected Dictionary<String, FieldInfo> getFieldMapperTable(Type clazz)
|
|
{
|
|
Dictionary<String, FieldInfo> keyMapper = null;
|
|
if (fieldMapperTable.ContainsKey(clazz))
|
|
{
|
|
keyMapper = fieldMapperTable[clazz];
|
|
}
|
|
else
|
|
{
|
|
keyMapper = new Dictionary<String, FieldInfo>();
|
|
// welche ImsApiKeys werden auf welche Fields abgebildet
|
|
// iterate over all fields
|
|
FieldInfo[] fields = clazz.GetFields();
|
|
foreach (FieldInfo field in fields)
|
|
{
|
|
// get relevant annotation
|
|
object[] annotation = field.GetCustomAttributes(typeof(ImsApiKey), true);
|
|
if (annotation != null && annotation.Length > 0)
|
|
{
|
|
// add field mappings
|
|
keyMapper.Add(((ImsApiKey)annotation[0]).Key, field);
|
|
}
|
|
}
|
|
fieldMapperTable.Add(clazz, keyMapper);
|
|
}
|
|
return keyMapper;
|
|
}
|
|
|
|
protected Dictionary<String, PropertyInfo> getPropertyMapperTable(Type clazz)
|
|
{
|
|
Dictionary<String, PropertyInfo> keyMapper = null;
|
|
if (propertyMapperTable.ContainsKey(clazz))
|
|
{
|
|
keyMapper = propertyMapperTable[clazz];
|
|
}
|
|
else
|
|
{
|
|
keyMapper = new Dictionary<String, PropertyInfo>();
|
|
// welche ImsApiKeys werden auf welche Fields abgebildet
|
|
// iterate over all fields
|
|
PropertyInfo[] properties = clazz.GetProperties();
|
|
foreach (PropertyInfo property in properties)
|
|
{
|
|
// get relevant annotation
|
|
object[] annotation = property.GetCustomAttributes(typeof(ImsApiKey), true);
|
|
if (annotation != null && annotation.Length > 0)
|
|
{
|
|
// add field mappings
|
|
keyMapper.Add(((ImsApiKey)annotation[0]).Key, property);
|
|
}
|
|
}
|
|
propertyMapperTable.Add(clazz, keyMapper);
|
|
}
|
|
return keyMapper;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// aus einem String-Array mit Keys und Werten eine Struktur erzeugen.
|
|
/// alle Felder in der Struktur muessen dafuer mit dem Attribut [IMSAPIKEY]
|
|
/// versehen sein
|
|
/// </summary>
|
|
/// <param name="clazz"></param>
|
|
/// <param name="imsApiKeys"></param>
|
|
/// <param name="imsApiValues"></param>
|
|
/// <returns></returns>
|
|
public T getStruct(Type clazz, string[] imsApiKeys, string[] imsApiValues)
|
|
{
|
|
if (clazz == null)
|
|
{
|
|
throw new ArgumentException("parameter clazz must not be null");
|
|
}
|
|
if (imsApiKeys == null)
|
|
{
|
|
throw new ArgumentException("parameter imsApiKeys must not be null");
|
|
}
|
|
if (imsApiValues == null)
|
|
{
|
|
throw new ArgumentException("parameter imsApiValues must not be null");
|
|
}
|
|
// Anzahl der Werte muss identisch sein mit der Anzahl der Keys
|
|
if (imsApiKeys.Length != imsApiValues.Length)
|
|
{
|
|
throw new ArgumentException("parameter imsApiKeys and imsApiValues must have the same size");
|
|
}
|
|
Dictionary<String, FieldInfo> keyMapper = getFieldMapperTable(clazz);
|
|
Dictionary<String, PropertyInfo> propertyKeyMapper = getPropertyMapperTable(clazz);
|
|
|
|
T instance = getInstance(clazz, imsApiKeys, imsApiValues, keyMapper, propertyKeyMapper, 0);
|
|
|
|
return instance;
|
|
}
|
|
|
|
|
|
|
|
private T getInstance(Type clazz, String[] imsApiKeys, String[] imsApiValues, Dictionary<String, FieldInfo> keyMapper,
|
|
Dictionary<String, PropertyInfo> propertyMapper, int baseIndex)
|
|
{
|
|
T instance = (T)Activator.CreateInstance(clazz);
|
|
// now map all keyValues to fields
|
|
for (int index = 0; index < imsApiKeys.Length; index++)
|
|
{
|
|
String key = imsApiKeys[index];
|
|
String sValue = imsApiValues[baseIndex + index];
|
|
if (!keyMapper.ContainsKey(key))
|
|
{
|
|
// dieser key ist nicht zur Abbildung definiert, d.h. es gibt keine Annotation in der Zielklasse mit diesem Key
|
|
if (!propertyMapper.ContainsKey(key))
|
|
{
|
|
continue;
|
|
}
|
|
PropertyInfo propInfo = propertyMapper[key];
|
|
safeSetProperty(instance, propInfo, sValue);
|
|
|
|
continue;
|
|
}
|
|
FieldInfo f = keyMapper[key];
|
|
safeSetField(instance, f, sValue);
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// aus einem String-Array mit Keys und Werten ein Array von Strukturen erzeugen.
|
|
/// alle Felder in der Struktur muessen dafuer mit dem Attribut [IMSAPIKEY]
|
|
/// versehen sein
|
|
/// </summary>
|
|
/// <param name="clazz"></param>
|
|
/// <param name="imsApiKeys"></param>
|
|
/// <param name="imsApiValues"></param>
|
|
/// <returns></returns>
|
|
public T[] getArray(Type clazz, String[] imsApiKeys, String[] imsApiValues)
|
|
{
|
|
// Check parameters
|
|
if (clazz == null)
|
|
{
|
|
throw new ArgumentException("parameter clazz must not be null");
|
|
}
|
|
if (imsApiKeys == null)
|
|
{
|
|
throw new ArgumentException("parameter imsApiKeys must not be null");
|
|
}
|
|
if (imsApiValues == null || imsApiValues.Length == 0)
|
|
{
|
|
throw new ArgumentException("parameter imsApiValues must not be null");
|
|
}
|
|
// Anzahl der Werte muss ein ganzzahliges Vielfaches der Anzahl der Keys sein
|
|
if ((imsApiValues.Length % imsApiKeys.Length) != 0)
|
|
{
|
|
throw new ArgumentException("parameter imsApiValues must be a multiple of imsApiKeys");
|
|
}
|
|
Dictionary<String, FieldInfo> keyMapper = getFieldMapperTable(clazz);
|
|
Dictionary<String, PropertyInfo> propertyKeyMapper = getPropertyMapperTable(clazz);
|
|
|
|
int length = imsApiValues.Length / imsApiKeys.Length;
|
|
T[] resultArray = (T[])Array.CreateInstance(clazz, length);
|
|
|
|
for (int baseIndex = 0; baseIndex < imsApiValues.Length; baseIndex += imsApiKeys.Length)
|
|
{
|
|
T instance = getInstance(clazz, imsApiKeys, imsApiValues, keyMapper, propertyKeyMapper, baseIndex);
|
|
resultArray[baseIndex / imsApiKeys.Length] = instance;
|
|
}
|
|
return resultArray;
|
|
}
|
|
|
|
|
|
protected void safeSetField(T instance, FieldInfo field, String sValue)
|
|
{
|
|
//if ((field.getModifiers() & Modifier.PRIVATE) == Modifier.PRIVATE) {
|
|
// field.setAccessible(true);
|
|
//}
|
|
try
|
|
{
|
|
if (field.FieldType == typeof(int) || field.FieldType == typeof(Int16) || field.FieldType == typeof(Int32) || field.FieldType == typeof(Int64))
|
|
{
|
|
try
|
|
{
|
|
field.SetValue(instance, Int32.Parse(sValue));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// replace all , by .
|
|
string s = sValue.Replace(",", ".");
|
|
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
|
|
field.SetValue(instance, Convert.ToInt32(Double.Parse(s, culture)));
|
|
}
|
|
}
|
|
else if (field.FieldType == typeof(String) || field.FieldType == typeof(string))
|
|
{
|
|
field.SetValue(instance, sValue);
|
|
}
|
|
//} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
|
|
// field.setBoolean(instance, Boolean.parseBoolean(sValue));
|
|
else if (field.FieldType == typeof(DateTime))
|
|
{
|
|
field.SetValue(instance, getDateValue(sValue));
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("unknown type mapper for " + field.FieldType.Name);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new ArgumentException("unknown type mapper or invalid value for " + field.Name + ":" + sValue, e);
|
|
}
|
|
}
|
|
|
|
protected void safeSetProperty(T instance, PropertyInfo field, String sValue)
|
|
{
|
|
//if ((field.getModifiers() & Modifier.PRIVATE) == Modifier.PRIVATE) {
|
|
// field.setAccessible(true);
|
|
//}
|
|
try
|
|
{
|
|
if (field.PropertyType== typeof(int) || field.PropertyType == typeof(Int16) || field.PropertyType == typeof(Int32) || field.PropertyType == typeof(Int64))
|
|
{
|
|
try
|
|
{
|
|
field.SetValue(instance, Int32.Parse(sValue), new object[] { });
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// replace all , by .
|
|
string s = sValue.Replace(",", ".");
|
|
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
|
|
field.SetValue(instance, Convert.ToInt32(Double.Parse(s, culture)), new object[] { });
|
|
}
|
|
}
|
|
else if (field.PropertyType == typeof(String) || field.PropertyType == typeof(string))
|
|
{
|
|
field.SetValue(instance, sValue, new object[] { });
|
|
}
|
|
//} else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
|
|
// field.setBoolean(instance, Boolean.parseBoolean(sValue));
|
|
else if (field.PropertyType == typeof(DateTime))
|
|
{
|
|
field.SetValue(instance, getDateValue(sValue), new object[] { });
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("unknown type mapper for " + field.PropertyType.Name);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new ArgumentException("unknown type mapper or invalid value for " + field.Name + ":" + sValue, e);
|
|
}
|
|
}
|
|
|
|
public DateTime getDateValue(string sDateValue)
|
|
{
|
|
if (sDateValue == null || sDateValue.Equals(""))
|
|
{
|
|
return new DateTime(1899, 12, 31, 23, 59, 59, DateTimeKind.Utc);
|
|
}
|
|
string s = sDateValue.Replace(",", ".");
|
|
CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
|
|
double millies = Double.Parse(sDateValue, culture);
|
|
if (millies <= 1000)
|
|
{
|
|
return new DateTime(1899, 12, 31, 23, 59, 59, DateTimeKind.Utc);
|
|
}
|
|
// treat date values >= 30.12.3000 as infinite...
|
|
if (millies >= 32535039600000)
|
|
{
|
|
return new DateTime(9999, 12, 31, 23, 59, 59, DateTimeKind.Utc);
|
|
}
|
|
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
DateTime expiry = epoch.AddMilliseconds(millies);
|
|
return expiry;
|
|
}
|
|
|
|
public String[] getValueArray(T[] value, String[] imsApiKeys)
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw new ArgumentException("parameter value must not be null");
|
|
}
|
|
if (imsApiKeys == null)
|
|
{
|
|
throw new ArgumentException("parameter imsApiKeys must not be null");
|
|
}
|
|
if (value.Length == 0)
|
|
{
|
|
return new String[0];
|
|
}
|
|
// aus der uebergebenen Struktur ein String Array bilden, unter der Prämisse der Imsapikeys
|
|
// Kein Element des ValueArray darf null sein !!!!!
|
|
if (value[0] == null)
|
|
{
|
|
throw new ArgumentException("first element in value array must not be null");
|
|
}
|
|
|
|
Dictionary<String, FieldInfo> keyMapper = getFieldMapperTable(value[0].GetType());
|
|
|
|
String[] resultArray = new String[imsApiKeys.Length * value.Length];
|
|
// nicht in der Struktur enthaltene Keys führen zu Fehlern
|
|
// in der Struktur enthaltene Keys, die nicht im imsapiKeysArray enthalten sind werden einfach ignoriert
|
|
int startIndex = 0;
|
|
foreach (T item in value)
|
|
{
|
|
toImsApiStringArray(item, resultArray, imsApiKeys, keyMapper, startIndex);
|
|
startIndex += imsApiKeys.Length;
|
|
}
|
|
return resultArray;
|
|
}
|
|
|
|
/// <summary>
|
|
/// aus einer Struktur ein String-Array erzeugen; alle als Keys uerbegebenen Felder
|
|
/// sind im String-Array in der Reihenfolge der imsApiKeys enthalten
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <param name="imsApiKeys"></param>
|
|
/// <returns></returns>
|
|
public String[] getValueArray(T value, String[] imsApiKeys)
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw new ArgumentException("parameter value must not be null");
|
|
}
|
|
if (imsApiKeys == null)
|
|
{
|
|
throw new ArgumentException("parameter imsApiKeys must not be null");
|
|
}
|
|
// aus der uebergebenen Struktur ein String Array bilden, unter der Prämisse der Imsapikeys
|
|
Dictionary<String, FieldInfo> keyMapper = getFieldMapperTable(value.GetType());
|
|
|
|
String[] resultArray = new String[imsApiKeys.Length];
|
|
// nicht in der Struktur enthaltene Keys führen zu Fehlern
|
|
// in der Struktur enthaltene Keys, die nicht im imsapiKeysArray enthalten sind werden einfach ignoriert
|
|
toImsApiStringArray(value, resultArray, imsApiKeys, keyMapper, 0);
|
|
|
|
return resultArray;
|
|
}
|
|
|
|
protected void toImsApiStringArray(T value, String[] resultArray, String[] imsApiKeys,
|
|
Dictionary<String, FieldInfo> keyMapper, int i)
|
|
{
|
|
int destinationIndex = i;
|
|
foreach (String key in imsApiKeys)
|
|
{
|
|
if (!keyMapper.ContainsKey(key))
|
|
{
|
|
throw new ArgumentException("destination key '" + key + "' is not available in structure");
|
|
}
|
|
FieldInfo field = keyMapper[key];
|
|
try
|
|
{
|
|
String imsapiString = safeGetField(field, value);
|
|
resultArray[destinationIndex++] = imsapiString;
|
|
}
|
|
catch (NullReferenceException)
|
|
{
|
|
// field is null
|
|
destinationIndex++;
|
|
}
|
|
catch (Exception )
|
|
{
|
|
destinationIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected String safeGetField(FieldInfo field, T value)
|
|
{
|
|
try
|
|
{
|
|
Object o = field.GetValue(value);
|
|
if (field.FieldType == typeof(int) || field.FieldType == typeof(Int16) || field.FieldType == typeof(Int32) || field.FieldType == typeof(Int64) )
|
|
{
|
|
return o.ToString();
|
|
}
|
|
else if (field.FieldType == typeof(string) || field.FieldType == typeof(String))
|
|
{
|
|
return o.ToString();
|
|
}
|
|
else if (field.FieldType == typeof(Boolean) || field.FieldType == typeof(bool))
|
|
{
|
|
bool b = (Boolean)o;
|
|
if (b)
|
|
{
|
|
return "1";
|
|
}
|
|
else
|
|
{
|
|
return "0";
|
|
}
|
|
}
|
|
else if (field.FieldType == typeof(DateTime))
|
|
{
|
|
DateTime d = (DateTime)o;
|
|
if (d == null)
|
|
{
|
|
return "0";
|
|
}
|
|
return "" + d.Ticks;// todo:correction
|
|
}
|
|
}
|
|
catch (NullReferenceException)
|
|
{
|
|
return "";
|
|
}
|
|
catch (AccessViolationException)
|
|
{
|
|
// einfach ignorieren, dies sollte eigentlich nie vorkommen
|
|
}
|
|
throw new ArgumentException("unknown type mapper for " + field.FieldType.Name);
|
|
}
|
|
}
|
|
}
|