private static void ConsiderType( Type type, bool runtime, Assembly targetAssembly, ISet <Type> includedTypes) { // The module containing the serializer. var module = runtime || type.Assembly != targetAssembly ? null : type.Module; var typeInfo = type.GetTypeInfo(); // If a type was encountered which can be accessed and is marked as [Serializable], process it for serialization. if (typeInfo.IsSerializable) { RecordType(type, module, targetAssembly, includedTypes); } ConsiderGenericBaseTypeArguments(typeInfo, module, targetAssembly, includedTypes); ConsiderGenericInterfacesArguments(typeInfo, module, targetAssembly, includedTypes); // Collect the types which require code generation. if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2("Will generate code for: {0}", type.GetParseableName()); } includedTypes.Add(type); } }
private static void ConsiderType( Type type, bool runtime, Assembly targetAssembly, ISet <Type> includedTypes) { // The module containing the serializer. var module = runtime ? null : type.Module; var typeInfo = type.GetTypeInfo(); // If a type was encountered which can be accessed and is marked as [Serializable], process it for serialization. if (typeInfo.IsSerializable) { RecordType(type, module, targetAssembly, includedTypes); } Type grainStateType; // If a type extends Grain<T>, add T to the list of candidates for serialization if (IsPersistentGrain(typeInfo, out grainStateType)) { RecordType(grainStateType, module, targetAssembly, includedTypes); } // Collect the types which require code generation. if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2("Will generate code for: {0}", type.GetParseableName()); } includedTypes.Add(type); } }
private static void ConsiderType( Type type, bool runtime, Assembly targetAssembly, ISet <Type> includedTypes) { // The module containing the serializer. var module = runtime ? null : type.Module; var typeInfo = type.GetTypeInfo(); // Every type which is encountered must be considered for serialization. if (!typeInfo.IsNested && !typeInfo.IsGenericParameter && typeInfo.IsSerializable) { // If a type was encountered which can be accessed, process it for serialization. if (SerializerGenerationManager.RecordTypeToGenerate(type, module, targetAssembly)) { includedTypes.Add(type); } } // Collect the types which require code generation. if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2("Will generate code for: {0}", type.GetParseableName()); } includedTypes.Add(type); } }
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))); }
private static GrainReferenceCaster MakeCaster(Type interfaceType) { CodeGeneratorManager.GenerateAndCacheCodeForAssembly(interfaceType.Assembly); var genericInterfaceType = interfaceType.IsConstructedGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType; // Try to find the correct GrainReference type for this interface. Type grainReferenceType; if (!GrainToReferenceMapping.TryGetValue(genericInterfaceType, out grainReferenceType)) { throw new InvalidOperationException( string.Format("Cannot find generated GrainReference class for interface '{0}'", interfaceType)); } if (interfaceType.IsConstructedGenericType) { grainReferenceType = grainReferenceType.MakeGenericType(interfaceType.GenericTypeArguments); } // Get the grain reference constructor. var constructor = grainReferenceType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) .Where( _ => { var parameters = _.GetParameters(); return(parameters.Length == 1 && parameters[0].ParameterType == typeof(GrainReference)); }).FirstOrDefault(); if (constructor == null) { throw new InvalidOperationException( string.Format( "Cannot find suitable constructor on generated reference type for interface '{0}'", interfaceType)); } // Construct an expression to construct a new instance of this grain reference when given another grain // reference. var createLambdaParameter = Expression.Parameter(typeof(GrainReference), "gr"); var createLambda = Expression.Lambda <Func <GrainReference, IAddressable> >( Expression.New(constructor, createLambdaParameter), createLambdaParameter); var grainRefParameter = Expression.Parameter(typeof(IAddressable), "grainRef"); var body = Expression.Call( GrainReferenceCastInternalMethodInfo, Expression.Constant(interfaceType), createLambda, grainRefParameter, Expression.Constant(GrainInterfaceData.GetGrainInterfaceId(interfaceType))); // Compile and return the reference casting lambda. var lambda = Expression.Lambda <GrainReferenceCaster>(body, grainRefParameter); return(lambda.Compile()); }
/// <summary> /// Generates the class for the provided grain types. /// </summary> /// <param name="grainType"> /// The grain interface type. /// </param> /// <returns> /// The generated class. /// </returns> internal static TypeDeclarationSyntax GenerateClass(Type grainType) { var baseTypes = new List <BaseTypeSyntax> { SF.SimpleBaseType(typeof(IGrainMethodInvoker).GetTypeSyntax()) }; var grainTypeInfo = grainType.GetTypeInfo(); var genericTypes = grainTypeInfo.IsGenericTypeDefinition ? grainTypeInfo.GetGenericArguments() .Select(_ => SF.TypeParameter(_.ToString())) .ToArray() : new TypeParameterSyntax[0]; // Create the special method invoker marker attribute. var interfaceId = GrainInterfaceData.GetGrainInterfaceId(grainType); var interfaceIdArgument = SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)); var grainTypeArgument = SF.TypeOfExpression(grainType.GetTypeSyntax(includeGenericParameters: false)); var attributes = new List <AttributeSyntax> { CodeGeneratorCommon.GetGeneratedCodeAttributeSyntax(), SF.Attribute(typeof(MethodInvokerAttribute).GetNameSyntax()) .AddArgumentListArguments( SF.AttributeArgument(grainType.GetParseableName().GetLiteralExpression()), SF.AttributeArgument(interfaceIdArgument), SF.AttributeArgument(grainTypeArgument)), SF.Attribute(typeof(ExcludeFromCodeCoverageAttribute).GetNameSyntax()) }; var members = new List <MemberDeclarationSyntax> { GenerateInvokeMethod(grainType), GenerateInterfaceIdProperty(grainType) }; // If this is an IGrainExtension, make the generated class implement IGrainExtensionMethodInvoker. if (typeof(IGrainExtension).IsAssignableFrom(grainType)) { baseTypes.Add(SF.SimpleBaseType(typeof(IGrainExtensionMethodInvoker).GetTypeSyntax())); members.Add(GenerateExtensionInvokeMethod(grainType)); } var classDeclaration = SF.ClassDeclaration( CodeGeneratorCommon.ClassPrefix + TypeUtils.GetSuitableClassName(grainType) + ClassSuffix) .AddModifiers(SF.Token(SyntaxKind.InternalKeyword)) .AddBaseListTypes(baseTypes.ToArray()) .AddConstraintClauses(grainType.GetTypeConstraintSyntax()) .AddMembers(members.ToArray()) .AddAttributeLists(SF.AttributeList().AddAttributes(attributes.ToArray())); if (genericTypes.Length > 0) { classDeclaration = classDeclaration.AddTypeParameterListParameters(genericTypes); } return(classDeclaration); }
/// <summary> /// Returns method declaration syntax for the InterfaceId property. /// </summary> /// <param name="grainType">The grain type.</param> /// <returns>Method declaration syntax for the InterfaceId property.</returns> private static MemberDeclarationSyntax GenerateInterfaceIdProperty(Type grainType) { var property = TypeUtils.Member((IGrainMethodInvoker _) => _.InterfaceId); var returnValue = SF.LiteralExpression( SyntaxKind.NumericLiteralExpression, SF.Literal(GrainInterfaceData.GetGrainInterfaceId(grainType))); return (SF.PropertyDeclaration(typeof(int).GetTypeSyntax(), property.Name) .AddAccessorListAccessors( SF.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .AddBodyStatements(SF.ReturnStatement(returnValue))) .AddModifiers(SF.Token(SyntaxKind.PublicKeyword))); }
/// <summary> /// Returns syntax for the options argument to <see cref="GrainReference.InvokeMethodAsync{T}"/> and <see cref="GrainReference.InvokeOneWayMethod"/>. /// </summary> /// <param name="method">The method which an invoke call is being generated for.</param> /// <returns> /// Argument syntax for the options argument to <see cref="GrainReference.InvokeMethodAsync{T}"/> and /// <see cref="GrainReference.InvokeOneWayMethod"/>, or <see langword="null"/> if no options are to be specified. /// </returns> private static ArgumentSyntax GetInvokeOptions(MethodInfo method) { var options = new List <ExpressionSyntax>(); if (GrainInterfaceData.IsReadOnly(method)) { options.Add(typeof(InvokeMethodOptions).GetNameSyntax().Member(InvokeMethodOptions.ReadOnly.ToString())); } if (GrainInterfaceData.IsUnordered(method)) { options.Add(typeof(InvokeMethodOptions).GetNameSyntax().Member(InvokeMethodOptions.Unordered.ToString())); } if (GrainInterfaceData.IsAlwaysInterleave(method)) { options.Add(typeof(InvokeMethodOptions).GetNameSyntax().Member(InvokeMethodOptions.AlwaysInterleave.ToString())); } ExpressionSyntax allOptions; if (options.Count <= 1) { allOptions = options.FirstOrDefault(); } else { allOptions = options.Aggregate((a, b) => SF.BinaryExpression(SyntaxKind.BitwiseOrExpression, a, b)); } if (allOptions == null) { return(null); } return(SF.Argument(SF.NameColon("options"), SF.Token(SyntaxKind.None), allOptions)); }
/// <summary> /// Generates invoker methods. /// </summary> /// <param name="grainType">The grain type.</param> /// <param name="onEncounteredType"> /// The callback which is invoked when a type is encountered. /// </param> /// <returns>Invoker methods for the provided grain type.</returns> private static MemberDeclarationSyntax[] GenerateInvokeMethods(Type grainType, Action <Type> onEncounteredType) { var baseReference = SF.BaseExpression(); var methods = GrainInterfaceData.GetMethods(grainType); var members = new List <MemberDeclarationSyntax>(); foreach (var method in methods) { onEncounteredType(method.ReturnType); var methodId = GrainInterfaceData.ComputeMethodId(method); var methodIdArgument = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Construct a new object array from all method arguments. var parameters = method.GetParameters(); var body = new List <StatementSyntax>(); foreach (var parameter in parameters) { onEncounteredType(parameter.ParameterType); if (typeof(IGrainObserver).IsAssignableFrom(parameter.ParameterType)) { body.Add( SF.ExpressionStatement( CheckGrainObserverParamInternalExpression.Invoke() .AddArgumentListArguments(SF.Argument(parameter.Name.ToIdentifierName())))); } } // Get the parameters argument value. ExpressionSyntax args; if (parameters.Length == 0) { args = SF.LiteralExpression(SyntaxKind.NullLiteralExpression); } else { args = SF.ArrayCreationExpression(typeof(object).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression) .AddExpressions(parameters.Select(GetParameterForInvocation).ToArray())); } var options = GetInvokeOptions(method); // Construct the invocation call. if (method.ReturnType == typeof(void)) { var invocation = SF.InvocationExpression(baseReference.Member("InvokeOneWayMethod")) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ExpressionStatement(invocation)); } else { var returnType = method.ReturnType == typeof(Task) ? typeof(object) : method.ReturnType.GenericTypeArguments[0]; var invocation = SF.InvocationExpression(baseReference.Member("InvokeMethodAsync", returnType)) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ReturnStatement(invocation)); } members.Add(method.GetDeclarationSyntax().AddBodyStatements(body.ToArray())); } return(members.ToArray()); }
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); }
protected override string GetInvokerImpl(GrainInterfaceData si, CodeTypeDeclaration invokerClass, Type grainType, GrainInterfaceInfo grainInterfaceInfo, bool isClient) { throw new NotImplementedException("GetInvokerImpl"); }
protected override void AddCreateObjectReferenceMethods(GrainInterfaceData grainInterfaceData, CodeTypeDeclaration factoryClass) { throw new NotImplementedException("AddCreateObjectReferenceMethods"); }
protected virtual void AddGetGrainMethods(GrainInterfaceData iface, CodeTypeDeclaration factoryClass) { throw new NotImplementedException("GrainNamespace.AddGetGrainMethods"); }
protected override void AddGetGrainMethods(GrainInterfaceData iface, CodeTypeDeclaration factoryClass) { RecordReferencedNamespaceAndAssembly(typeof(GrainId)); RecordReferencedNamespaceAndAssembly(iface.Type); var interfaceId = GrainInterfaceData.GetGrainInterfaceId(iface.Type); var interfaceName = iface.InterfaceTypeName; Action <string> add = codeFmt => factoryClass.Members.Add(new CodeSnippetTypeMember( String.Format(codeFmt, FixupTypeName(interfaceName), interfaceId))); bool isGuidCompoundKey = typeof(IGrainWithGuidCompoundKey).IsAssignableFrom(iface.Type); bool isLongCompoundKey = typeof(IGrainWithIntegerCompoundKey).IsAssignableFrom(iface.Type); bool isGuidKey = typeof(IGrainWithGuidKey).IsAssignableFrom(iface.Type); bool isLongKey = typeof(IGrainWithIntegerKey).IsAssignableFrom(iface.Type); bool isStringKey = typeof(IGrainWithStringKey).IsAssignableFrom(iface.Type); bool isDefaultKey = !(isGuidKey || isStringKey || isLongKey); if (isLongCompoundKey) { // the programmer has specified [ExtendedPrimaryKey] on the interface. add( @" Public Shared Function GetGrain(primaryKey as System.Int64, keyExt as System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(GetType({0}), {1}, primaryKey, keyExt)) End Function"); add( @" Public Shared Function GetGrain(primaryKey as System.Int64, keyExt as System.String, grainClassNamePrefix As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(GetType({0}), {1}, primaryKey, keyExt, grainClassNamePrefix)) End Function"); } else if (isGuidCompoundKey) { add( @" Public Shared Function GetGrain(primaryKey As System.Guid, keyExt as System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(GetType({0}), {1}, primaryKey, keyExt)) End Function"); add( @" Public Shared Function GetGrain(primaryKey As System.Guid, keyExt as System.String, grainClassNamePrefix As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(GetType({0}), {1}, primaryKey, keyExt,grainClassNamePrefix)) End Function"); } else { // the programmer has not specified [ExplicitPlacement] on the interface nor [ExtendedPrimaryKey]. if (isLongKey || isDefaultKey) { add( @" Public Shared Function GetGrain(primaryKey as System.Int64) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey)) End Function"); add( @" Public Shared Function GetGrain(primaryKey as System.Int64, grainClassNamePrefix As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey, grainClassNamePrefix)) End Function"); } if (isGuidKey || isDefaultKey) { add( @" Public Shared Function GetGrain(primaryKey As System.Guid) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey)) End Function"); add( @" Public Shared Function GetGrain(primaryKey As System.Guid, grainClassNamePrefix As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey, grainClassNamePrefix)) End Function"); } if (isStringKey) { add( @" Public Shared Function GetGrain(primaryKey As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey)) End Function"); add( @" Public Shared Function GetGrain(primaryKey As System.String, grainClassNamePrefix As System.String) As {0} Return Cast(Global.Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(GetType({0}), {1}, primaryKey, grainClassNamePrefix)) End Function"); } } }
/// <summary> /// Generates a syntax tree for the provided assemblies. /// </summary> /// <param name="assemblies">The assemblies to generate code for.</param> /// <param name="runtime">Whether or not runtime code generation is being performed.</param> /// <returns>The generated syntax tree.</returns> private static GeneratedSyntax GenerateForAssemblies(List <Assembly> assemblies, bool runtime) { if (Logger.IsVerbose) { Logger.Verbose( "Generating code for assemblies: {0}", string.Join(", ", assemblies.Select(_ => _.FullName))); } Assembly targetAssembly; HashSet <Type> ignoredTypes; if (runtime) { // Ignore types which have already been accounted for. ignoredTypes = GetTypesWithGeneratedSupportClasses(); targetAssembly = null; } else { ignoredTypes = new HashSet <Type>(); targetAssembly = assemblies.FirstOrDefault(); } var members = new List <MemberDeclarationSyntax>(); // If any KnownAssemblies have been specified, include them during code generation. var knownAssemblies = assemblies.SelectMany(_ => _.GetCustomAttributes <KnownAssemblyAttribute>()) .Select(_ => _.Assembly) .Distinct() .ToSet(); if (knownAssemblies.Count > 0) { knownAssemblies.UnionWith(assemblies); assemblies = knownAssemblies.ToList(); } // Get types from assemblies which reference Orleans and are not generated assemblies. var includedTypes = new HashSet <Type>(); for (var i = 0; i < assemblies.Count; i++) { var assembly = assemblies[i]; foreach (var attribute in assembly.GetCustomAttributes <KnownTypeAttribute>()) { ConsiderType(attribute.Type, runtime, targetAssembly, includedTypes); } foreach (var type in assembly.DefinedTypes) { ConsiderType(type, runtime, targetAssembly, includedTypes); } } includedTypes.RemoveWhere(_ => ignoredTypes.Contains(_)); // Group the types by namespace and generate the required code in each namespace. foreach (var group in includedTypes.GroupBy(_ => CodeGeneratorCommon.GetGeneratedNamespace(_))) { var namespaceMembers = new List <MemberDeclarationSyntax>(); foreach (var type in group) { // The module containing the serializer. var module = runtime ? null : type.Module; // Every type which is encountered must be considered for serialization. Action <Type> onEncounteredType = encounteredType => { // If a type was encountered which can be accessed, process it for serialization. SerializerGenerationManager.RecordTypeToGenerate(encounteredType, module, targetAssembly); }; if (Logger.IsVerbose2) { Logger.Verbose2("Generating code for: {0}", type.GetParseableName()); } if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2( "Generating GrainReference and MethodInvoker for {0}", type.GetParseableName()); } GrainInterfaceData.ValidateInterfaceRules(type); namespaceMembers.Add(GrainReferenceGenerator.GenerateClass(type, onEncounteredType)); namespaceMembers.Add(GrainMethodInvokerGenerator.GenerateClass(type)); } // Generate serializers. var first = true; Type toGen; while (SerializerGenerationManager.GetNextTypeToProcess(out toGen)) { if (!runtime) { if (first) { ConsoleText.WriteStatus("ClientGenerator - Generating serializer classes for types:"); first = false; } ConsoleText.WriteStatus( "\ttype " + toGen.FullName + " in namespace " + toGen.Namespace + " defined in Assembly " + toGen.Assembly.GetName()); } if (Logger.IsVerbose2) { Logger.Verbose2( "Generating & Registering Serializer for Type {0}", toGen.GetParseableName()); } namespaceMembers.AddRange(SerializerGenerator.GenerateClass(toGen, onEncounteredType)); } } if (namespaceMembers.Count == 0) { if (Logger.IsVerbose) { Logger.Verbose2("Skipping namespace: {0}", group.Key); } continue; } members.Add( SF.NamespaceDeclaration(SF.ParseName(group.Key)) .AddUsings( TypeUtils.GetNamespaces(typeof(TaskUtility), typeof(GrainExtensions)) .Select(_ => SF.UsingDirective(SF.ParseName(_))) .ToArray()) .AddMembers(namespaceMembers.ToArray())); } return(new GeneratedSyntax { SourceAssemblies = assemblies, Syntax = members.Count > 0 ? SF.CompilationUnit().AddMembers(members.ToArray()) : null }); }
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); }
private string GetMethodDispatchSwitchForInterface(int interfaceId, InterfaceInfo interfaceInfo) { var methodSwitchBody = String.Empty; foreach (int methodId in interfaceInfo.Methods.Keys) { var methodInfo = interfaceInfo.Methods[methodId]; var returnType = methodInfo.ReturnType; GetGenericTypeName(returnType); // Adds return type assembly and namespace to import / library lists if necessary var invokeGrainArgs = string.Empty; ParameterInfo[] paramInfoArray = methodInfo.GetParameters(); for (int count = 0; count < paramInfoArray.Length; count++) { invokeGrainArgs += string.Format("CType(arguments({1}),{0})", GetGenericTypeName(paramInfoArray[count].ParameterType), count); if (count < paramInfoArray.Length - 1) { invokeGrainArgs += ", "; } } // todo: parameters for indexed properties var grainTypeName = GetGenericTypeName(interfaceInfo.InterfaceType); var methodName = methodInfo.Name; string invokeGrainMethod; if (!methodInfo.IsSpecialName) { invokeGrainMethod = string.Format("CType(grain,{0}).{1}({2})", grainTypeName, methodName, invokeGrainArgs); } else if (methodInfo.Name.StartsWith("get_")) { invokeGrainMethod = string.Format("CType(grain,{0}).{1}", grainTypeName, methodName.Substring(4)); } else if (methodInfo.Name.StartsWith("set_")) { invokeGrainMethod = string.Format("CType(grain,{0}).{1} = {2}", grainTypeName, methodName.Substring(4), invokeGrainArgs); } else { // Should never happen throw new InvalidOperationException("Don't know how to handle method " + methodInfo); } string caseBodyStatements; if (returnType == typeof(void)) { caseBodyStatements = string.Format( @"{0} Return System.Threading.Tasks.Task.FromResult(CObj(True)) ", invokeGrainMethod); } else if (GrainInterfaceData.IsTaskType(returnType)) { if (returnType == typeof(Task)) { caseBodyStatements = string.Format( @" Return {0}.ContinueWith(Function(t) If t.Status = System.Threading.Tasks.TaskStatus.Faulted Then : Throw t.Exception : End If Return Nothing End Function) ", invokeGrainMethod); } else { caseBodyStatements = string.Format( @"Return {0}.ContinueWith(Function(t) CObj(t.Result)) ", invokeGrainMethod); } } else { // Should never happen throw new InvalidOperationException(string.Format( "Don't know how to create invoker for method {0} with Id={1} of returnType={2}", methodInfo, methodId, returnType)); } methodSwitchBody += string.Format(@" Case {0} {1}", methodId, caseBodyStatements); } var defaultCase = @" Case Else Throw New NotImplementedException(""interfaceId=""+interfaceId+"",methodId=""+methodId)"; return(String.Format(@"Case {0} ' {1} Select Case methodId {2} {3} End Select ", interfaceId, interfaceInfo.InterfaceType.Name, methodSwitchBody, defaultCase)); }
private CodeTypeDeclaration GetInvokerClass(GrainInterfaceData si, bool isClient) { Type grainType = si.Type; CodeTypeParameterCollection genericTypeParams = si.GenericTypeParams; var invokerClass = new CodeTypeDeclaration(si.InvokerClassBaseName); if (genericTypeParams != null) { invokerClass.TypeParameters.AddRange(genericTypeParams); } invokerClass.IsClass = true; MarkAsGeneratedCode(invokerClass); invokerClass.BaseTypes.Add(si.IsExtension ? new CodeTypeReference(typeof(IGrainExtensionMethodInvoker), CodeTypeReferenceOptions.GlobalReference) : new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference)); GrainInterfaceInfo grainInterfaceInfo = GetInterfaceInfo(grainType); var interfaceId = grainInterfaceInfo.Interfaces.Keys.First(); invokerClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(MethodInvokerAttribute), CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument(new CodePrimitiveExpression(grainType.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainType))), new CodeAttributeArgument(new CodePrimitiveExpression(interfaceId)))); var interfaceIdProperty = new CodeMemberProperty { Name = "InterfaceId", Attributes = MemberAttributes.Public | MemberAttributes.Final, Type = new CodeTypeReference(typeof(int)) }; interfaceIdProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(interfaceId))); interfaceIdProperty.PrivateImplementationType = new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference); invokerClass.Members.Add(interfaceIdProperty); //Add invoke method for Orleans message var orleansInvoker = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = "Invoke", ReturnType = new CodeTypeReference(typeof(Task <object>), CodeTypeReferenceOptions.GlobalReference) }; orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IAddressable), CodeTypeReferenceOptions.GlobalReference), "grain")); orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId")); orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId")); orleansInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object[]), "arguments")); orleansInvoker.PrivateImplementationType = new CodeTypeReference(typeof(IGrainMethodInvoker), CodeTypeReferenceOptions.GlobalReference); var orleansInvokerImpl = new CodeSnippetStatement(GetInvokerImpl(si, invokerClass, grainType, grainInterfaceInfo, isClient)); orleansInvoker.Statements.Add(orleansInvokerImpl); invokerClass.Members.Add(orleansInvoker); //Add TryInvoke method for Orleans message, if the type is an extension interface if (si.IsExtension) { var orleansTryInvoker = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Final, Name = "Invoke", ReturnType = new CodeTypeReference(typeof(Task <object>), CodeTypeReferenceOptions.GlobalReference) }; orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(IGrainExtension), CodeTypeReferenceOptions.GlobalReference), "grain")); orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId")); orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId")); orleansTryInvoker.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object[]), "arguments")); orleansTryInvoker.PrivateImplementationType = new CodeTypeReference(typeof(IGrainExtensionMethodInvoker), CodeTypeReferenceOptions.GlobalReference); var orleansTryInvokerImp = new CodeSnippetStatement(GetInvokerImpl(si, invokerClass, grainType, grainInterfaceInfo, isClient)); orleansTryInvoker.Statements.Add(orleansTryInvokerImp); invokerClass.Members.Add(orleansTryInvoker); } //Add GetMethodName() method var getMethodName = new CodeMemberMethod { Attributes = MemberAttributes.Public | MemberAttributes.Final | MemberAttributes.Static, Name = "GetMethodName", ReturnType = new CodeTypeReference(typeof(string)) }; getMethodName.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "interfaceId")); getMethodName.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "methodId")); var orleansGetMethodNameImpl = new CodeSnippetStatement(GetOrleansGetMethodNameImpl(grainType, grainInterfaceInfo)); getMethodName.Statements.Add(orleansGetMethodNameImpl); invokerClass.Members.Add(getMethodName); return(invokerClass); }
internal void AddStateClass(GrainInterfaceData interfaceData) { GetActivationNamespace(ReferencedNamespace, interfaceData); }
/// <summary> /// Generate Cast method in CodeDom and add it in reference class /// </summary> /// <param name="si">The service interface this grain reference type is being generated for</param> /// <param name="isFactory">whether the class being generated is a factory class rather than a grainref implementation</param> /// <param name="referenceClass">The class being generated for this grain reference type</param> protected virtual void AddCastMethods(GrainInterfaceData si, bool isFactory, CodeTypeDeclaration referenceClass) { throw new NotImplementedException("GrainNamespace.AddCastMethods"); }
/// <summary> /// Generate Cast method in CodeDom and add it in reference class /// </summary> /// <param name="si">The service interface this grain reference type is being generated for</param> /// <param name="isFactory">whether the class being generated is a factory class rather than a grainref implementation</param> /// <param name="referenceClass">The class being generated for this grain reference type</param> protected override void AddCastMethods(GrainInterfaceData si, bool isFactory, CodeTypeDeclaration referenceClass) { throw new NotImplementedException("AddCastMethods"); }
protected override void AddGetGrainMethods(GrainInterfaceData iface, CodeTypeDeclaration factoryClass) { throw new NotImplementedException("AddGetGrainMethods"); }
internal static void RecordTypeToGenerate(Type t) { var typeInfo = t.GetTypeInfo(); if (typeInfo.IsGenericParameter || ProcessedTypes.Contains(t) || TypesToProcess.Contains(t) || typeof(Exception).GetTypeInfo().IsAssignableFrom(t)) { return; } if (typeInfo.IsArray) { RecordTypeToGenerate(typeInfo.GetElementType()); return; } if (typeInfo.IsNestedPublic || typeInfo.IsNestedFamily || typeInfo.IsNestedPrivate) { Log.Warn( ErrorCode.CodeGenIgnoringTypes, "Skipping serializer generation for nested type {0}. If this type is used frequently, you may wish to consider making it non-nested.", t.Name); } if (typeInfo.IsGenericType) { var args = t.GetGenericArguments(); foreach (var arg in args) { if (!arg.IsGenericParameter) { RecordTypeToGenerate(arg); } } } if (typeInfo.IsInterface || typeInfo.IsAbstract || typeInfo.IsEnum || t == typeof(object) || t == typeof(void) || GrainInterfaceData.IsTaskType(t)) { return; } if (typeInfo.IsGenericType) { var def = typeInfo.GetGenericTypeDefinition(); if (def == typeof(Task <>) || (SerializationManager.GetSerializer(def) != null) || ProcessedTypes.Contains(def) || typeof(IAddressable).IsAssignableFrom(def)) { return; } if (def.Namespace != null && (def.Namespace.Equals("System") || def.Namespace.StartsWith("System."))) { Log.Warn( ErrorCode.CodeGenSystemTypeRequiresSerializer, "System type " + def.Name + " requires a serializer."); } else { TypesToProcess.Add(def); } return; } if (typeInfo.IsOrleansPrimitive() || (SerializationManager.GetSerializer(t) != null) || typeof(IAddressable).GetTypeInfo().IsAssignableFrom(t)) { return; } if (typeInfo.Namespace != null && (typeInfo.Namespace.Equals("System") || typeInfo.Namespace.StartsWith("System."))) { var message = "System type " + t.Name + " may require a custom serializer for optimal performance. " + "If you use arguments of this type a lot, consider asking the Orleans team to build a custom serializer for it."; Log.Warn(ErrorCode.CodeGenSystemTypeRequiresSerializer, message); return; } bool hasCopier = false; bool hasSerializer = false; bool hasDeserializer = false; foreach (var method in t.GetMethods(BindingFlags.Static | BindingFlags.Public)) { if (method.GetCustomAttributes(typeof(SerializerMethodAttribute), false).Length > 0) { hasSerializer = true; } else if (method.GetCustomAttributes(typeof(DeserializerMethodAttribute), false).Length > 0) { hasDeserializer = true; } if (method.GetCustomAttributes(typeof(CopierMethodAttribute), false).Length > 0) { hasCopier = true; } } if (hasCopier && hasSerializer && hasDeserializer) { return; } TypesToProcess.Add(t); }
protected override 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 => false; 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)); hasStateClass = properties.Count > 0; if (!hasStateClass) { return(null); } var typeAccess = (persistentInterface != null && !persistentInterface.IsPublic) ? "internal" : "public"; StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<System.CodeDom.Compiler.GeneratedCodeAttribute(""{0}"", ""{1}"")>]", CODE_GENERATOR_NAME, CodeGeneratorVersion); StartNewLine(); generatedCode.AppendFormat(@"[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"[<System.SerializableAttribute()>]"); StartNewLine(); var grainName = grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.GrainStateAttribute(""{0}"")>]", grainName); StartNewLine(); generatedCode.AppendFormat(@"type {0} {1}", typeAccess, stateClassBaseName); if (genericTypeParams != null && genericTypeParams.Count > 0) { generatedCode.Append('<'); for (int p = 0; p < genericTypeParams.Count; ++p) { if (p > 0) { generatedCode.Append(','); } CodeTypeParameter param = genericTypeParams[p]; generatedCode.Append('\'').Append(param.Name); } generatedCode.Append('>'); } generatedCode.AppendFormat(@"() ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"inherit global.Orleans.CodeGeneration.GrainState(""{0}"")", grainName); StartNewLine(); var declaringTypes = new Dictionary <string, List <KeyValuePair <string, PropertyInfo> > >(); foreach (var pair in asyncProperties) { var dtName = GetGenericTypeName(pair.Value.DeclaringType, referred, nonamespace); if (!declaringTypes.ContainsKey(dtName)) { declaringTypes.Add(dtName, new List <KeyValuePair <string, PropertyInfo> >()); } var lst = declaringTypes[dtName]; lst.Add(pair); } foreach (var declaringType in declaringTypes) { StartNewLine(); generatedCode.AppendFormat(@"interface {0} with", declaringType.Key); IncreaseIndent(); foreach (var pair in declaringType.Value) { var propertyType = pair.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 initExpr = noCreateNew ? string.Format("Unchecked.defaultof<{0}>", GetGenericTypeName(propertyType, referred, nonamespace)) : string.Format("{0}()", GetGenericTypeName(propertyType, referred, nonamespace)); StartNewLine(); generatedCode.AppendFormat(@"override val {0} = {1} with get,set", pair.Key, initExpr); } DecreaseIndent(); } GenerateSetAll(asyncProperties, referred); GenerateAsDictionary(asyncProperties, referred); GenerateToString(stateClassName, asyncProperties, referred); // Generate the serialization members. StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.CopierMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Copier(original:obj) : obj ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"input.DeepCopy() :> obj"); DecreaseIndent(); StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.SerializerMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Serializer(original:obj, stream:global.Orleans.Serialization.BinaryTokenStreamWriter, expected:System.Type) : unit ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"input.SerializeTo(stream)"); DecreaseIndent(); StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.DeserializerMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Deserializer(expected:System.Type, stream:global.Orleans.Serialization.BinaryTokenStreamReader) : obj ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let result = {0}()", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"result.DeserializeFrom(stream)"); StartNewLine(); generatedCode.AppendFormat(@"result :> obj"); DecreaseIndent(); DecreaseIndent(); return(null); }
/// <summary> /// Generates a syntax tree for the provided assemblies. /// </summary> /// <param name="assemblies">The assemblies to generate code for.</param> /// <param name="runtime">Whether or not runtime code generation is being performed.</param> /// <returns>The generated syntax tree.</returns> private static GeneratedSyntax GenerateForAssemblies(List <Assembly> assemblies, bool runtime) { if (Logger.IsVerbose) { Logger.Verbose( "Generating code for assemblies: {0}", string.Join(", ", assemblies.Select(_ => _.FullName))); } Assembly targetAssembly; HashSet <Type> ignoredTypes; if (runtime) { // Ignore types which have already been accounted for. ignoredTypes = CodeGeneratorCommon.GetTypesWithImplementations( typeof(MethodInvokerAttribute), typeof(GrainReferenceAttribute), typeof(GrainStateAttribute), typeof(SerializerAttribute)); targetAssembly = null; } else { ignoredTypes = new HashSet <Type>(); targetAssembly = assemblies.FirstOrDefault(); } var members = new List <MemberDeclarationSyntax>(); // Get types from assemblies which reference Orleans and are not generated assemblies. var includedTypes = new HashSet <Type>(); foreach (var type in assemblies.SelectMany(_ => _.GetTypes())) { // The module containing the serializer. var module = runtime ? null : type.Module; // Every type which is encountered must be considered for serialization. if (!type.IsNested && !type.IsGenericParameter && type.IsSerializable) { // If a type was encountered which can be accessed, process it for serialization. var isAccessibleForSerialization = !TypeUtilities.IsTypeIsInaccessibleForSerialization(type, module, targetAssembly); if (isAccessibleForSerialization) { includedTypes.Add(type); SerializerGenerationManager.RecordTypeToGenerate(type); } } // Collect the types which require code generation. if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2("Will generate code for: {0}", type.GetParseableName()); } includedTypes.Add(type); } } includedTypes.RemoveWhere(_ => ignoredTypes.Contains(_)); // Group the types by namespace and generate the required code in each namespace. foreach (var group in includedTypes.GroupBy(_ => CodeGeneratorCommon.GetGeneratedNamespace(_))) { var namespaceMembers = new List <MemberDeclarationSyntax>(); foreach (var type in group) { // The module containing the serializer. var module = runtime ? null : type.Module; // Every type which is encountered must be considered for serialization. Action <Type> onEncounteredType = encounteredType => { // If a type was encountered which can be accessed, process it for serialization. var isAccessibleForSerialization = !TypeUtilities.IsTypeIsInaccessibleForSerialization(encounteredType, module, targetAssembly); if (isAccessibleForSerialization) { SerializerGenerationManager.RecordTypeToGenerate(encounteredType); } }; if (Logger.IsVerbose2) { Logger.Verbose2("Generating code for: {0}", type.GetParseableName()); } if (GrainInterfaceData.IsGrainInterface(type)) { if (Logger.IsVerbose2) { Logger.Verbose2( "Generating GrainReference and MethodInvoker for {0}", type.GetParseableName()); } namespaceMembers.Add(GrainReferenceGenerator.GenerateClass(type, onEncounteredType)); namespaceMembers.Add(GrainMethodInvokerGenerator.GenerateClass(type)); } // Generate serializers. var first = true; Type toGen; while (SerializerGenerationManager.GetNextTypeToProcess(out toGen)) { // Filter types which are inaccessible by the serialzation module/assembly. var skipSerialzerGeneration = toGen.GetAllFields() .Any( field => TypeUtilities.IsTypeIsInaccessibleForSerialization( field.FieldType, module, targetAssembly)); if (skipSerialzerGeneration) { continue; } if (!runtime) { if (first) { ConsoleText.WriteStatus("ClientGenerator - Generating serializer classes for types:"); first = false; } ConsoleText.WriteStatus( "\ttype " + toGen.FullName + " in namespace " + toGen.Namespace + " defined in Assembly " + toGen.Assembly.GetName()); } if (Logger.IsVerbose2) { Logger.Verbose2( "Generating & Registering Serializer for Type {0}", toGen.GetParseableName()); } namespaceMembers.AddRange(SerializerGenerator.GenerateClass(toGen, onEncounteredType)); } } if (namespaceMembers.Count == 0) { if (Logger.IsVerbose) { Logger.Verbose2("Skipping namespace: {0}", group.Key); } continue; } members.Add( SF.NamespaceDeclaration(SF.ParseName(group.Key)) .AddUsings( TypeUtils.GetNamespaces(typeof(TaskUtility), typeof(GrainExtensions)) .Select(_ => SF.UsingDirective(SF.ParseName(_))) .ToArray()) .AddMembers(namespaceMembers.ToArray())); } return(new GeneratedSyntax { SourceAssemblies = assemblies, Syntax = members.Count > 0 ? SF.CompilationUnit().AddMembers(members.ToArray()) : null }); }
protected virtual void AddCreateObjectReferenceMethods(GrainInterfaceData grainInterfaceData, CodeTypeDeclaration factoryClass) { throw new NotImplementedException("GrainNamespace.AddCreateObjectReferenceMethods"); }
protected override string GetBasicMethodImpl(MethodInfo methodInfo) { var invokeArguments = GetInvokeArguments(methodInfo); int methodId = GrainInterfaceData.ComputeMethodId(methodInfo); string methodImpl; string optional = null; if (GrainInterfaceData.IsReadOnly(methodInfo)) { optional = ", options:= Global.Orleans.CodeGeneration.InvokeMethodOptions.ReadOnly"; } if (GrainInterfaceData.IsUnordered(methodInfo)) { if (optional == null) { optional = ", options:= "; } else { optional += " | "; } optional += " Global.Orleans.CodeGeneration.InvokeMethodOptions.Unordered"; } if (GrainInterfaceData.IsAlwaysInterleave(methodInfo)) { if (optional == null) { optional = ", options:= "; } else { optional += " | "; } optional += " Global.Orleans.CodeGeneration.InvokeMethodOptions.AlwaysInterleave"; } if (methodInfo.ReturnType == typeof(void)) { methodImpl = string.Format(@" MyBase.InvokeOneWayMethod({0}, New System.Object() {{{1}}} {2})", methodId, invokeArguments, optional); } else { if (methodInfo.ReturnType == typeof(Task)) { methodImpl = string.Format(@" Return MyBase.InvokeMethodAsync(Of System.Object)({0}, New System.Object() {{{1}}} {2})", methodId, invokeArguments, optional); } else { methodImpl = string.Format(@" Return MyBase.InvokeMethodAsync(Of {0})({1}, New System.Object() {{{2}}} {3})", GetActualMethodReturnType(methodInfo.ReturnType, SerializeFlag.NoSerialize), methodId, invokeArguments, optional); } } return(GetParamGuardCheckStatements(methodInfo) + methodImpl); }
protected override void AddGetGrainMethods(GrainInterfaceData iface, CodeTypeDeclaration factoryClass) { RecordReferencedNamespaceAndAssembly(typeof(GrainId)); RecordReferencedNamespaceAndAssembly(iface.Type); var interfaceId = GrainInterfaceData.GetGrainInterfaceId(iface.Type); Action <string> add = codeFmt => factoryClass.Members.Add( new CodeSnippetTypeMember(String.Format(codeFmt, iface.InterfaceTypeName, interfaceId))); bool hasKeyExt = GrainInterfaceData.UsesPrimaryKeyExtension(iface.Type); bool isGuidKey = typeof(IGrainWithGuidKey).IsAssignableFrom(iface.Type); bool isLongKey = typeof(IGrainWithIntegerKey).IsAssignableFrom(iface.Type); bool isStringKey = typeof(IGrainWithStringKey).IsAssignableFrom(iface.Type); bool isDefaultKey = !(isGuidKey || isStringKey || isLongKey); if (isDefaultKey && hasKeyExt) { // the programmer has specified [ExtendedPrimaryKey] on the interface. add(@" public static {0} GetGrain(long primaryKey, string keyExt) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(typeof({0}), {1}, primaryKey, keyExt)); }}"); add(@" public static {0} GetGrain(long primaryKey, string keyExt, string grainClassNamePrefix) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(typeof({0}), {1}, primaryKey, keyExt, grainClassNamePrefix)); }}"); add(@" public static {0} GetGrain(System.Guid primaryKey, string keyExt) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(typeof({0}), {1}, primaryKey, keyExt)); }}"); add(@" public static {0} GetGrain(System.Guid primaryKey, string keyExt, string grainClassNamePrefix) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeKeyExtendedGrainReferenceInternal(typeof({0}), {1}, primaryKey, keyExt,grainClassNamePrefix)); }}"); } else { // the programmer has not specified [ExplicitPlacement] on the interface nor [ExtendedPrimaryKey]. if (isLongKey || isDefaultKey) { add(@" public static {0} GetGrain(long primaryKey) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey)); }}"); add(@" public static {0} GetGrain(long primaryKey, string grainClassNamePrefix) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey, grainClassNamePrefix)); }}"); } if (isGuidKey || isDefaultKey) { add(@" public static {0} GetGrain(System.Guid primaryKey) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey)); }}"); add(@" public static {0} GetGrain(System.Guid primaryKey, string grainClassNamePrefix) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey, grainClassNamePrefix)); }}"); } if (isStringKey) { add(@" public static {0} GetGrain(System.String primaryKey) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey)); }}"); add(@" public static {0} GetGrain(System.String primaryKey, string grainClassNamePrefix) {{ return Cast(global::Orleans.CodeGeneration.GrainFactoryBase.MakeGrainReferenceInternal(typeof({0}), {1}, primaryKey, grainClassNamePrefix)); }}"); } } }
/// <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()); }
/// <summary> /// Returns the Visual Basic name for the provided <paramref name="parameter"/>. /// </summary> /// <param name="parameter">The parameter.</param> /// <returns>The Visual Basic name for the provided <paramref name="parameter"/>.</returns> protected override string GetParameterName(ParameterInfo parameter) { return(string.Format("[{0}]", GrainInterfaceData.GetParameterName(parameter))); }