Exemplo n.º 1
0
        public void LookupAmqpMethod(MethodInfo method,
                                     string methodName,
                                     out AmqpClass amqpClass,
                                     out AmqpMethod amqpMethod)
        {
            amqpClass  = null;
            amqpMethod = null;

            // First, try autodetecting the class/method via the
            // IModel method name.

            foreach (AmqpClass c in m_classes)
            {
                foreach (AmqpMethod m in c.m_Methods)
                {
                    if (methodName.Equals(MangleMethodClass(c, m)))
                    {
                        amqpClass  = c;
                        amqpMethod = m;
                        goto stopSearching; // wheee
                    }
                }
            }
stopSearching:

            // If an explicit mapping was provided as an attribute,
            // then use that instead, whether the autodetect worked or
            // not.

            {
                AmqpMethodMappingAttribute methodMapping =
                    Attribute(method, typeof(AmqpMethodMappingAttribute)) as AmqpMethodMappingAttribute;
                if (methodMapping != null)
                {
                    amqpClass = null;
                    foreach (AmqpClass c in m_classes)
                    {
                        if (c.Name == methodMapping.m_className)
                        {
                            amqpClass = c;
                            break;
                        }
                    }
                    amqpMethod = amqpClass.MethodNamed(methodMapping.m_methodName);
                }
            }

            // At this point, if can't find either the class or the
            // method, we can't proceed. Complain.

            if (amqpClass == null || amqpMethod == null)
            {
                throw new Exception("Could not find AMQP class or method for IModel method " + method.Name);
            }
        }
