Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit 3bf6096

Browse files
committed
properties: Correct test execution
This commit: - Corrects the failing Property unit test; - Adds ExportObject.HandlePropertyCall(MessageContainer); - Adds Mapper.GetInterfaceType(Type, string); - Adds Mapper.GetPublicProperties(Type); - Adds a structure, PropertyCallers to hold the property type and a MethodCaller (or null) for the accessor and mutator; - Adds TypeImplementor.GenPropertyCallers(PropertyInfo) which produces the above structure; - Adds IEnumerable<object> MessageReader.ReadValues() method which will yield objects based on the signature of the received Message the MessageReader was constructed with.
1 parent 492157d commit 3bf6096

5 files changed

Lines changed: 214 additions & 6 deletions

File tree

src/BusObject.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See COPYING for details
44

55
using System;
6+
using System.Linq;
67
using System.Reflection;
78
using System.Reflection.Emit;
89
using System.Collections.Generic;
@@ -171,7 +172,7 @@ public object SendPropertyGet (string iface, string property)
171172

172173
MessageReader reader = SendMethodCall ("org.freedesktop.DBus.Properties", "Get", "ss", writer, typeof(object), out exception);
173174

174-
return reader.ReadVariant ();
175+
return reader.ReadValues ().FirstOrDefault ();
175176
}
176177

177178
public void SendPropertySet (string iface, string property, object value)

