#region License
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed 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.
*/
#endregion
#region Imports
using System;
using System.Reflection;
using System.Reflection.Emit;
using Spring.Proxy;
#endregion
namespace Spring.Web.Support{
/// <summary>
/// This MethodBuilder emits a Callback-call before calling the base method
/// </summary>
/// <author>Erich Eichinger</author>
internal class SupportsWebDependencyInjectionMethodBuilder : BaseProxyMethodBuilder
{
private FieldInfo _appContextField;
private MethodInfo _callbackMethod;
/// <summary>
/// Initializes a new instance of a SupportsWebDependencyInjectionMethodBuilder
/// </summary>
public SupportsWebDependencyInjectionMethodBuilder(TypeBuilder typeBuilder, IProxyTypeGenerator proxyGenerator,
FieldInfo appContextField, MethodInfo callbackMethod)
: base(typeBuilder, proxyGenerator, true)
{
_appContextField = appContextField;
_callbackMethod = callbackMethod;
}
/// <summary>
/// Inserts a call to a callback-method before actually calling the base-method.
/// </summary>
/// <param name="il">The IL generator to use</param>
/// <param name="method">The method to proxy</param>
/// <param name="interfaceMethod">The interface definition of this method, if applicable</param>
protected override void GenerateMethod(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod)
{
this.GenerateCallbackMethodCall(il, method, interfaceMethod);
base.GenerateMethod(il, method, interfaceMethod);
}
/// <summary>
/// Emits the callback invocation.
/// </summary>
private void GenerateCallbackMethodCall(ILGenerator il, MethodInfo method, MethodInfo interfaceMethod)
{
// setup parameters for call
// IApplicationContext is always first parameter!
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, _appContextField);
// lookup parameters needed for callback - they are matched by type in order!
ParameterInfo[] callbackParams = _callbackMethod.GetParameters();
ParameterInfo[] paramArray = method.GetParameters();
Type returnType = _callbackMethod.ReturnType;
int replaceArgumentIndex = -1;
for (int j = 1; j < callbackParams.Length; j++)
{
for (int i = 0; i < paramArray.Length; i++)
{
// remember the parameter to assign the value returned from the callback to
if (paramArray[i].ParameterType == returnType)
{
replaceArgumentIndex = i;
}
if (paramArray[i].ParameterType == callbackParams[j].ParameterType)
{
il.Emit(OpCodes.Ldarg_S, i + 1);
break;
}
}
}
// invoke static(!) callback
il.EmitCall(OpCodes.Call, _callbackMethod, null);
// if callback has a result, store the result back into the first matching argument
if (replaceArgumentIndex > -1)
{
il.Emit(OpCodes.Starg_S, (byte)replaceArgumentIndex+1);
}
return;
}
}
}
|