using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Reflection; using System.Text; namespace com.itac.mes.imsapi { /// /// tool fuer das automatische Mapping von Werten in Strukturen nach String-Arrays und umgekehrt /// /// Prinzip uebernommen aus dem ImsInterfaces, Klasse ImsApiMapTool /// /// public class ImsApiMapTool { // von einem Typ private static Dictionary> fieldMapperTable = new Dictionary>(); private static Dictionary> propertyMapperTable = new Dictionary>(); public static void clearClassCache(Type clazz) { Dictionary fieldKeyMapper = null; if (fieldMapperTable.ContainsKey(clazz)) { fieldKeyMapper = fieldMapperTable[clazz]; fieldMapperTable.Remove(clazz); } Dictionary propertyKeyMapper = null; if (propertyMapperTable.ContainsKey(clazz)) { propertyKeyMapper = propertyMapperTable[clazz]; propertyMapperTable.Remove(clazz); } } /// /// eine Abbildungstabelle fuer einen Typ ermitteln (Namen von Feldern und IMSAPI-Keys) /// /// /// protected Dictionary getFieldMapperTable(Type clazz) { Dictionary keyMapper = null; if (fieldMapperTable.ContainsKey(clazz)) { keyMapper = fieldMapperTable[clazz]; } else { keyMapper = new Dictionary(); // 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 getPropertyMapperTable(Type clazz) { Dictionary keyMapper = null; if (propertyMapperTable.ContainsKey(clazz)) { keyMapper = propertyMapperTable[clazz]; } else { keyMapper = new Dictionary(); // 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; } /// /// aus einem String-Array mit Keys und Werten eine Struktur erzeugen. /// alle Felder in der Struktur muessen dafuer mit dem Attribut [IMSAPIKEY] /// versehen sein /// /// /// /// /// 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 keyMapper = getFieldMapperTable(clazz); Dictionary propertyKeyMapper = getPropertyMapperTable(clazz); T instance = getInstance(clazz, imsApiKeys, imsApiValues, keyMapper, propertyKeyMapper, 0); return instance; } private T getInstance(Type clazz, String[] imsApiKeys, String[] imsApiValues, Dictionary keyMapper, Dictionary 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; } /// /// 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 /// /// /// /// /// 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 keyMapper = getFieldMapperTable(clazz); Dictionary 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 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; } /// /// aus einer Struktur ein String-Array erzeugen; alle als Keys uerbegebenen Felder /// sind im String-Array in der Reihenfolge der imsApiKeys enthalten /// /// /// /// 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 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 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); } } }