Commit 632d54e0 authored by Owen Fraser-Green's avatar Owen Fraser-Green

Added InterfaceProxy to Mono bindings to avoid having to generate a proxy for...

Added InterfaceProxy to Mono bindings to avoid having to generate a proxy for every registered object. Also added object_path functions to dbus-message.
parent 0a673a8c
2004-03-23 Owen Fraser-Green <owen@discobabe.net>
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 <owen@discobabe.net>
First checkin of mono bindings.
* configure.in:
* Makefile.am:
Build stuff for the bindings
......
......@@ -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.
*
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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);
......
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;
}
}
}
}
......@@ -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();
}
}
}
......@@ -12,6 +12,7 @@ DBUS_SHARP_FILES= \
Error.cs \
Handler.cs \
InterfaceAttribute.cs \
InterfaceProxy.cs \
Introspector.cs \
Message.cs \
MethodAttribute.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
......
......@@ -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;
}
}
}
}
......
......@@ -68,8 +68,8 @@ namespace DBus
string pathName)
{
Handler handler = new Handler(handledObject,
pathName,
this);
pathName,
this);
registeredHandlers.Add(handledObject, handler);
}