2
0

MetaDataCodeGenerator.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. //
  2. // System.Runtime.Remoting.MetadataServices.MetaDataCodeGenerator
  3. //
  4. // Authors:
  5. // Lluis Sanchez Gual ([email protected])
  6. //
  7. // (C) 2003 Novell, Inc
  8. //
  9. using System.Collections;
  10. using System.IO;
  11. using System.Xml;
  12. using System.Reflection;
  13. using System.Runtime.Remoting;
  14. using System.Runtime.Remoting.Metadata;
  15. namespace System.Runtime.Remoting.MetadataServices
  16. {
  17. internal class MetaDataCodeGenerator
  18. {
  19. XmlDocument doc;
  20. CodeFile currentFile;
  21. XmlNamespaceManager nsManager;
  22. Hashtable sudsTypes;
  23. public void GenerateCode (bool clientProxy, string outputDirectory, Stream inputStream,
  24. ArrayList outCodeStreamList, string proxyUrl, string proxyNamespace)
  25. {
  26. doc = new XmlDocument ();
  27. doc.Load (inputStream);
  28. nsManager = new XmlNamespaceManager (doc.NameTable);
  29. nsManager.AddNamespace ("wsdl", MetaData.WsdlNamespace);
  30. nsManager.AddNamespace ("s", MetaData.SchemaNamespace);
  31. nsManager.AddNamespace ("suds", MetaData.SudsNamespace);
  32. if (outputDirectory == null) outputDirectory = Directory.GetCurrentDirectory();
  33. CodeFile mainFile = new CodeFile (outputDirectory);
  34. CodeFile interopFile = new CodeFile (outputDirectory);
  35. currentFile = mainFile;
  36. // Suds types
  37. sudsTypes = new Hashtable ();
  38. XmlNodeList nodes = doc.DocumentElement.SelectNodes ("wsdl:binding/suds:class|wsdl:binding/suds:interface|wsdl:binding/suds:struct", nsManager);
  39. foreach (XmlElement node in nodes)
  40. sudsTypes [GetTypeQualifiedName (node, node.GetAttribute ("type"))] = node;
  41. // Data types
  42. nodes = doc.SelectNodes ("wsdl:definitions/wsdl:types/s:schema", nsManager);
  43. foreach (XmlElement schema in nodes)
  44. GenerateSchemaCode (schema);
  45. // Services
  46. nodes = doc.SelectNodes ("wsdl:definitions/wsdl:service/wsdl:port", nsManager);
  47. foreach (XmlElement port in nodes)
  48. GeneratePortCode (port);
  49. mainFile.Write ();
  50. if (mainFile.FileName != null)
  51. outCodeStreamList.Add (mainFile.FilePath);
  52. }
  53. void GeneratePortCode (XmlElement port)
  54. {
  55. XmlElement binding = GetBinding (port.GetAttribute ("binding"));
  56. XmlElement type = null;
  57. foreach (XmlNode node in binding)
  58. if ((node is XmlElement) && ((XmlElement)node).NamespaceURI == MetaData.SudsNamespace)
  59. { type = (XmlElement) node; break; }
  60. string rootType = type.GetAttribute ("rootType");
  61. if (rootType == "Delegate")
  62. GenerateServiceDelegateCode (port, binding, type);
  63. else
  64. GenerateServiceClassCode (port, binding, type);
  65. }
  66. void GenerateServiceDelegateCode (XmlElement port, XmlElement binding, XmlElement type)
  67. {
  68. string typeName = (type != null) ? type.GetAttribute ("type") : port.GetAttribute ("name");
  69. string portName = GetNameFromQn (binding.GetAttribute ("type"));
  70. string name, ns;
  71. GetTypeQualifiedName (port, typeName, out name, out ns);
  72. currentFile.SetCurrentNamespace (ns);
  73. XmlElement oper = (XmlElement) binding.SelectSingleNode ("wsdl:operation[@name='Invoke']", nsManager);
  74. if (oper == null) throw new InvalidOperationException ("Invalid delegate schema");
  75. string parsDec;
  76. string returnType;
  77. GetParameters (oper, portName, "Invoke", out parsDec, out returnType);
  78. currentFile.WriteLine ("public delegate " + returnType + " " + name + " (" + parsDec + ");");
  79. currentFile.WriteLine ("");
  80. }
  81. void GenerateServiceClassCode (XmlElement port, XmlElement binding, XmlElement type)
  82. {
  83. string typeName = (type != null) ? type.GetAttribute ("type") : port.GetAttribute ("name");
  84. string name, ns;
  85. GetTypeQualifiedName (port, typeName, out name, out ns);
  86. currentFile.SetCurrentNamespace (ns);
  87. string cls = "public " + type.LocalName + " " + name;
  88. string baset = type.GetAttribute ("extends");
  89. if (baset != "") cls += ": " + GetTypeQualifiedName (port, baset);
  90. // Interfaces
  91. XmlNodeList interfaces = type.SelectNodes ("suds:implements",nsManager);
  92. if (interfaces.Count == 0) interfaces = type.SelectNodes ("suds:extends",nsManager);
  93. foreach (XmlElement interf in interfaces)
  94. {
  95. string iname = GetTypeQualifiedName (interf, interf.GetAttribute ("type"));
  96. if (cls.IndexOf (':') == -1) cls += ": " + iname;
  97. else cls += ", " + iname;
  98. }
  99. currentFile.WriteLine (cls);
  100. currentFile.WriteLineInd ("{");
  101. string portName = GetNameFromQn (binding.GetAttribute ("type"));
  102. bool isInterface = type.LocalName == "interface";
  103. string vis = isInterface? "":"public ";
  104. ArrayList mets = GetMethods (portName, binding);
  105. foreach (MethodData met in mets)
  106. {
  107. if (met.IsProperty)
  108. {
  109. string prop = vis + met.ReturnType + " ";
  110. if (met.Signature != "") prop += "this [" + met.Signature + "]";
  111. else prop += met.Name;
  112. if (isInterface)
  113. {
  114. prop += " { ";
  115. if (met.HasGet) prop += "get; ";
  116. if (met.HasSet) prop += "set; ";
  117. prop += "}";
  118. currentFile.WriteLine (prop);
  119. }
  120. else
  121. {
  122. currentFile.WriteLine (prop);
  123. currentFile.WriteLineInd ("{");
  124. if (met.HasGet) currentFile.WriteLine ("get { throw new NotImplementedException (); }");
  125. if (met.HasSet) currentFile.WriteLine ("set { throw new NotImplementedException (); }");
  126. currentFile.WriteLineUni ("}");
  127. currentFile.WriteLine ("");
  128. }
  129. }
  130. else
  131. {
  132. currentFile.WriteLine (vis + met.ReturnType + " " + met.Name + " (" + met.Signature + ")" + (isInterface?";":""));
  133. if (!isInterface)
  134. {
  135. currentFile.WriteLineInd ("{");
  136. currentFile.WriteLine ("throw new NotImplementedException ();");
  137. currentFile.WriteLineUni ("}");
  138. currentFile.WriteLine ("");
  139. }
  140. }
  141. }
  142. currentFile.WriteLineUni ("}");
  143. currentFile.WriteLine ("");
  144. }
  145. class MethodData
  146. {
  147. public string ReturnType;
  148. public string Signature;
  149. public string Name;
  150. public bool HasSet;
  151. public bool HasGet;
  152. public bool IsProperty { get { return HasGet || HasSet; } }
  153. }
  154. ArrayList GetMethods (string portName, XmlElement binding)
  155. {
  156. ArrayList mets = new ArrayList ();
  157. XmlNodeList nodes = binding.SelectNodes ("wsdl:operation", nsManager);
  158. foreach (XmlElement oper in nodes)
  159. {
  160. MethodData md = new MethodData ();
  161. md.Name = oper.GetAttribute ("name");
  162. GetParameters (oper, portName, md.Name, out md.Signature, out md.ReturnType);
  163. if (md.Name.StartsWith ("set_") || md.Name.StartsWith ("get_"))
  164. {
  165. string tmp = ", " + md.Signature;
  166. if (tmp.IndexOf (", out ") == -1 && tmp.IndexOf (", ref ") == -1)
  167. {
  168. bool isSet = md.Name[0]=='s';
  169. md.Name = md.Name.Substring (4);
  170. MethodData previousProp = null;
  171. foreach (MethodData fmd in mets)
  172. if (fmd.Name == md.Name && fmd.IsProperty)
  173. previousProp = fmd;
  174. if (previousProp != null) {
  175. if (isSet) previousProp.HasSet = true;
  176. else { previousProp.HasGet = true; previousProp.Signature = md.Signature; }
  177. continue;
  178. }
  179. else {
  180. if (isSet) { md.HasSet = true; md.Signature = ""; }
  181. else md.HasGet = true;
  182. }
  183. }
  184. }
  185. mets.Add (md);
  186. }
  187. return mets;
  188. }
  189. void GetParameters (XmlElement oper, string portName, string operName, out string signature, out string returnType)
  190. {
  191. returnType = null;
  192. XmlElement portType = (XmlElement) doc.SelectSingleNode ("wsdl:definitions/wsdl:portType[@name='" + portName + "']", nsManager);
  193. XmlElement portOper = (XmlElement) portType.SelectSingleNode ("wsdl:operation[@name='" + operName + "']", nsManager);
  194. string[] parNames = portOper.GetAttribute ("parameterOrder").Split (' ');
  195. XmlElement inPortMsg = (XmlElement) portOper.SelectSingleNode ("wsdl:input", nsManager);
  196. XmlElement inMsg = FindMessageFromPortMessage (inPortMsg);
  197. XmlElement outPortMsg = (XmlElement) portOper.SelectSingleNode ("wsdl:output", nsManager);
  198. XmlElement outMsg = FindMessageFromPortMessage (outPortMsg);
  199. string[] parameters;
  200. if (parNames [0] != "") parameters = new string [parNames.Length];
  201. else parameters = new string [0];
  202. foreach (XmlElement part in inMsg.SelectNodes ("wsdl:part",nsManager))
  203. {
  204. int i = Array.IndexOf (parNames, part.GetAttribute ("name"));
  205. string type = GetTypeQualifiedName (part, part.GetAttribute ("type"));
  206. parameters [i] = type + " " + parNames [i];
  207. }
  208. foreach (XmlElement part in outMsg.SelectNodes ("wsdl:part",nsManager))
  209. {
  210. string pn = part.GetAttribute ("name");
  211. string type = GetTypeQualifiedName (part, part.GetAttribute ("type"));
  212. if (pn == "return")
  213. returnType = type;
  214. else {
  215. int i = Array.IndexOf (parNames, pn);
  216. if (parameters [i] != null) parameters [i] = "ref " + parameters [i];
  217. else parameters [i] = "out " + type + " " + pn;
  218. }
  219. }
  220. signature = string.Join (", ", parameters);
  221. if (returnType == null) returnType = "void";
  222. }
  223. XmlElement FindMessageFromPortMessage (XmlElement portMsg)
  224. {
  225. string msgName = portMsg.GetAttribute ("message");
  226. msgName = GetNameFromQn (msgName);
  227. return (XmlElement) doc.SelectSingleNode ("wsdl:definitions/wsdl:message[@name='" + msgName + "']", nsManager);
  228. }
  229. void GenerateSchemaCode (XmlElement schema)
  230. {
  231. string ns = schema.GetAttribute ("targetNamespace");
  232. string clrNs = DecodeNamespace (ns);
  233. currentFile.SetCurrentNamespace (clrNs);
  234. foreach (XmlNode node in schema)
  235. {
  236. XmlElement elem = node as XmlElement;
  237. if (elem == null) continue;
  238. if (elem.LocalName == "complexType")
  239. GenerateClassCode (ns, elem);
  240. else if (elem.LocalName == "simpleType")
  241. GenerateEnumCode (ns, elem);
  242. }
  243. }
  244. void GenerateClassCode (string ns, XmlElement elem)
  245. {
  246. if (elem.SelectSingleNode ("s:complexContent/s:restriction", nsManager) != null) return;
  247. string clrNs = DecodeNamespace (ns);
  248. string typeName = GetTypeName (elem.GetAttribute ("name"), ns);
  249. XmlElement sudsType = (XmlElement) sudsTypes [clrNs + "." + typeName];
  250. string typetype = "class";
  251. if (sudsType != null) typetype = sudsType.LocalName;
  252. currentFile.WriteLine ("[Serializable, SoapType (XmlNamespace = @\"" + ns + "\", XmlTypeNamespace = @\"" + ns + "\")]");
  253. string cls = "public " + typetype + " " + typeName;
  254. string baseType = elem.GetAttribute ("base");
  255. if (baseType != "") cls += ": " + GetTypeQualifiedName (elem, baseType);
  256. bool isSerializable = (sudsType.GetAttribute ("rootType") == "ISerializable");
  257. if (isSerializable)
  258. {
  259. if (cls.IndexOf (':') == -1) cls += ": ";
  260. else cls += ", ";
  261. cls += "System.Runtime.Serialization.ISerializable";
  262. }
  263. currentFile.WriteLine (cls);
  264. currentFile.WriteLineInd ("{");
  265. XmlNodeList elems = elem.GetElementsByTagName ("element", MetaData.SchemaNamespace);
  266. foreach (XmlElement elemField in elems)
  267. WriteField (elemField);
  268. elems = elem.GetElementsByTagName ("attribute", MetaData.SchemaNamespace);
  269. foreach (XmlElement elemField in elems)
  270. WriteField (elemField);
  271. if (isSerializable)
  272. {
  273. currentFile.WriteLine ("");
  274. currentFile.WriteLine ("public " + typeName + " ()");
  275. currentFile.WriteLineInd ("{");
  276. currentFile.WriteLineUni ("}");
  277. currentFile.WriteLine ("");
  278. currentFile.WriteLine ("public " + typeName + " (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)");
  279. currentFile.WriteLineInd ("{");
  280. currentFile.WriteLine ("throw new NotImplementedException ();");
  281. currentFile.WriteLineUni ("}");
  282. currentFile.WriteLine ("");
  283. currentFile.WriteLine ("public void GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)");
  284. currentFile.WriteLineInd ("{");
  285. currentFile.WriteLine ("throw new NotImplementedException ();");
  286. currentFile.WriteLineUni ("}");
  287. }
  288. currentFile.WriteLineUni ("}");
  289. currentFile.WriteLine ("");
  290. }
  291. void WriteField (XmlElement elemField)
  292. {
  293. bool isAttr = elemField.LocalName == "attribute";
  294. string type = elemField.GetAttribute ("type");
  295. if (isAttr)
  296. currentFile.WriteLine ("[SoapField (UseAttribute = true)]");
  297. else if (!IsPrimitive (elemField, type))
  298. currentFile.WriteLine ("[SoapField (Embedded = true)]");
  299. currentFile.WriteLine ("public " + GetTypeQualifiedName (elemField, type) + " " + elemField.GetAttribute ("name") + ";");
  300. }
  301. void GenerateEnumCode (string ns, XmlElement elem)
  302. {
  303. currentFile.WriteLine ("public enum " + GetTypeName (elem.GetAttribute ("name"), ns));
  304. currentFile.WriteLineInd ("{");
  305. XmlNodeList nodes = elem.SelectNodes ("s:restriction/s:enumeration/@value", nsManager);
  306. foreach (XmlNode node in nodes)
  307. currentFile.WriteLine (node.Value + ",");
  308. currentFile.WriteLineUni ("}");
  309. currentFile.WriteLine ("");
  310. }
  311. bool IsPrimitive (XmlNode node, string qname)
  312. {
  313. string name = GetTypeQualifiedName (node, qname);
  314. return name.IndexOf ('.') == -1;
  315. }
  316. string GetTypeName (string localName, string ns)
  317. {
  318. return localName;
  319. }
  320. void GetTypeQualifiedName (XmlNode node, string qualifiedName, out string name, out string ns)
  321. {
  322. int i = qualifiedName.IndexOf (':');
  323. if (i == -1)
  324. {
  325. name = qualifiedName;
  326. ns = "";
  327. return;
  328. }
  329. string prefix = qualifiedName.Substring (0,i);
  330. name = qualifiedName.Substring (i+1);
  331. ns = node.GetNamespaceOfPrefix (prefix);
  332. string arrayType = GetArrayType (node, name, ns);
  333. if (arrayType != null) {
  334. name = arrayType;
  335. ns = "";
  336. }
  337. else if (ns != MetaData.SchemaNamespace) {
  338. ns = DecodeNamespace (ns);
  339. }
  340. else {
  341. ns = "";
  342. name = GetClrFromXsd (name);
  343. }
  344. }
  345. string GetClrFromXsd (string type)
  346. {
  347. switch (type)
  348. {
  349. case "boolean": return "bool";
  350. case "unsignedByte": return "byte";
  351. case "char": return "char";
  352. case "dateTime": return "DateTime";
  353. case "decimal": return "decimal";
  354. case "double": return "double";
  355. case "short": return "short";
  356. case "int": return "int";
  357. case "long": return "long";
  358. case "byte": return "sbyte";
  359. case "float": return "float";
  360. case "unsignedShort": return "ushort";
  361. case "unsignedInt": return "uint";
  362. case "unsignedLong": return "ulong";
  363. case "string": return "string";
  364. case "duration": return "TimeSpan";
  365. case "anyType": return "object";
  366. }
  367. throw new InvalidOperationException ("Unknown schema type: " + type);
  368. }
  369. string GetTypeQualifiedName (XmlNode node, string qualifiedName)
  370. {
  371. string name, ns;
  372. GetTypeQualifiedName (node, qualifiedName, out name, out ns);
  373. if (ns != "") return ns + "." + name;
  374. else return name;
  375. }
  376. string GetTypeNamespace (XmlNode node, string qualifiedName)
  377. {
  378. string name, ns;
  379. GetTypeQualifiedName (node, qualifiedName, out name, out ns);
  380. return ns;
  381. }
  382. string GetArrayType (XmlNode node, string name, string ns)
  383. {
  384. XmlNode anod = doc.SelectSingleNode ("wsdl:definitions/wsdl:types/s:schema[@targetNamespace='" + ns + "']/s:complexType[@name='" + name + "']/s:complexContent/s:restriction/s:attribute/@wsdl:arrayType", nsManager);
  385. if (anod == null) return null;
  386. string atype = anod.Value;
  387. int i = atype.IndexOf ('[');
  388. string itemType = GetTypeQualifiedName (node, atype.Substring (0,i));
  389. return itemType + atype.Substring (i);
  390. }
  391. XmlElement GetBinding (string name)
  392. {
  393. int i = name.IndexOf (':');
  394. name = name.Substring (i+1);
  395. return doc.SelectSingleNode ("wsdl:definitions/wsdl:binding[@name='" + name + "']", nsManager) as XmlElement;
  396. }
  397. string DecodeNamespace (string xmlNamespace)
  398. {
  399. string tns, tasm;
  400. if (!SoapServices.DecodeXmlNamespaceForClrTypeNamespace (xmlNamespace, out tns, out tasm))
  401. tns = xmlNamespace;
  402. return tns;
  403. }
  404. string GetLiteral (object ob)
  405. {
  406. if (ob == null) return "null";
  407. if (ob is string) return "\"" + ob.ToString().Replace("\"","\"\"") + "\"";
  408. if (ob is bool) return ((bool)ob) ? "true" : "false";
  409. if (ob is XmlQualifiedName) {
  410. XmlQualifiedName qn = (XmlQualifiedName)ob;
  411. return "new XmlQualifiedName (" + GetLiteral(qn.Name) + "," + GetLiteral(qn.Namespace) + ")";
  412. }
  413. else return ob.ToString ();
  414. }
  415. string Params (params string[] pars)
  416. {
  417. string res = "";
  418. foreach (string p in pars)
  419. {
  420. if (res != "") res += ", ";
  421. res += p;
  422. }
  423. return res;
  424. }
  425. string GetNameFromQn (string qn)
  426. {
  427. int i = qn.IndexOf (':');
  428. if (i == -1) return qn;
  429. else return qn.Substring (i+1);
  430. }
  431. }
  432. class CodeFile
  433. {
  434. public string FileName;
  435. public string Directory;
  436. public string FilePath;
  437. Hashtable namespaces = new Hashtable ();
  438. public StringWriter writer;
  439. int indent;
  440. string currentNamespace;
  441. public CodeFile (string directory)
  442. {
  443. Directory = directory;
  444. }
  445. public void SetCurrentNamespace (string ns)
  446. {
  447. writer = namespaces [ns] as StringWriter;
  448. if (writer == null)
  449. {
  450. indent = 0;
  451. writer = new StringWriter ();
  452. namespaces [ns] = writer;
  453. WriteLine ("namespace " + ns);
  454. WriteLineInd ("{");
  455. }
  456. indent = 1;
  457. if (FileName == null)
  458. FileName = ns + ".cs";
  459. }
  460. public void WriteLineInd (string code)
  461. {
  462. WriteLine (code);
  463. indent++;
  464. }
  465. public void WriteLineUni (string code)
  466. {
  467. if (indent > 0) indent--;
  468. WriteLine (code);
  469. }
  470. public void WriteLine (string code)
  471. {
  472. if (code != "") writer.Write (new String ('\t',indent));
  473. writer.WriteLine (code);
  474. }
  475. public void Write ()
  476. {
  477. if (FileName == null) return;
  478. FilePath = Path.Combine (Directory, FileName);
  479. StreamWriter sw = new StreamWriter (FilePath);
  480. sw.WriteLine ("using System;");
  481. sw.WriteLine ("using System.Runtime.Remoting.Metadata;");
  482. sw.WriteLine ();
  483. foreach (StringWriter nsWriter in namespaces.Values)
  484. {
  485. sw.Write (nsWriter.ToString ());
  486. sw.WriteLine ("}");
  487. sw.WriteLine ();
  488. }
  489. sw.Close ();
  490. }
  491. }
  492. }