private static ClassDeclarationSyntax GenerateWriteGrain(ClassDeclarationSyntax grainClass, ITypeSymbol swmrInterface, int readReplicaCount) { string grainName = grainClass.Identifier.Text; string writerGrainName = SwmrUtils.GetWriteInterfaceName(grainName); string writerInterfaceName = SwmrUtils.GetWriteInterfaceName(swmrInterface.Name); ClassDeclarationSyntax writerGrain = GenerateClassSqueleton(writerGrainName).WithBaseList(RoslynUtils.BaseList(new[] { "Grain", writerInterfaceName })); writerGrain = RoslynUtils.AddField(writerGrain, "ITopology<string>", "_topology"); writerGrain = writerGrain.AddMembers(GenerateOnActivateAsyncMethod(readReplicaCount)); string readReplicaInterfaceName = SwmrUtils.GetReadReplicaInterfaceName(swmrInterface.Name); foreach (ISymbol member in swmrInterface.GetMembers()) { IMethodSymbol methodSymbol = member as IMethodSymbol; if (methodSymbol == null || IsReadOnlyMethod(methodSymbol) || new MethodInspector(methodSymbol).MethodName == "GetState") { continue; } MethodInspector methodInspector = new MethodInspector(methodSymbol); MethodDeclarationSyntax methodImpl = GenerateMethodDeclaration(methodInspector); methodImpl = SwmrUtils.AddSessionIdParameter(methodImpl).AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.AsyncKeyword)).WithSemicolonToken(SF.Token(SyntaxKind.None)); BlockSyntax statmentBlock = SF.Block(); statmentBlock = AddStatement(statmentBlock, "string grainId = this.GetPrimaryKeyString();"); statmentBlock = AddStatement(statmentBlock, string.Format("{0} grain = GrainFactory.GetGrain<{0}>(grainId);", swmrInterface.Name)); statmentBlock = AddStatement(statmentBlock, String.Format("{0} await grain.{1}({2});", methodInspector.ReturnType != "Task"? "var result =" : "", methodInspector.MethodName, string.Join(", ", methodInspector.MethodParams.Keys))); statmentBlock = AddStatement(statmentBlock, "GrainState state = await grain.GetState();"); statmentBlock = AddStatement(statmentBlock, "string sessionNode = _topology.GetNode(sessionId);"); statmentBlock = AddStatement(statmentBlock, "IEnumerable<string> otherNodes = _topology.Nodes.Where(node => node != sessionNode);"); ForEachStatementSyntax forEachStatement = SF.ForEachStatement( SF.PredefinedType(SF.Token(SyntaxKind.StringKeyword)), SF.Identifier("node"), SF.IdentifierName("otherNodes"), SF.Block(SF.ParseStatement(GenerateSetStateStmt(readReplicaInterfaceName, @"node"))) ); statmentBlock = statmentBlock.AddStatements(forEachStatement); statmentBlock = AddStatement(statmentBlock, (string.Format("{0} {1}", "await", GenerateSetStateStmt(readReplicaInterfaceName, @"sessionNode")))); if (methodInspector.ReturnType != "Task") { statmentBlock = AddStatement(statmentBlock, "return result;"); } methodImpl = methodImpl.WithBody(statmentBlock); writerGrain = writerGrain.AddMembers(methodImpl); } return(writerGrain); }
public async Task <CodeGenResult> CodeGen(Workspace workspace, Project project) { CompilationUnitSyntax cu = SF.CompilationUnit(); var usings = new HashSet <string>(); foreach (Document document in project.Documents) { SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync(); _semanticModel = await document.GetSemanticModelAsync(); IEnumerable <InterfaceDeclarationSyntax> interfaces = syntaxTree.GetRoot().DescendantNodes().OfType <InterfaceDeclarationSyntax>(); foreach (var interfaceNode in interfaces) { if (!RoslynUtils.IsPublic(interfaceNode)) { continue; } AttributeSyntax swmrAttribute = AttributeUtils.SelectAttributeOfType(interfaceNode.AttributeLists, typeof(SingleWriterMultipleReadersAttribute), _semanticModel); if (swmrAttribute == null) { continue; } var namespaceNode = interfaceNode.Parent as NamespaceDeclarationSyntax; if (namespaceNode == null) { throw new Exception("A grain interface must be declared inside a namespace"); } usings.UnionWith(syntaxTree.GetRoot().DescendantNodes().OfType <UsingDirectiveSyntax>().Select(usingDirective => usingDirective.Name.ToString())); var methods = RoslynUtils.GetMethodDeclarations(interfaceNode); var readMethods = SwmrUtils.GetReadOnlyMethods(methods, _semanticModel); var writeMethods = methods.Except(readMethods).Where(method => new MethodInspector(method).MethodName != "GetState"); readMethods = SwmrUtils.RemoveReadOnlyAttribute(readMethods, _semanticModel); string grainInterfaceName = interfaceNode.Identifier.Text; var readReplicaMethods = new List <MethodDeclarationSyntax>(readMethods) { GenerateSetStateMethod() }; InterfaceDeclarationSyntax readReplicaInterface = GenerateInterface(SwmrUtils.GetReadReplicaInterfaceName(grainInterfaceName), readReplicaMethods, interfaceNode.BaseList); readMethods = SwmrUtils.AddSessionIdParameter(readMethods); writeMethods = SwmrUtils.AddSessionIdParameter(writeMethods); string readerInterfaceName = SwmrUtils.GetReadInterfaceName(grainInterfaceName); string writerInterfaceName = SwmrUtils.GetWriteInterfaceName(grainInterfaceName); InterfaceDeclarationSyntax readerInterface = GenerateInterface(readerInterfaceName, readMethods, interfaceNode.BaseList); InterfaceDeclarationSyntax writerInterface = GenerateInterface(writerInterfaceName, writeMethods, interfaceNode.BaseList); string fullNameSpace = _semanticModel.GetDeclaredSymbol(namespaceNode).ToString(); NamespaceDeclarationSyntax namespaceDclr = SF.NamespaceDeclaration(SF.IdentifierName(fullNameSpace)).WithUsings(namespaceNode.Usings); namespaceDclr = namespaceDclr.AddMembers(readerInterface, writerInterface, readReplicaInterface); usings.UnionWith(namespaceNode.Usings.Select(@using => @using.Name.ToString())); usings.Remove("ETG.Orleans.Attributes"); cu = cu.AddMembers(namespaceDclr); } } return(new CodeGenResult(Formatter.Format(cu, workspace).ToString(), usings)); }