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); }
protected virtual CodeTypeDeclaration GetStateClass( GrainInterfaceData grainInterfaceData, Action <Type> referred, string stateClassBaseName, string stateClassName, out bool hasStateClass) { var sourceType = grainInterfaceData.Type; stateClassName = FixupTypeName(stateClassName); CodeTypeParameterCollection genericTypeParams = grainInterfaceData.GenericTypeParams; Func <Type, bool> nonamespace = t => CurrentNamespace == t.Namespace || ReferencedNamespaces.Contains(t.Namespace); Type persistentInterface = GetPersistentInterface(sourceType); Dictionary <string, PropertyInfo> asyncProperties = GrainInterfaceData.GetPersistentProperties(persistentInterface) .ToDictionary(p => p.Name.Substring(p.Name.LastIndexOf('.') + 1), p => p); Dictionary <string, string> properties = asyncProperties.ToDictionary(p => p.Key, p => GetGenericTypeName(GrainInterfaceData.GetPromptType(p.Value.PropertyType), referred, nonamespace)); var stateClass = new CodeTypeDeclaration(stateClassBaseName); if (genericTypeParams != null) { stateClass.TypeParameters.AddRange(genericTypeParams); } stateClass.IsClass = true; if (persistentInterface != null) { stateClass.TypeAttributes = persistentInterface.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic; } else { stateClass.TypeAttributes = TypeAttributes.Public; } stateClass.BaseTypes.Add(new CodeTypeReference(typeof(GrainState), CodeTypeReferenceOptions.GlobalReference)); MarkAsGeneratedCode(stateClass); referred(typeof(GrainState)); if (persistentInterface != null) { stateClass.BaseTypes.Add(new CodeTypeReference(GetGenericTypeName(persistentInterface, referred, nonamespace))); } stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(SerializableAttribute).Name)); stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(GrainStateAttribute), CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument(new CodePrimitiveExpression(grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type))))); referred(typeof(SerializableAttribute)); referred(typeof(OnDeserializedAttribute)); var initStateFields = new CodeMemberMethod { Name = "InitStateFields" }; initStateFields.Attributes = (initStateFields.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private; foreach (var peoperty in asyncProperties) { Type propertyType = peoperty.Value.PropertyType; bool noCreateNew = propertyType.IsPrimitive || typeof(string).IsAssignableFrom(propertyType) || // Primative types propertyType.IsAbstract || propertyType.IsInterface || propertyType.IsGenericParameter || // No concrete implementation propertyType.GetConstructor(Type.EmptyTypes) == null; // No default constructor var initExpression = noCreateNew // Pre-initialize this type to default value ? (CodeExpression) new CodeDefaultValueExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace))) : new CodeObjectCreateExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace))); initStateFields.Statements.Add(new CodeAssignStatement( new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), peoperty.Key), initExpression)); } hasStateClass = properties.Count > 0; if (hasStateClass) { foreach (var pair in properties) { GenerateStateClassProperty(stateClass, asyncProperties[pair.Key], pair.Key, pair.Value); } var returnType = new CodeTypeReference("System.Collections.Generic.IDictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object))); var concreteType = new CodeTypeReference("System.Collections.Generic.Dictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object))); var asDictionary = new CodeMemberMethod { Name = "AsDictionary", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = returnType }; asDictionary.Statements.Add(new CodeVariableDeclarationStatement(concreteType, "result", new CodeObjectCreateExpression(concreteType))); foreach (var pair in properties) { asDictionary.Statements.Add(new CodeAssignStatement( new CodeIndexerExpression(new CodeVariableReferenceExpression("result"), new CodePrimitiveExpression(pair.Key)), new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), pair.Key))); } asDictionary.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("result"))); stateClass.Members.Add(asDictionary); GenerateSetAll(stateClass, properties); GenerateToString(stateClass, stateClassName, properties); } // Copier, serializer, and deserializer for the state class var copier = SerializerGenerationUtilities.GenerateCopier("_Copier", stateClassName, genericTypeParams); var serializer = SerializerGenerationUtilities.GenerateSerializer("_Serializer", stateClassName, genericTypeParams); var deserializer = SerializerGenerationUtilities.GenerateDeserializer("_Deserializer", stateClassName, genericTypeParams); var ctor = new CodeConstructor { Attributes = (copier.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public }; ctor.BaseConstructorArgs.Add(new CodePrimitiveExpression(TypeUtils.GetFullName(grainInterfaceData.Type))); ctor.Statements.Add(new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "InitStateFields")); copier.Statements.Add(new CodeMethodReturnStatement( new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("input"), "DeepCopy"))); serializer.Statements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("input"), "SerializeTo", new CodeArgumentReferenceExpression("stream"))); deserializer.Statements.Add(new CodeVariableDeclarationStatement(stateClassName, "result", new CodeObjectCreateExpression(stateClassName))); deserializer.Statements.Add(new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("result"), "DeserializeFrom", new CodeArgumentReferenceExpression("stream"))); deserializer.Statements.Add(new CodeMethodReturnStatement( new CodeVariableReferenceExpression("result"))); stateClass.Members.Add(ctor); stateClass.Members.Add(initStateFields); stateClass.Members.Add(copier); stateClass.Members.Add(serializer); stateClass.Members.Add(deserializer); return(stateClass); }