src/ExportObject.cs

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,27 @@ namespace DBus
1414
{
1515
using Protocol;
1616

17+
internal class PropertyCallers {
18+
public Type Type { get; set; }
19+
public MethodCaller Get { get; set; }
20+
public MethodCaller Set { get; set; }
21+
}
22+
1723
//TODO: perhaps ExportObject should not derive from BusObject
1824
internal class ExportObject : BusObject, IDisposable
1925
{
2026
//maybe add checks to make sure this is not called more than once
2127
//it's a bit silly as a property
2228
bool isRegistered = false;
29+
30+
Dictionary<string, PropertyInfo> propertyInfoCache = new Dictionary<string, PropertyInfo> ();
31+
2332
Dictionary<string, MethodInfo> methodInfoCache = new Dictionary<string, MethodInfo> ();
2433

2534
static readonly Dictionary<MethodInfo, MethodCaller> mCallers = new Dictionary<MethodInfo, MethodCaller> ();
2635

36+
static readonly Dictionary<PropertyInfo, PropertyCallers> pCallers = new Dictionary<PropertyInfo, PropertyCallers> ();
37+
2738
public ExportObject (Connection conn, ObjectPath object_path, object obj) : base (conn, null, object_path)
2839
{
2940
Object = obj;
@@ -79,11 +90,25 @@ public static ExportObject CreateExportObject (Connection conn, ObjectPath objec
7990
return new ExportObject (conn, object_path, obj);
8091
}
8192

93+
private static string Key (string iface, string member)
94+
{
95+
return string.Format ("{0}.{1}", iface, member);
96+
}
97+
8298
public virtual void HandleMethodCall (MessageContainer method_call)
8399
{
100+
switch (method_call.Interface) {
101+
case "org.freedesktop.DBus.Properties":
102+
HandlePropertyCall (method_call);
103+
return;
104+
}
105+
106+
var cache_key = Key (method_call.Interface, method_call.Member);
84107
MethodInfo mi;
85-
if (!methodInfoCache.TryGetValue (method_call.Member, out mi))
86-
methodInfoCache[method_call.Member] = mi = Mapper.GetMethod (Object.GetType (), method_call);
108+
if (!methodInfoCache.TryGetValue (cache_key, out mi)) {
109+
mi = Mapper.GetMethod (Object.GetType (), method_call);
110+
methodInfoCache [cache_key] = mi;
111+
}
87112

88113
if (mi == null) {
89114
conn.MaybeSendUnknownMethodError (method_call);
@@ -110,6 +135,13 @@ public virtual void HandleMethodCall (MessageContainer method_call)
110135
raisedException = e;
111136
}
112137

138+
IssueReply (method_call, outSig, retWriter, mi, raisedException);
139+
}
140+
141+
private void IssueReply (MessageContainer method_call, Signature outSig, MessageWriter retWriter, MethodInfo mi, Exception raisedException)
142+
{
143+
Message msg = method_call.Message;
144+
113145
if (!msg.ReplyExpected)
114146
return;
115147

@@ -118,6 +150,7 @@ public virtual void HandleMethodCall (MessageContainer method_call)
118150
if (raisedException == null) {
119151
MessageContainer method_return = new MessageContainer {
120152
Type = MessageType.MethodReturn,
153+
Destination = method_call.Sender,
121154
ReplySerial = msg.Header.Serial
122155
};
123156
replyMsg = method_return.Message;
@@ -138,12 +171,81 @@ public virtual void HandleMethodCall (MessageContainer method_call)
138171
replyMsg = method_call.CreateError (Mapper.GetInterfaceName (raisedException.GetType ()), raisedException.Message);
139172
}
140173

141-
if (method_call.Sender != null)
142-
replyMsg.Header[FieldCode.Destination] = method_call.Sender;
143-
144174
conn.Send (replyMsg);
145175
}
146176

177+
private void HandlePropertyCall (MessageContainer method_call)
178+
{
179+
Message msg = method_call.Message;
180+
MessageReader msgReader = new MessageReader (msg);
181+
MessageWriter retWriter = new MessageWriter ();
182+
183+
object[] args = MessageHelper.GetDynamicValues (msg);
184+
185+
string face = (string) args [0];
186+
string name = (string) args [1];
187+
188+
PropertyInfo p = GetPropertyInfo (Object.GetType (), face, name);
189+
PropertyCallers pcs = GetPropertyCallers (p);
190+
191+
MethodCaller pc;
192+
MethodInfo mi;
193+
194+
switch (method_call.Member) {
195+
case "Set":
196+
pc = pcs.Set;
197+
mi = p.GetSetMethod ();
198+
break;
199+
case "Get":
200+
pc = pcs.Get;
201+
mi = p.GetGetMethod ();
202+
break;
203+
case "GetAll":
204+
throw new NotImplementedException ();
205+
default:
206+
throw new ArgumentException (string.Format ("No such method {0}.{1}", method_call.Interface, method_call.Member));
207+
}
208+
209+
if (null == pc || null == mi) {
210+
throw new MissingMethodException ();
211+
}
212+
213+
Exception raised = null;
214+
try {
215+
pc (Object, msgReader, msg, retWriter);
216+
} catch (Exception e) {
217+
raised = e;
218+
}
219+
220+
Signature inSig, outSig;
221+
TypeImplementer.SigsForMethod (mi, out inSig, out outSig);
222+
223+
IssueReply (method_call, outSig, retWriter, mi, raised);
224+
}
225+
226+
private PropertyInfo GetPropertyInfo (Type type, string @interface, string property)
227+
{
228+
var key = Key (@interface, property);
229+
PropertyInfo pi;
230+
if (!propertyInfoCache.TryGetValue (key, out pi)) {
231+
pi = Mapper.GetPublicProperties(Mapper.GetInterfaceType (type, @interface)).First (x => property == x.Name);
232+
propertyInfoCache [key] = pi;
233+
}
234+
235+
return pi;
236+
}
237+
238+
private static PropertyCallers GetPropertyCallers (PropertyInfo pi)
239+
{
240+
PropertyCallers pCaller;
241+
if (!pCallers.TryGetValue (pi, out pCaller)) {
242+
pCaller = TypeImplementer.GenPropertyCallers (pi);
243+
pCallers[pi] = pCaller;
244+
}
245+
246+
return pCaller;
247+
}
248+
147249
public object Object {
148250
get;
149251
private set;

src/Mapper.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ public static string GetArgumentName (ICustomAttributeProvider attrProvider, str
3535
return argName;
3636
}
3737

38+
public static Type GetInterfaceType(Type type, string iface)
39+
{
40+
return type.GetInterfaces ().FirstOrDefault (x => iface == GetInterfaceName (x));
41+
}
42+
43+
public static IEnumerable<PropertyInfo> GetPublicProperties (Type type)
44+
{
45+
return type.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
46+
}
47+
3848
public static IEnumerable<KeyValuePair<Type, MemberInfo>> GetPublicMembers (Type type)
3949
{
4050
//note that Type.GetInterfaces() returns all interfaces with flattened hierarchy
@@ -74,6 +84,7 @@ static IEnumerable<MemberInfo> GetDeclaredPublicMembers (Type type)
7484
public static MethodInfo GetMethod (Type type, MessageContainer method_call)
7585
{
7686
var mems = Mapper.GetPublicMembers (type).ToArray ();
87+
7788
foreach (var memberForType in mems) {
7889
//this could be made more efficient by using the given interface name earlier and avoiding walking through all public interfaces
7990
if (method_call.Interface != null)

src/Protocol/MessageReader.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ public bool DataAvailable {
7272
}
7373
}
7474

75+
public IEnumerable<object> ReadValues ()
76+
{
77+
for (int i = 0; i < message.Signature.Length; ++i) {
78+
yield return ReadValue (message.Signature[i]);
79+
}
80+
}
81+
7582
public object ReadValue (Type type)
7683
{
7784
if (type == typeof (void))

src/TypeImplementer.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class TypeImplementer
3131
static MethodInfo messageReaderReadArray = typeof (MessageReader).GetMethod ("ReadArray", Type.EmptyTypes);
3232
static MethodInfo messageReaderReadDictionary = typeof (MessageReader).GetMethod ("ReadDictionary", Type.EmptyTypes);
3333
static MethodInfo messageReaderReadStruct = typeof (MessageReader).GetMethod ("ReadStruct", Type.EmptyTypes);
34+
static MethodInfo messageHelperGetDynamicValues = typeof (MessageHelper).GetMethod ("GetDynamicValues", new [] { typeof (Message) });
3435

3536
static Dictionary<Type,MethodInfo> writeMethods = new Dictionary<Type,MethodInfo> ();
3637
static Dictionary<Type,object> typeWriters = new Dictionary<Type,object> ();
@@ -513,6 +514,92 @@ internal static MethodInfo GetReadMethod (Type t)
513514
return null;
514515
}
515516

517+
internal static PropertyCallers GenPropertyCallers (PropertyInfo target)
518+
{
519+
var pc = new PropertyCallers {
520+
Type = target.PropertyType,
521+
Get = GenGetMethod (target),
522+
Set = GenSetMethod (target)
523+
};
524+
525+
return pc;
526+
}
527+
528+
internal static MethodCaller GenGetMethod (PropertyInfo target)
529+
{
530+
var mi = target.GetGetMethod ();
531+
532+
if (null == mi) {
533+
return null;
534+
}
535+
536+
Type[] parms = new Type[] { typeof (object), typeof (MessageReader), typeof (Message), typeof (MessageWriter) };
537+
var method = new DynamicMethod ("PropertyGet", typeof(void), parms, typeof(MessageReader));
538+
539+
var ilg = method.GetILGenerator ();
540+
541+
ilg.Emit (OpCodes.Ldarg_0);
542+
ilg.EmitCall (mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi, null);
543+
544+
LocalBuilder retLocal = ilg.DeclareLocal (mi.ReturnType);
545+
ilg.Emit (OpCodes.Stloc, retLocal);
546+
547+
ilg.Emit (OpCodes.Ldarg_3);
548+
ilg.Emit (OpCodes.Ldloc, retLocal);
549+
GenWriter (ilg, mi.ReturnType);
550+
551+
ilg.Emit (OpCodes.Ret);
552+
553+
return (MethodCaller) method.CreateDelegate (typeof(MethodCaller));
554+
}
555+
556+
internal static MethodCaller GenSetMethod (PropertyInfo target)
557+
{
558+
var mi = target.GetSetMethod ();
559+
560+
if (null == mi) {
561+
return null;
562+
}
563+
564+
Type[] parms = new Type[] { typeof (object), typeof (MessageReader), typeof (Message), typeof (MessageWriter) };
565+
var method = new DynamicMethod ("PropertySet", typeof(void), parms, typeof(MessageReader));
566+
567+
var ilg = method.GetILGenerator ();
568+
569+
if (null == messageHelperGetDynamicValues) {
570+
throw new MissingMethodException (typeof(MessageHelper).Name, "GetDynamicValues");
571+
}
572+
573+
var args = ilg.DeclareLocal (typeof(object[]));
574+
var arg = ilg.DeclareLocal (typeof(object));
575+
var v = ilg.DeclareLocal (target.PropertyType);
576+
577+
ilg.Emit (OpCodes.Ldarg_2);
578+
ilg.Emit (OpCodes.Call, messageHelperGetDynamicValues);
579+
ilg.Emit (OpCodes.Stloc, args);
580+
581+
ilg.Emit (OpCodes.Ldloc, args);
582+
ilg.Emit (OpCodes.Ldc_I4_2);
583+
ilg.Emit (OpCodes.Ldelem, typeof(object));
584+
ilg.Emit (OpCodes.Stloc, arg);
585+
586+
var cast = target.PropertyType.IsValueType
587+
? OpCodes.Unbox_Any
588+
: OpCodes.Castclass;
589+
590+
ilg.Emit (OpCodes.Ldloc, arg);
591+
ilg.Emit (cast, target.PropertyType);
592+
ilg.Emit (OpCodes.Stloc, v);
593+
594+
ilg.Emit (OpCodes.Ldarg_0);
595+
ilg.Emit (OpCodes.Ldloc, v);
596+
ilg.Emit (mi.IsFinal ? OpCodes.Call : OpCodes.Callvirt, mi);
597+
598+
ilg.Emit (OpCodes.Ret);
599+
600+
return (MethodCaller) method.CreateDelegate (typeof(MethodCaller));
601+
}
602+
516603
internal static MethodCaller GenCaller (MethodInfo target)
517604
{
518605
DynamicMethod hookupMethod = GenReadMethod (target);

0 commit comments

Comments
 (0)