Exemplo n.º 2
0
        public void EmitModelMethod(MethodInfo method)
        {
            ParameterInfo[] parameters = method.GetParameters();

            AmqpClass  amqpClass  = null;
            AmqpMethod amqpMethod = null;

            LookupAmqpMethod(method, method.Name, out amqpClass, out amqpMethod);

            string requestImplClass = MangleMethodClass(amqpClass, amqpMethod);

            // At this point, we know which request method to
            // send. Now compute whether it's an RPC or not.

            AmqpMethod amqpReplyMethod = null;
            AmqpMethodMappingAttribute replyMapping =
                Attribute(method.ReturnTypeCustomAttributes, typeof(AmqpMethodMappingAttribute))
                as AmqpMethodMappingAttribute;

            if (Attribute(method, typeof(AmqpForceOneWayAttribute)) == null &&
                (amqpMethod.IsSimpleRpcRequest || replyMapping != null))
            {
                // We're not forcing oneway, and either are a simple
                // RPC request, or have an explicit replyMapping
                amqpReplyMethod = amqpClass.MethodNamed(replyMapping == null
                                                        ? (string)amqpMethod.m_ResponseMethods[0]
                                                        : replyMapping.m_methodName);
                if (amqpReplyMethod == null)
                {
                    throw new Exception("Could not find AMQP reply method for IModel method " + method.Name);
                }
            }

            // If amqpReplyMethod is null at this point, it's a
            // one-way operation, and no continuation needs to be
            // consed up. Otherwise, we should expect a reply of kind
            // identified by amqpReplyMethod - unless there's a nowait
            // parameter thrown into the equation!
            //
            // Examine the parameters to discover which might be
            // nowait, content header or content body.

            ParameterInfo nowaitParameter        = null;
            string        nowaitExpression       = "null";
            ParameterInfo contentHeaderParameter = null;
            ParameterInfo contentBodyParameter   = null;

            foreach (ParameterInfo pi in parameters)
            {
                AmqpNowaitArgumentAttribute nwAttr =
                    Attribute(pi, typeof(AmqpNowaitArgumentAttribute)) as AmqpNowaitArgumentAttribute;
                if (nwAttr != null)
                {
                    nowaitParameter = pi;
                    if (nwAttr.m_replacementExpression != null)
                    {
                        nowaitExpression = nwAttr.m_replacementExpression;
                    }
                }
                if (Attribute(pi, typeof(AmqpContentHeaderMappingAttribute)) != null)
                {
                    contentHeaderParameter = pi;
                }
                if (Attribute(pi, typeof(AmqpContentBodyMappingAttribute)) != null)
                {
                    contentBodyParameter = pi;
                }
            }

            // Compute expression text for the content header and body.

            string contentHeaderExpr =
                contentHeaderParameter == null
                ? "null"
                : " (" + MangleClass(amqpClass.Name) + "Properties) " + contentHeaderParameter.Name;
            string contentBodyExpr =
                contentBodyParameter == null ? "null" : contentBodyParameter.Name;

            // Emit the method declaration and preamble.

            EmitModelMethodPreamble(method);
            EmitLine("    {");

            // Emit the code to build the request.

            EmitLine("      " + requestImplClass + " __req = new " + requestImplClass + "();");
            foreach (ParameterInfo pi in parameters)
            {
                if (pi != contentHeaderParameter &&
                    pi != contentBodyParameter)
                {
                    if (Attribute(pi, typeof(AmqpUnsupportedAttribute)) != null)
                    {
                        EmitLine("      if (@" + pi.Name + " != null) {");
                        EmitLine("        throw new UnsupportedMethodFieldException(\"" + method.Name + "\",\"" + pi.Name + "\");");
                        EmitLine("      }");
                    }
                    else
                    {
                        AmqpFieldMappingAttribute fieldMapping =
                            Attribute(pi, typeof(AmqpFieldMappingAttribute)) as AmqpFieldMappingAttribute;
                        if (fieldMapping != null)
                        {
                            EmitLine("      __req.m_" + fieldMapping.m_fieldName + " = @" + pi.Name + ";");
                        }
                        else
                        {
                            EmitLine("      __req.m_" + pi.Name + " = @" + pi.Name + ";");
                        }
                    }
                }
            }

            // If we have a nowait parameter, sometimes that can turn
            // a ModelRpc call into a ModelSend call.

            if (nowaitParameter != null)
            {
                EmitLine("      if (" + nowaitParameter.Name + ") {");
                EmitLine("        ModelSend(__req," + contentHeaderExpr + "," + contentBodyExpr + ");");
                if (method.ReturnType != typeof(void))
                {
                    EmitLine("        return " + nowaitExpression + ";");
                }
                EmitLine("      }");
            }

            // At this point, perform either a ModelRpc or a
            // ModelSend.

            if (amqpReplyMethod == null)
            {
                EmitLine("      ModelSend(__req," + contentHeaderExpr + "," + contentBodyExpr + ");");
            }
            else
            {
                string replyImplClass = MangleMethodClass(amqpClass, amqpReplyMethod);

                EmitLine("      RabbitMQ.Client.Impl.MethodBase __repBase = ModelRpc(__req," + contentHeaderExpr + "," + contentBodyExpr + ");");
                EmitLine("      " + replyImplClass + " __rep = __repBase as " + replyImplClass + ";");
                EmitLine("      if (__rep == null) throw new UnexpectedMethodException(__repBase);");

                if (method.ReturnType == typeof(void))
                {
                    // No need to further examine the reply.
                }
                else
                {
                    // At this point, we have the reply method. Extract values from it.
                    AmqpFieldMappingAttribute returnMapping =
                        Attribute(method.ReturnTypeCustomAttributes, typeof(AmqpFieldMappingAttribute))
                        as AmqpFieldMappingAttribute;
                    if (returnMapping == null)
                    {
                        string fieldPrefix = IsAmqpClass(method.ReturnType) ? "m_" : "";

                        // No field mapping --> it's assumed to be a struct to fill in.
                        EmitLine("      " + method.ReturnType + " __result = new " + method.ReturnType + "();");
                        foreach (FieldInfo fi in method.ReturnType.GetFields())
                        {
                            AmqpFieldMappingAttribute returnFieldMapping =
                                Attribute(fi, typeof(AmqpFieldMappingAttribute)) as AmqpFieldMappingAttribute;
                            if (returnFieldMapping != null)
                            {
                                EmitLine("      __result." + fi.Name + " = __rep." + fieldPrefix + returnFieldMapping.m_fieldName + ";");
                            }
                            else
                            {
                                EmitLine("      __result." + fi.Name + " = __rep." + fieldPrefix + fi.Name + ";");
                            }
                        }
                        EmitLine("      return __result;");
                    }
                    else
                    {
                        // Field mapping --> return just the field we're interested in.
                        EmitLine("      return __rep.m_" + returnMapping.m_fieldName + ";");
                    }
                }
            }

            // All the IO and result-extraction has been done. Emit
            // the method postamble.

            EmitLine("    }");
        }