/// <summary> /// Calls the appropriate GetInterfaceInfo method depending on whether we are dealing with an implicit or explicit service type and /// returns the a dictionary of Inteface and Event info exposed by either service type /// </summary> /// <param name="grainType"></param> /// <returns></returns> internal static GrainInterfaceInfo GetInterfaceInfo(Type grainType) { var result = new GrainInterfaceInfo(); Dictionary <int, Type> interfaces = GrainInterfaceData.GetRemoteInterfaces(grainType); if (interfaces.Keys.Count == 0) { // Should never happen! Debug.Fail("Could not find any service interfaces for type=" + grainType.Name); } IEqualityComparer <InterfaceInfo> ifaceComparer = new InterfaceInfoComparer(); foreach (var interfaceId in interfaces.Keys) { Type interfaceType = interfaces[interfaceId]; var interfaceInfo = new InterfaceInfo(interfaceType); if (!result.Interfaces.Values.Contains(interfaceInfo, ifaceComparer)) { result.Interfaces.Add(GrainInterfaceData.GetGrainInterfaceId(interfaceType), interfaceInfo); } } return(result); }
private static MemberDeclarationSyntax GenerateIsCompatibleMethod(Type grainType) { var method = TypeUtils.Method((GrainReference _) => _.IsCompatible(default(int))); var methodDeclaration = method.GetDeclarationSyntax(); var interfaceIdParameter = method.GetParameters()[0].Name.ToIdentifierName(); var interfaceIds = new HashSet <int>( new[] { GrainInterfaceData.GetGrainInterfaceId(grainType) }.Concat( GrainInterfaceData.GetRemoteInterfaces(grainType).Keys)); var returnValue = default(BinaryExpressionSyntax); foreach (var interfaceId in interfaceIds) { var check = SF.BinaryExpression( SyntaxKind.EqualsExpression, interfaceIdParameter, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // If this is the first check, assign it, otherwise OR this check with the previous checks. returnValue = returnValue == null ? check : SF.BinaryExpression(SyntaxKind.LogicalOrExpression, returnValue, check); } return (methodDeclaration.AddBodyStatements(SF.ReturnStatement(returnValue)) .AddModifiers(SF.Token(SyntaxKind.OverrideKeyword))); }
/// <summary> /// Generates switch cases for the provided grain type. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="methodIdArgument"> /// The method id argument, which is used to select the correct switch label. /// </param> /// <param name="generateMethodHandler"> /// The function used to generate switch block statements for each method. /// </param> /// <returns> /// The switch cases for the provided grain type. /// </returns> public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch( Type grainType, IdentifierNameSyntax methodIdArgument, Func <MethodInfo, StatementSyntax[]> generateMethodHandler) { var interfaces = GrainInterfaceData.GetRemoteInterfaces(grainType); interfaces[GrainInterfaceData.GetGrainInterfaceId(grainType)] = grainType; // Switch on interface id. var interfaceCases = new List <SwitchSectionSyntax>(); foreach (var @interface in interfaces) { var interfaceType = @interface.Value; var interfaceId = @interface.Key; var methods = GrainInterfaceData.GetMethods(interfaceType); var methodCases = new List <SwitchSectionSyntax>(); // Switch on method id. foreach (var method in methods) { // Generate switch case. var methodId = GrainInterfaceData.ComputeMethodId(method); var methodType = method; // Generate the switch label for this interface id. var methodIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Generate the switch body. var methodInvokeStatement = generateMethodHandler(methodType); methodCases.Add( SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement)); } // Generate the switch label for this interface id. var interfaceIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), SF.BinaryExpression( SyntaxKind.AddExpression, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)), SF.BinaryExpression( SyntaxKind.AddExpression, ",methodId=".GetLiteralExpression(), methodIdArgument))); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); // Generate switch statements for the methods in this interface. var methodSwitchStatements = SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase); // Generate the switch section for this interface. interfaceCases.Add( SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements)); } return(interfaceCases.ToArray()); }
internal void AddReferenceClass(GrainInterfaceData interfaceData) { bool isObserver = IsObserver(interfaceData.Type); CodeTypeParameterCollection genericTypeParam = interfaceData.GenericTypeParams; // Declare factory class var factoryClass = new CodeTypeDeclaration(interfaceData.FactoryClassBaseName); if (genericTypeParam != null) { factoryClass.TypeParameters.AddRange(genericTypeParam); } factoryClass.IsClass = true; factoryClass.TypeAttributes = interfaceData.Type.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic; MarkAsGeneratedCode(factoryClass); AddFactoryMethods(interfaceData, factoryClass); AddCastMethods(interfaceData, true, factoryClass); if (ShouldGenerateObjectRefFactory(interfaceData)) { AddCreateObjectReferenceMethods(interfaceData, factoryClass); } int factoryClassIndex = ReferencedNamespace.Types.Add(factoryClass); var referenceClass = new CodeTypeDeclaration(interfaceData.ReferenceClassBaseName); if (genericTypeParam != null) { referenceClass.TypeParameters.AddRange(genericTypeParam); } referenceClass.IsClass = true; referenceClass.BaseTypes.Add(new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference)); referenceClass.BaseTypes.Add(new CodeTypeReference(typeof(IAddressable), CodeTypeReferenceOptions.GlobalReference)); var tref = new CodeTypeReference(interfaceData.Type); if (genericTypeParam != null) { foreach (CodeTypeParameter tp in genericTypeParam) { tref.TypeArguments.Add(tp.Name); } } referenceClass.BaseTypes.Add(tref); MarkAsGeneratedCode(referenceClass); referenceClass.TypeAttributes = TypeAttributes.NestedAssembly; referenceClass.CustomAttributes.Add( new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute)))); referenceClass.CustomAttributes.Add( new CodeAttributeDeclaration( new CodeTypeReference(typeof(GrainReferenceAttribute), CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument( new CodePrimitiveExpression(interfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName((interfaceData.Type)))))); var baseReferenceConstructor2 = new CodeConstructor { Attributes = MemberAttributes.FamilyOrAssembly }; baseReferenceConstructor2.Parameters.Add(new CodeParameterDeclarationExpression( new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference), "reference")); baseReferenceConstructor2.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("reference")); referenceClass.Members.Add(baseReferenceConstructor2); var baseReferenceConstructor3 = new CodeConstructor { Attributes = MemberAttributes.FamilyOrAssembly }; baseReferenceConstructor3.Parameters.Add(new CodeParameterDeclarationExpression("SerializationInfo", "info")); baseReferenceConstructor3.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("info")); baseReferenceConstructor3.Parameters.Add(new CodeParameterDeclarationExpression("StreamingContext", "context")); baseReferenceConstructor3.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("context")); referenceClass.Members.Add(baseReferenceConstructor3); var grainRef = new CodeTypeReference(typeof(GrainReference), CodeTypeReferenceOptions.GlobalReference); var refClassName = FixupTypeName(interfaceData.ReferenceClassName); // Copier, serializer, and deserializer for this type var copier = SerializerGenerationUtilities.GenerateCopier("_Copier", refClassName, genericTypeParam); copier.Statements.Add( new CodeMethodReturnStatement( new CodeCastExpression(refClassName, new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(grainRef), "CopyGrainReference", new CodeVariableReferenceExpression("input"))))); referenceClass.Members.Add(copier); var serializer = SerializerGenerationUtilities.GenerateSerializer("_Serializer", refClassName, genericTypeParam); serializer.Statements.Add( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(grainRef), "SerializeGrainReference", new CodeVariableReferenceExpression("input"), new CodeArgumentReferenceExpression("stream"), new CodeArgumentReferenceExpression("expected"))); referenceClass.Members.Add(serializer); var deserializer = SerializerGenerationUtilities.GenerateDeserializer("_Deserializer", refClassName, genericTypeParam); deserializer.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(refClassName), "Cast", new CodeCastExpression(grainRef, new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(grainRef), "DeserializeGrainReference", new CodeArgumentReferenceExpression("expected"), new CodeArgumentReferenceExpression("stream")))))); referenceClass.Members.Add(deserializer); // this private class is the "implementation class" for the interface reference type ReferencedNamespace.Types[factoryClassIndex].Members.Add(referenceClass); AddCastMethods(interfaceData, false, referenceClass); var interfaceId = GrainInterfaceData.GetGrainInterfaceId(interfaceData.Type); var interfaceIdMethod = new CodeMemberProperty { Name = "InterfaceId", Type = new CodeTypeReference(typeof(int)), Attributes = MemberAttributes.Family | MemberAttributes.Override, HasSet = false, HasGet = true }; interfaceIdMethod.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(interfaceId))); referenceClass.Members.Add(interfaceIdMethod); var left = new CodeBinaryOperatorExpression( new CodeArgumentReferenceExpression("interfaceId"), CodeBinaryOperatorType.ValueEquality, new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "InterfaceId")); var interfaceList = GrainInterfaceData.GetRemoteInterfaces(interfaceData.Type); foreach (int iid in interfaceList.Keys) { if (iid == interfaceId) { continue; // already covered the main interfaces } left = new CodeBinaryOperatorExpression( left, CodeBinaryOperatorType.BooleanOr, new CodeBinaryOperatorExpression( new CodeArgumentReferenceExpression("interfaceId"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(iid))); } var interfaceIsCompatibleMethod = new CodeMemberMethod { Name = "IsCompatible", ReturnType = new CodeTypeReference(typeof(bool)) }; interfaceIsCompatibleMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "interfaceId")); interfaceIsCompatibleMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override; interfaceIsCompatibleMethod.Statements.Add(new CodeMethodReturnStatement(left)); referenceClass.Members.Add(interfaceIsCompatibleMethod); var interfaceNameMethod = new CodeMemberProperty { Name = "InterfaceName", Type = new CodeTypeReference(typeof(string)), Attributes = MemberAttributes.Family | MemberAttributes.Override, HasSet = false, HasGet = true }; interfaceNameMethod.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(FixupTypeName(interfaceData.TypeFullName)))); referenceClass.Members.Add(interfaceNameMethod); var invokerClassName = interfaceData.InvokerClassName; var getMethodNameMethod = new CodeMemberMethod { Name = "GetMethodName", ReturnType = new CodeTypeReference(typeof(string)) }; getMethodNameMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "interfaceId")); getMethodNameMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "methodId")); getMethodNameMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; var methodInvokerName = string.Format("{0}.GetMethodName", FixupTypeName(invokerClassName)); getMethodNameMethod.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( null, methodInvokerName, new CodeArgumentReferenceExpression("interfaceId"), new CodeArgumentReferenceExpression("methodId")))); referenceClass.Members.Add(getMethodNameMethod); CodeTypeDeclaration invokerClass = GetInvokerClass(interfaceData, true); invokerClass.TypeAttributes = TypeAttributes.NotPublic; ReferencedNamespace.Types.Add(invokerClass); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System")); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Net")); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization")); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Runtime.Serialization.Formatters.Binary")); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.IO")); ReferencedNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic")); MethodInfo[] methods = GrainInterfaceData.GetMethods(interfaceData.Type); AddMethods(methods, referenceClass, genericTypeParam, isObserver); }