1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.web.soap.service.parser.bindingparser;
7 
8 import std.array : split, join;
9 import std..string : format;
10 
11 import diamond.dom;
12 import diamond.xml;
13 import diamond.web.soap.service.message;
14 import diamond.web.soap.service.messageoperation;
15 import diamond.errors.exceptions.soapexception;
16 
17 package(diamond.web.soap.service.parser):
18 /**
19 * Parses the bindings of the wsdl file.
20 * Params:
21 *   root =       The root node of the wsdl file.
22 *   operations = The message operations.
23 */
24 string parseBinding(XmlNode root, SoapMessageOperation[][string] operations)
25 {
26   // TODO:
27   /*
28   1. Create a class with the name attribute which inherits interface from type attribute
29   2. Loop through operation tags
30   3. Create the method with parameters.
31   4. Body has to create the soap envelop message and call using soap client.
32   5. Ignore everything else, because it's verbose information we already havve extracted and got.
33   */
34 
35   static const bindingClassFormat = q{
36 final class %s : SoapBinding, I%s
37 {
38   public:
39   final:
40   this()
41   {
42     super();
43   }
44 
45 %s
46 }
47   };
48 
49   static const bindingOperationFormat = "\t@SoapOperation(\"%s\") %s %s(%s) { mixin SoapBindingMethod!(%s); mixin(executeSoapBinding()); }\r\n";
50 
51 /*private string parameters(alias T)()
52 {
53   import __stdtraits = std.traits;
54   import std.array : join;
55 
56   string[] result;
57   enum paramsId = [__stdtraits.ParameterIdentifierTuple!T];
58 
59   static foreach (i; 0 .. paramsId.length)
60   {
61       result ~= __stdtraits.Parameters!T[i].stringof ~ " " ~ paramsId[i];
62   }
63 
64   return result.join(",");
65 }*/
66 
67   string result = q{
68 private mixin template SoapBindingMethod(alias f)
69 {
70   string executeSoapBinding()
71   {
72     return "return new SoapClient.sendRequestFromFunctionDefinition!(" ~ __stdtraits.fullyQualifiedName!f ~ ")(" ~ __stdtraits.ParameterIdentifierTuple!f ~ ");";
73   }
74 }
75   };
76 
77   auto bindingTypes = root.getByTagName("wsdl:binding");
78 
79   if (!bindingTypes || !bindingTypes.length)
80   {
81     bindingTypes = root.getByTagName("xs:binding");
82   }
83 
84   if (!bindingTypes || !bindingTypes.length)
85   {
86     bindingTypes = root.getByTagName("xsd:binding");
87   }
88 
89   if (!bindingTypes || !bindingTypes.length)
90   {
91     bindingTypes = root.getByTagName("binding");
92   }
93 
94   if (bindingTypes && bindingTypes.length)
95   {
96     foreach (bindingType; bindingTypes)
97     {
98       auto name = bindingType.getAttribute("name");
99 
100       if (!name)
101       {
102         throw new SoapException("Missing name for binding.");
103       }
104 
105       auto type = bindingType.getAttribute("type");
106 
107       if (!type)
108       {
109         throw new SoapException("Missing type for binding.");
110       }
111 
112       auto typeName = type.value.split(":").length == 2 ? type.value.split(":")[1] : type.value;
113 
114       auto bindingOperations = operations.get(typeName, null);
115 
116       string operationsResult = "";
117 
118       if (bindingOperations && bindingOperations.length)
119       {
120         foreach (bindingOperation; bindingOperations)
121         {
122           auto bindingOperationNodes = bindingType.getByAttribute("name", bindingOperation.name);
123           auto bindingOperationNode = bindingOperationNodes && bindingOperationNodes.length ? bindingOperationNodes[0] : null;
124 
125           if (bindingOperationNode && (bindingOperationNode.name == "wsdl:operation" || bindingOperationNode.name == "xs:operation" || bindingOperationNode.name == "xsd:operation" || bindingOperationNode.name == "operation"))
126           {
127             auto soapOperations = bindingOperationNode.getByTagName("soap:operation");
128             auto soapOperation = soapOperations && soapOperations.length ? soapOperations[0] : null;
129 
130             auto action = soapOperation && soapOperation.hasAttribute("soapAction") ? soapOperation.getAttribute("soapAction").value : bindingOperation.action;
131 
132             if (!action)
133             {
134               action = "";
135             }
136 
137             operationsResult ~= bindingOperationFormat.format(action, bindingOperation.returnType, bindingOperation.name, bindingOperation.parameters, "I" ~ typeName ~ "." ~ bindingOperation.name);
138           }
139         }
140       }
141 
142       result ~= bindingClassFormat.format(name.value, typeName, operationsResult);
143     }
144   }
145 
146   return result;
147 }