/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Reflection; using System.Globalization; using System.Collections.Generic; using System.Collections.Specialized; using Apache.NMS; using Apache.NMS.Util; namespace Apache.NMS.ActiveMQ.Util { /// /// Utility class used to provide conveince methods that apply named property /// settings to objects. /// public class IntrospectionSupport { /// /// Sets the public properties of a target object using a string map. /// This method uses .Net reflection to identify public properties of /// the target object matching the keys from the passed map. /// /// The object whose properties will be set. /// Map of key/value pairs. public static void SetProperties(object target, StringDictionary map) { SetProperties(target, map, ""); } /// /// Sets the public properties of a target object using a string map. /// This method uses .Net reflection to identify public properties of /// the target object matching the keys from the passed map. /// /// The object whose properties will be set. /// Map of key/value pairs. /// Key value prefix. This is prepended to the property name /// before searching for a matching key value. public static void SetProperties(object target, StringDictionary map, string prefix) { Tracer.DebugFormat("SetProperties called with target: {0}, and prefix: {1}", target.GetType().Name, prefix); foreach(string key in map.Keys) { if(key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase)) { string propertyName = key.Substring(prefix.Length); // Process all member assignments at this level before processing // any deeper member assignments. if(!propertyName.Contains(".")) { MemberInfo member = FindPropertyInfo(target, propertyName); if(member == null) { throw new NMSException(string.Format("No such property or field: {0} on class: {1}", propertyName, target.GetType().Name)); } try { if(member.MemberType == MemberTypes.Property) { PropertyInfo property = member as PropertyInfo; property.SetValue(target, Convert.ChangeType(map[key], property.PropertyType, CultureInfo.InvariantCulture), null); } else { FieldInfo field = member as FieldInfo; field.SetValue(target, Convert.ChangeType(map[key], field.FieldType, CultureInfo.InvariantCulture)); } } catch(Exception ex) { throw NMSExceptionSupport.Create("Error while attempting to apply option.", ex); } } } } IList propertiesSet = new List(); // Now process any compound assignments, ensuring that once we recurse into an // object we don't do it again as there could be multiple compunds element assignments // and they'd have already been processed recursively. foreach(string key in map.Keys) { if(key.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase)) { string propertyName = key.Substring(prefix.Length); if(propertyName.Contains(".")) { string newTargetName = propertyName.Substring(0, propertyName.IndexOf('.')); string newPrefix = prefix + newTargetName + "."; if(!propertiesSet.Contains(newPrefix)) { MemberInfo member = FindPropertyInfo(target, newTargetName); object newTarget = GetUnderlyingObject(member, target); SetProperties(newTarget, map, newPrefix); propertiesSet.Add(newPrefix); } } } } } private static object GetUnderlyingObject(MemberInfo member, object target) { object result = null; if(member.MemberType == MemberTypes.Field) { FieldInfo field = member as FieldInfo; if(field.FieldType.IsPrimitive) { throw new NMSException("The field given is a priomitive type: " + member.Name); } result = field.GetValue(target); } else { PropertyInfo property = member as PropertyInfo; MethodInfo getter = property.GetGetMethod(); if(getter == null) { throw new NMSException("Cannot access member: " + member.Name); } result = getter.Invoke(target, null); } if(result == null) { throw new NMSException(String.Format("Could not retrieve the value of member {0}."), member.Name); } return result; } private static MemberInfo FindPropertyInfo(object target, string name) { BindingFlags flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; Type type = target.GetType(); MemberInfo member = type.GetProperty(name, flags); if(member == null) { member = type.GetField(name, flags); } return member; } } }