Skip to content

Commit

Permalink
Added Hprose Invocation Proxy Implementation Generator
Browse files Browse the repository at this point in the history
  • Loading branch information
andot committed Jan 30, 2016
0 parents commit 5970f6c
Show file tree
Hide file tree
Showing 13 changed files with 343 additions and 0 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Hprose Invocation Proxy Implementation Generator

Copyright (c) 2008-2016 http://hprose.com

hipig -i:IExample.cs -r:Hprose.Client.dll -o:Example.cs

-input:FILE1[,FILEn] Input files (short: -i)
-output:FILE Output files (short: -o)
-reference:A1[,An] Imports metadata from the specified assembly (short: -r)
23 changes: 23 additions & 0 deletions example/IExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using Hprose.Common;
using System.Threading.Tasks;

namespace Example {
public class User {
public string name;
public int age;
public bool male;
public List<User> friends;
}

public interface IExample {
[SimpleMode(true)]
Task<string> Hello(string name);
[ResultMode(HproseResultMode.Serialized)]
[MethodName("SendUsers")]
byte[] SendUsersRaw(List<User> users);
List<User> SendUsers(List<User> users);
void SendUsers(List<User> users, HproseCallback1<List<User>> callback);
}
}
17 changes: 17 additions & 0 deletions hipig/hipig.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hipig", "hipig\hipig.csproj", "{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Debug|x86.ActiveCfg = Debug|x86
{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Debug|x86.Build.0 = Debug|x86
{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Release|x86.ActiveCfg = Release|x86
{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal
12 changes: 12 additions & 0 deletions hipig/hipig.userprefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Properties StartupItem="hipig/hipig.csproj">
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release" ActiveRuntime="Mono 4.2.2" />
<MonoDevelop.Ide.Workbench ActiveDocument="hipig/Program.cs">
<Files>
<File FileName="hipig/Program.cs" Line="122" Column="13" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
</Properties>
Binary file added hipig/hipig/Hprose.Client.dll
Binary file not shown.
214 changes: 214 additions & 0 deletions hipig/hipig/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
using System.CodeDom;
using System.IO;
using Hprose.Common;

namespace Hprose {
class HIPIG {
public static CodeTypeDeclaration ImplementIt(Type it) {
string name = it.Name;
if (name.Length > 1 && name[0] == 'I' && name[1] >= 'A' && name[1] <= 'Z') {
name = name.Substring(1);
}
name += "Impl";
CodeTypeDeclaration proxyClass = new CodeTypeDeclaration(name);
proxyClass.BaseTypes.Add(typeof(HproseInvocationHandler));
proxyClass.BaseTypes.Add(it);

CodeConstructor constructor = new CodeConstructor();
constructor.Attributes = MemberAttributes.Public;
constructor.Parameters.Add( new CodeParameterDeclarationExpression(typeof(HproseInvoker), "invoker") );
constructor.Parameters.Add( new CodeParameterDeclarationExpression(typeof(String), "ns") );
constructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("invoker"));
constructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("ns"));
proxyClass.Members.Add(constructor);

CodeConstructor constructor2 = new CodeConstructor();
constructor2.Attributes = MemberAttributes.Public;
constructor2.Parameters.Add( new CodeParameterDeclarationExpression(typeof(HproseInvoker), "invoker") );
constructor2.ChainedConstructorArgs.Add(new CodeVariableReferenceExpression("invoker"));
constructor2.ChainedConstructorArgs.Add(new CodePrimitiveExpression(""));
proxyClass.Members.Add(constructor2);

foreach (MethodInfo m in it.GetMethods()) {
CodeMemberMethod method = new CodeMemberMethod();
method.Name = m.Name;
method.Attributes = MemberAttributes.Public;
ParameterInfo[] pis = m.GetParameters();
foreach (ParameterInfo p in pis) {
CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(p.ParameterType, p.Name);
if (p.IsOut) cpde.Direction = FieldDirection.Out;
if (p.ParameterType.IsByRef) cpde.Direction = FieldDirection.Ref;
method.Parameters.Add(cpde);
}
method.ReturnType = new CodeTypeReference(m.ReturnType);

CodeExpression[] types = new CodeExpression[pis.Length];
for (int i = 0; i < pis.Length; i++) {
types[i] = new CodeTypeOfExpression(pis[i].ParameterType);
}

var customAttrs = m.GetCustomAttributes(true);
var n = 0;
foreach (var attr in customAttrs) {
if (attr is ResultModeAttribute ||
attr is SimpleModeAttribute ||
attr is ByRefAttribute ||
attr is MethodNameAttribute) {
n++;
}
}
CodeExpression[] attrs = new CodeExpression[n];
n = 0;
foreach (var attr in customAttrs) {
if (attr is ResultModeAttribute) {
attrs[n++] = new CodeObjectCreateExpression(typeof(ResultModeAttribute), new CodeSnippetExpression("HproseResultMode." + (attr as ResultModeAttribute).Value));
}
else if (attr is SimpleModeAttribute) {
attrs[n++] = new CodeObjectCreateExpression(typeof(SimpleModeAttribute), new CodePrimitiveExpression((attr as SimpleModeAttribute).Value));
}
else if (attr is ByRefAttribute) {
attrs[n++] = new CodeObjectCreateExpression(typeof(ByRefAttribute), new CodePrimitiveExpression((attr as ByRefAttribute).Value));
}
else if (attr is MethodNameAttribute) {
attrs[n++] = new CodeObjectCreateExpression(typeof(MethodNameAttribute), new CodePrimitiveExpression((attr as MethodNameAttribute).Value));
}
}

CodeExpression[] args = new CodeExpression[pis.Length];
for (int i = 0; i < pis.Length; i++) {
args[i] = new CodeVariableReferenceExpression(pis[i].Name);
}
if (m.ReturnType != typeof(void)) {
method.Statements.Add(new CodeMethodReturnStatement(new CodeCastExpression(method.ReturnType, new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", new CodeExpression[] {
new CodeThisReferenceExpression(),
new CodePrimitiveExpression(method.Name),
(types.Length == 0) ? new CodeArrayCreateExpression(typeof(Type[]), 0) : new CodeArrayCreateExpression(typeof(Type[]), types),
new CodeTypeOfExpression(method.ReturnType),
(attrs.Length == 0) ? new CodeArrayCreateExpression(typeof(Attribute[]), 0) : new CodeArrayCreateExpression(typeof(Attribute[]), attrs),
(args.Length == 0) ? new CodeArrayCreateExpression(typeof(object[]), 0) : new CodeArrayCreateExpression(typeof(object[]), args)
}))));
}
else {
method.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", new CodeExpression[] {
new CodeThisReferenceExpression(),
new CodePrimitiveExpression(method.Name),
(types.Length == 0) ? new CodeArrayCreateExpression(typeof(Type[]), 0) : new CodeArrayCreateExpression(typeof(Type[]), types),
new CodeTypeOfExpression(method.ReturnType),
(attrs.Length == 0) ? new CodeArrayCreateExpression(typeof(Attribute[]), 0) : new CodeArrayCreateExpression(typeof(Attribute[]), attrs),
(args.Length == 0) ? new CodeArrayCreateExpression(typeof(object[]), 0) : new CodeArrayCreateExpression(typeof(object[]), args)
}));
}
proxyClass.Members.Add(method);
}
return proxyClass;
}
public static void Main(string[] args) {

if (args.Length == 0) {
Console.WriteLine("Hprose Invocation Proxy Implementation Generator 1.0");
Console.WriteLine("Copyright (c) 2008-2016 http://hprose.com");
Console.WriteLine("hipig -i:IExample.cs -r:Hprose.Client.dll -o:Example.cs");
Console.WriteLine(" -input:FILE1[,FILEn] Input files (short: -i)");
Console.WriteLine(" -output:FILE Output files (short: -o)");
Console.WriteLine(" -reference:A1[,An] Imports metadata from the specified assembly (short: -r)");
return;
}
CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

CompilerParameters objCompilerParameters = new CompilerParameters();
objCompilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
objCompilerParameters.ReferencedAssemblies.Add("System.dll");
objCompilerParameters.ReferencedAssemblies.Add("System.Core.dll");

objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true;
objCompilerParameters.OutputAssembly = "";

string[] inputFiles = null;
string output = "ServiceProxyImpl.cs";

foreach (string a in args) {
if (a.StartsWith("-r:") || a.StartsWith("-reference:")) {
string references = a.Substring(a.IndexOf(":") + 1);
if (references[0] == '"') references = references.Substring(1);
if (references[references.Length - 1] == '"') references = references.Substring(0, references.Length - 1);
objCompilerParameters.ReferencedAssemblies.AddRange(references.Split(','));
}
if (a.StartsWith("-i:") || a.StartsWith("-input:")) {
string input = a.Substring(a.IndexOf(":") + 1);
if (input[0] == '"') input = input.Substring(1);
if (input[input.Length - 1] == '"') input = input.Substring(0, input.Length - 1);
inputFiles = input.Split(',');
}
if (a.StartsWith("-o:") || a.StartsWith("-output:")) {
output = a.Substring(a.IndexOf(":") + 1);
if (output[0] == '"') output = output.Substring(1);
if (output[output.Length - 1] == '"') output = output.Substring(0, output.Length - 1);
}
}
if (inputFiles == null) {
inputFiles = new string[] { args[0] };
}

CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromFile(objCompilerParameters, inputFiles);
String outputMessage = "";
foreach (var item in cr.Output) {
outputMessage += item + Environment.NewLine;
}
Console.WriteLine(outputMessage);
if (cr.Errors.HasErrors) {
Console.WriteLine("编译错误:");
foreach (CompilerError err in cr.Errors) {
Console.WriteLine(err.ErrorText);
}
}
else {
Type[] types = cr.CompiledAssembly.GetTypes();

CodeCompileUnit compunit = new CodeCompileUnit();
CodeNamespace ns = new CodeNamespace(types[0].Namespace);
compunit.Namespaces.Add(ns);
ns.Imports.Add(new CodeNamespaceImport("System"));
ns.Imports.Add(new CodeNamespaceImport("System.Reflection"));
ns.Imports.Add(new CodeNamespaceImport("Hprose.Common"));
foreach (Type t in types) {
if (t.IsInterface) {
ns.Types.Add(ImplementIt(t));
}
}
StringBuilder fileContent = new StringBuilder();
CodeGeneratorOptions options = new CodeGeneratorOptions();
using (StringWriter sw = new StringWriter(fileContent)) {
objCSharpCodePrivoder.GenerateCodeFromNamespace(ns, sw, options);
}
File.WriteAllText(output, fileContent.ToString());

string[] files = new string[inputFiles.Length + 1];
inputFiles.CopyTo(files, 0);
files[files.Length - 1] = output;

objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true;
objCompilerParameters.OutputAssembly = "";

cr = objCSharpCodePrivoder.CompileAssemblyFromFile(objCompilerParameters, files);
foreach (var item in cr.Output) {
outputMessage += item + Environment.NewLine;
}
Console.WriteLine(outputMessage);
if (cr.Errors.HasErrors) {
Console.WriteLine("编译错误:");
foreach (CompilerError err in cr.Errors) {
Console.WriteLine(err.ErrorText);
}
}
}

}
}
}
27 changes: 27 additions & 0 deletions hipig/hipig/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Reflection;
using System.Runtime.CompilerServices;

// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.

[assembly: AssemblyTitle ("hipig")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("andot")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]

// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.

[assembly: AssemblyVersion ("1.0.*")]

// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.

//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

Binary file added hipig/hipig/bin/Release/Hprose.Client.dll
Binary file not shown.
Binary file added hipig/hipig/bin/Release/hipig.exe
Binary file not shown.
35 changes: 35 additions & 0 deletions hipig/hipig/hipig.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>hipig</RootNamespace>
<AssemblyName>hipig</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Debug</OutputPath>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<WarningLevel>4</WarningLevel>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="Hprose.Client">
<HintPath>Hprose.Client.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// <autogenerated />
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = "")]
4 changes: 4 additions & 0 deletions hipig/hipig/obj/Release/hipig.csproj.FilesWrittenAbsolute.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/Users/andot/Git/hprose-dotnet/hipig/hipig/obj/Release/.NETFramework,Version=v4.5.AssemblyAttribute.cs
/Users/andot/Git/hprose-dotnet/hipig/hipig/bin/Release/hipig.exe
/Users/andot/Git/hprose-dotnet/hipig/hipig/obj/Release/hipig.exe
/Users/andot/Git/hprose-dotnet/hipig/hipig/bin/Release/Hprose.Client.dll
Binary file added hipig/hipig/obj/Release/hipig.exe
Binary file not shown.

0 comments on commit 5970f6c

Please sign in to comment.