From 632d54e0dbf5e405258be7afffbaa48942c06cbc Mon Sep 17 00:00:00 2001 From: Owen Fraser-Green Date: Tue, 23 Mar 2004 18:07:48 +0000 Subject: Added InterfaceProxy to Mono bindings to avoid having to generate a proxy for every registered object. Also added object_path functions to dbus-message. --- ChangeLog | 21 +++++++- dbus/dbus-message.c | 88 +++++++++++++++++++++++++++------- dbus/dbus-message.h | 5 ++ mono/Arguments.cs | 16 ------- mono/Handler.cs | 56 +++++++--------------- mono/InterfaceProxy.cs | 86 +++++++++++++++++++++++++++++++++ mono/Introspector.cs | 127 ++++++++++++++++++++----------------------------- mono/Makefile.am | 1 + mono/Message.cs | 12 +++++ mono/ProxyBuilder.cs | 81 ++++++++++++++----------------- mono/Service.cs | 4 +- 11 files changed, 303 insertions(+), 194 deletions(-) create mode 100644 mono/InterfaceProxy.cs diff --git a/ChangeLog b/ChangeLog index 30ae5ad3..e9ccd386 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,26 @@ 2004-03-23 Owen Fraser-Green - First checkin of mono bindings. + * mono/Arguments.cs: + * mono/Introspector.cs: + * mono/Handler.cs: + * mono/InterfaceProxy.cs: + * mono/Message.cs + * mono/ProxyBuilder.cs: + * mono/Service.cs: + Added InterfaceProxy class to avoid building proxies for every + object. + + * dbus-message.h: + * dbus-message.c (dbus_message_append_args_valist) + (dbus_message_iter_get_object_path) + (dbus_message_iter_get_object_path_array) + (dbus_message_iter_append_object_path) + (dbus_message_iter_append_object_path_array): + Added object_path iter functions to handle OBJECT_PATH arguments + +2004-03-23 Owen Fraser-Green + First checkin of mono bindings. * configure.in: * Makefile.am: Build stuff for the bindings diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 6ae5a933..d56cd45d 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1916,7 +1916,8 @@ dbus_message_append_args_valist (DBusMessage *message, goto errorout; break; case DBUS_TYPE_OBJECT_PATH: - + if (!dbus_message_iter_append_object_path (&iter, va_arg (var_args, const char*))) + goto errorout; break; case DBUS_TYPE_CUSTOM: { @@ -1977,6 +1978,10 @@ dbus_message_append_args_valist (DBusMessage *message, if (!dbus_message_iter_append_string_array (&iter, (const char **)data, len)) goto errorout; break; + case DBUS_TYPE_OBJECT_PATH: + if (!dbus_message_iter_append_object_path_array (&iter, (const char **)data, len)) + goto errorout; + break; case DBUS_TYPE_NIL: case DBUS_TYPE_ARRAY: case DBUS_TYPE_CUSTOM: @@ -2664,7 +2669,6 @@ dbus_message_iter_get_string (DBusMessageIter *iter) int type, pos; _dbus_return_val_if_fail (dbus_message_iter_check (real), NULL); - pos = dbus_message_iter_get_data_start (real, &type); _dbus_assert (type == DBUS_TYPE_STRING); @@ -2673,11 +2677,7 @@ dbus_message_iter_get_string (DBusMessageIter *iter) pos, NULL); } -#if 0 /** - * @todo FIXME to finish this _dbus_demarshal_object_path() needs - * to not explode the path. - * * Returns the object path value that an iterator may point to. * Note that you need to check that the iterator points to * an object path value before using this function. @@ -2698,10 +2698,9 @@ dbus_message_iter_get_object_path (DBusMessageIter *iter) _dbus_assert (type == DBUS_TYPE_OBJECT_PATH); - return _dbus_demarshal_object_path (&real->message->body, real->message->byte_order, - pos, NULL); + return _dbus_demarshal_string (&real->message->body, real->message->byte_order, + pos, NULL); } -#endif /** * Returns the name and data from a custom type that an iterator may @@ -3325,11 +3324,7 @@ dbus_message_iter_get_string_array (DBusMessageIter *iter, return TRUE; } -#if 0 /** - * @todo FIXME to implement this _dbus_demarshal_object_path_array() - * needs implementing - * * Returns the object path array that the iterator may point to. * Note that you need to check that the iterator points * to an object path array prior to using this function. @@ -3361,13 +3356,12 @@ dbus_message_iter_get_object_path_array (DBusMessageIter *iter, type = iter_get_array_type (real, NULL); _dbus_assert (type == DBUS_TYPE_OBJECT_PATH); - if (!_dbus_demarshal_object_path_array (&real->message->body, real->message->byte_order, - pos, NULL, value, len)) + if (!_dbus_demarshal_string_array (&real->message->body, real->message->byte_order, + pos, NULL, value, len)) return FALSE; else return TRUE; } -#endif /** * Returns the key name fot the dict entry that an iterator @@ -3799,6 +3793,37 @@ dbus_message_iter_append_string (DBusMessageIter *iter, return TRUE; } +/** + * Appends an object path to the message. + * + * @todo add return_val_if_fail(UTF-8 is valid) + * + * @param iter an iterator pointing to the end of the message + * @param value the object path + * @returns #TRUE on success + */ +dbus_bool_t +dbus_message_iter_append_object_path (DBusMessageIter *iter, + const char *value) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); + + if (!dbus_message_iter_append_type (real, DBUS_TYPE_OBJECT_PATH)) + return FALSE; + + if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, value)) + { + _dbus_string_set_length (&real->message->body, real->pos); + return FALSE; + } + + dbus_message_iter_append_done (real); + + return TRUE; +} + /** * Appends a custom type data chunk to the message. A custom * type is simply an arbitrary UTF-8 string used as a type @@ -4330,6 +4355,37 @@ dbus_message_iter_append_string_array (DBusMessageIter *iter, return TRUE; } +/** + * Appends an object path array to the message. + * + * @param iter an iterator pointing to the end of the message + * @param value the array + * @param len the length of the array + * @returns #TRUE on success + */ +dbus_bool_t +dbus_message_iter_append_object_path_array (DBusMessageIter *iter, + const char **value, + int len) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE); + + if (!append_array_type (real, DBUS_TYPE_OBJECT_PATH, NULL, NULL)) + return FALSE; + + if (!_dbus_marshal_string_array (&real->message->body, real->message->byte_order, value, len)) + { + _dbus_string_set_length (&real->message->body, real->pos); + return FALSE; + } + + dbus_message_iter_append_done (real); + + return TRUE; +} + /** * Sets the message sender. * diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index 02fa181b..51676698 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -230,6 +230,8 @@ dbus_bool_t dbus_message_iter_append_double (DBusMessageIter *iter, double value); dbus_bool_t dbus_message_iter_append_string (DBusMessageIter *iter, const char *value); +dbus_bool_t dbus_message_iter_append_object_path (DBusMessageIter *iter, + const char *value); dbus_bool_t dbus_message_iter_append_custom (DBusMessageIter *iter, const char *name, const unsigned char *data, @@ -269,6 +271,9 @@ dbus_bool_t dbus_message_iter_append_byte_array (DBusMessageIter *iter, dbus_bool_t dbus_message_iter_append_string_array (DBusMessageIter *iter, const char **value, int len); +dbus_bool_t dbus_message_iter_append_object_path_array (DBusMessageIter *iter, + const char **value, + int len); diff --git a/mono/Arguments.cs b/mono/Arguments.cs index ac88d6a7..0df205c3 100644 --- a/mono/Arguments.cs +++ b/mono/Arguments.cs @@ -170,22 +170,6 @@ namespace DBus return constructor; } - // Get the signature of a method - public static string ParseParameters(MethodInfo method) - { - ParameterInfo[] pars = method.GetParameters(); - string key = ""; - - foreach (ParameterInfo par in pars) { - if (!par.IsOut) { - Type dbusType = MatchType(par.ParameterType); - key += GetCode(dbusType); - } - } - - return key; - } - // Get the type code for a given D-BUS type public static char GetCode(Type dbusType) { diff --git a/mono/Handler.cs b/mono/Handler.cs index d565b7ec..a854c9ce 100644 --- a/mono/Handler.cs +++ b/mono/Handler.cs @@ -12,7 +12,6 @@ namespace DBus private string pathName = null; private Introspector introspector = null; private object handledObject = null; - private Hashtable handledMethods = null; private DBusObjectPathVTable vTable; private Connection connection; private Service service; @@ -99,33 +98,20 @@ namespace DBus throw new OutOfMemoryException(); } - private void RegisterMethod(MethodInfo method) - { - string key = method.Name + " " + Arguments.ParseParameters(method); - handledMethods.Add(key, method); - } - public object HandledObject { - get - { - return this.handledObject; - } + get { + return this.handledObject; + } - set - { - this.handledObject = value; - - object[] attributes; - - // Register the methods - this.handledMethods = new Hashtable(); - this.introspector = new Introspector(value.GetType()); - - foreach (MethodInfo method in this.introspector.Methods) { - RegisterMethod(method); - } - } + set { + this.handledObject = value; + + object[] attributes; + + // Register the methods + this.introspector = Introspector.GetIntrospector(value.GetType()); + } } public int Filter_Called(IntPtr rawConnection, @@ -169,22 +155,14 @@ namespace DBus private Result HandleMethod(MethodCall methodCall) { methodCall.Service = service; - - // Check the interface name matches - if (methodCall.InterfaceName != this.introspector.InterfaceName) { - return Result.NotYetHandled; - } - - // Iterate through getting the type codes - string key = methodCall.Name + " " + methodCall.Arguments; - - // Check it's one of our methods - if (!handledMethods.Contains(key)) { + + InterfaceProxy interfaceProxy = this.introspector.GetInterface(methodCall.InterfaceName); + if (interfaceProxy == null || !interfaceProxy.HasMethod(methodCall.Key)) { + // No such interface here. return Result.NotYetHandled; } - - // Got it! - MethodInfo method = (MethodInfo) handledMethods[key]; + + MethodInfo method = interfaceProxy.GetMethod(methodCall.Key); // Now call the method. FIXME: Error handling object [] args = methodCall.Arguments.GetParameters(method); diff --git a/mono/InterfaceProxy.cs b/mono/InterfaceProxy.cs new file mode 100644 index 00000000..6ccc9636 --- /dev/null +++ b/mono/InterfaceProxy.cs @@ -0,0 +1,86 @@ +namespace DBus +{ + using System; + using System.Collections; + using System.Reflection; + + internal class InterfaceProxy + { + private static Hashtable interfaceProxies = new Hashtable(); + private Hashtable methods = null; + + private string interfaceName; + + private InterfaceProxy(Type type) + { + object[] attributes = type.GetCustomAttributes(typeof(InterfaceAttribute), true); + InterfaceAttribute interfaceAttribute = (InterfaceAttribute) attributes[0]; + this.interfaceName = interfaceAttribute.InterfaceName; + AddMethods(type); + } + + private void AddMethods(Type type) + { + this.methods = new Hashtable(); + foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | + BindingFlags.Instance | + BindingFlags.DeclaredOnly)) { + object[] attributes = method.GetCustomAttributes(typeof(MethodAttribute), true); + if (attributes.GetLength(0) > 0) { + methods.Add(GetKey(method), method); + } + } + } + + + public static InterfaceProxy GetInterface(Type type) + { + if (!interfaceProxies.Contains(type)) { + interfaceProxies[type] = new InterfaceProxy(type); + } + + return (InterfaceProxy) interfaceProxies[type]; + } + + public bool HasMethod(string key) + { + return this.Methods.Contains(key); + } + + public MethodInfo GetMethod(string key) + { + return (MethodInfo) this.Methods[key]; + } + + private string GetKey(MethodInfo method) + { + ParameterInfo[] pars = method.GetParameters(); + string key = method.Name + " "; + + foreach (ParameterInfo par in pars) { + if (!par.IsOut) { + Type dbusType = Arguments.MatchType(par.ParameterType); + key += Arguments.GetCode(dbusType); + } + } + + return key; + } + + public Hashtable Methods + { + get { + return this.methods; + } + } + + public string InterfaceName + { + get { + return this.interfaceName; + } + } + } +} + + diff --git a/mono/Introspector.cs b/mono/Introspector.cs index c7b9d05b..8e97abc6 100644 --- a/mono/Introspector.cs +++ b/mono/Introspector.cs @@ -10,97 +10,72 @@ namespace DBus internal class Introspector { private Type type; - private string interfaceName; + private static Hashtable introspectors = new Hashtable(); + private Hashtable interfaceProxies = null; - public Introspector(Type type) { - object[] attributes = type.GetCustomAttributes(typeof(InterfaceAttribute), true); - if (attributes.Length != 1) - throw new ApplicationException("Type '" + type + "' is not a D-BUS interface."); - - InterfaceAttribute interfaceAttribute = (InterfaceAttribute) attributes[0]; - - this.interfaceName = interfaceAttribute.InterfaceName; + public static Introspector GetIntrospector(Type type) + { + if (!introspectors.Contains(type)) { + introspectors[type] = new Introspector(type); + } + + return (Introspector) introspectors[type]; + } + + private Introspector(Type type) + { + interfaceProxies = new Hashtable(); + AddType(type); this.type = type; } - public string InterfaceName + private void AddType(Type type) { - get - { - return this.interfaceName; - } + if (type == typeof(object)) { + // Base case + return; + } + + object[] attributes = type.GetCustomAttributes(typeof(InterfaceAttribute), false); + if (attributes.Length >= 1) { + // This is a D-BUS interface so add it to the hashtable + InterfaceProxy interfaceProxy = InterfaceProxy.GetInterface(type); + interfaceProxies.Add(interfaceProxy.InterfaceName, interfaceProxy); + } + + AddType(type.BaseType); + } + + public InterfaceProxy GetInterface(string interfaceName) { + if (interfaceProxies.Contains(interfaceName)) { + return (InterfaceProxy) interfaceProxies[interfaceName]; + } else { + return null; + } } - public ConstructorInfo Constructor + public Hashtable InterfaceProxies { - get - { - ConstructorInfo ret = this.type.GetConstructor(new Type[0]); - if (ret != null) { - return ret; - } else { - return typeof(object).GetConstructor(new Type[0]); - } - } + get { + return this.interfaceProxies; + } } - public IntrospectorMethods Methods + public ConstructorInfo Constructor { - get - { - return new IntrospectorMethods(this.type); + get { + ConstructorInfo ret = this.type.GetConstructor(new Type[0]); + if (ret != null) { + return ret; + } else { + return typeof(object).GetConstructor(new Type[0]); } + } } - public class IntrospectorMethods : IEnumerable + public override string ToString() { - private Type type; - - public IntrospectorMethods(Type type) - { - this.type = type; - } - - public IEnumerator GetEnumerator() - { - return new MethodEnumerator(this.type.GetMethods(BindingFlags.Public|BindingFlags.Instance).GetEnumerator()); - } - - private class MethodEnumerator : IEnumerator - { - private IEnumerator enumerator; - - public MethodEnumerator(IEnumerator enumerator) - { - this.enumerator = enumerator; - } - - public bool MoveNext() - { - while (enumerator.MoveNext()) { - MethodInfo method = (MethodInfo) enumerator.Current; - object[] attributes = method.GetCustomAttributes(typeof(MethodAttribute), true); - if (attributes.GetLength(0) > 0) { - return true; - } - } - - return false; - } - - public void Reset() - { - enumerator.Reset(); - } - - public object Current - { - get - { - return enumerator.Current; - } - } - } + return this.type.ToString(); } } } diff --git a/mono/Makefile.am b/mono/Makefile.am index 6483f4ed..b35a5c42 100644 --- a/mono/Makefile.am +++ b/mono/Makefile.am @@ -12,6 +12,7 @@ DBUS_SHARP_FILES= \ Error.cs \ Handler.cs \ InterfaceAttribute.cs \ + InterfaceProxy.cs \ Introspector.cs \ Message.cs \ MethodAttribute.cs \ diff --git a/mono/Message.cs b/mono/Message.cs index 2f5270dd..a1ff220c 100644 --- a/mono/Message.cs +++ b/mono/Message.cs @@ -35,6 +35,7 @@ namespace DBus protected string pathName = null; protected string interfaceName = null; protected string name = null; + private string key= null; protected Message() { @@ -263,6 +264,17 @@ namespace DBus } } + public string Key + { + get { + if (this.key == null) { + this.key = Name + " " + Arguments; + } + + return this.key; + } + } + public Arguments Arguments { get diff --git a/mono/ProxyBuilder.cs b/mono/ProxyBuilder.cs index 8e170c74..06bdeecb 100644 --- a/mono/ProxyBuilder.cs +++ b/mono/ProxyBuilder.cs @@ -50,13 +50,13 @@ namespace DBus this.service = service; this.pathName = pathName; this.type = type; - this.introspector = new Introspector(type); + this.introspector = Introspector.GetIntrospector(type); } private void BuildMethod(MethodInfo method, + InterfaceProxy interfaceProxy, ref TypeBuilder typeB, FieldInfo serviceF, - FieldInfo interfaceF, FieldInfo pathF) { ParameterInfo[] pars = method.GetParameters(); @@ -95,7 +95,7 @@ namespace DBus generator.Emit(OpCodes.Ldsfld, serviceF); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, pathF); - generator.Emit(OpCodes.Ldsfld, interfaceF); + generator.Emit(OpCodes.Ldstr, interfaceProxy.InterfaceName); generator.Emit(OpCodes.Ldstr, method.Name); generator.Emit(OpCodes.Newobj, MethodCall_C); generator.Emit(OpCodes.Stloc_0); @@ -190,9 +190,9 @@ namespace DBus } } - public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo interfaceF, FieldInfo pathF) + public void BuildConstructor(ref TypeBuilder typeB, FieldInfo serviceF, FieldInfo pathF) { - Type[] pars = {typeof(Service), typeof(string), typeof(string)}; + Type[] pars = {typeof(Service), typeof(string)}; ConstructorBuilder constructor = typeB.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.Public, CallingConventions.Standard, pars); @@ -202,10 +202,8 @@ namespace DBus generator.Emit(OpCodes.Call, this.introspector.Constructor); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Stsfld, serviceF); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit(OpCodes.Stsfld, interfaceF); generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_3); + generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Stfld, pathF); generator.Emit(OpCodes.Ret); @@ -216,29 +214,28 @@ namespace DBus // Build the type TypeBuilder typeB = ServiceModuleBuilder.DefineType(ProxyName, TypeAttributes.Public, this.type); - //type.AddInterfaceImplementation(typeof(IProxy)); FieldBuilder serviceF = typeB.DefineField("service", typeof(Service), FieldAttributes.Private | FieldAttributes.Static); - FieldBuilder interfaceF = typeB.DefineField("interfaceName", - typeof(string), - FieldAttributes.Private | - FieldAttributes.Static); FieldBuilder pathF = typeB.DefineField("pathName", typeof(string), FieldAttributes.Private); - BuildConstructor(ref typeB, serviceF, interfaceF, pathF); + BuildConstructor(ref typeB, serviceF, pathF); // Build the methods - foreach (MethodInfo method in this.introspector.Methods) { - BuildMethod(method, ref typeB, serviceF, interfaceF, pathF); + foreach (DictionaryEntry interfaceEntry in this.introspector.InterfaceProxies) { + InterfaceProxy interfaceProxy = (InterfaceProxy) interfaceEntry.Value; + foreach (DictionaryEntry methodEntry in interfaceProxy.Methods) { + MethodInfo method = (MethodInfo) methodEntry.Value; + BuildMethod(method, interfaceProxy, ref typeB, serviceF, pathF); + } } - Type [] parTypes = new Type[] {typeof(Service), typeof(string), typeof(string)}; - object [] pars = new object[] {Service, this.introspector.InterfaceName, pathName}; + Type [] parTypes = new Type[] {typeof(Service), typeof(string)}; + object [] pars = new object[] {Service, pathName}; Type proxyType = typeB.CreateType(); @@ -247,7 +244,7 @@ namespace DBus // monodis. Note that in order for this to work you should copy // the client assembly as a dll file so that monodis can pick it // up. - //ProxyAssembly.Save("proxy.dll"); + ProxyAssembly.Save("proxy.dll"); ConstructorInfo constructor = proxyType.GetConstructor(parTypes); object instance = constructor.Invoke(pars); @@ -256,45 +253,41 @@ namespace DBus private ModuleBuilder ServiceModuleBuilder { - get - { - if (Service.module == null) { - Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true); - } - - return Service.module; + get { + if (Service.module == null) { + Service.module = ProxyAssembly.DefineDynamicModule(Service.Name, "proxy.dll", true); } + + return Service.module; + } } private Service Service { - get - { - return this.service; - } + get { + return this.service; + } } private string ProxyName { - get - { - return this.introspector.InterfaceName + ".Proxy"; - } + get { + return this.introspector.ToString() + ".Proxy"; + } } private AssemblyBuilder ProxyAssembly { - get - { - if (this.proxyAssembly == null){ - AssemblyName assemblyName = new AssemblyName(); - assemblyName.Name = "DBusProxy"; - this.proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, - AssemblyBuilderAccess.RunAndSave); - } - - return this.proxyAssembly; + get { + if (this.proxyAssembly == null){ + AssemblyName assemblyName = new AssemblyName(); + assemblyName.Name = "DBusProxy"; + this.proxyAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, + AssemblyBuilderAccess.RunAndSave); } + + return this.proxyAssembly; + } } } } diff --git a/mono/Service.cs b/mono/Service.cs index a3c2a31f..39dd4f45 100644 --- a/mono/Service.cs +++ b/mono/Service.cs @@ -68,8 +68,8 @@ namespace DBus string pathName) { Handler handler = new Handler(handledObject, - pathName, - this); + pathName, + this); registeredHandlers.Add(handledObject, handler); } -- cgit