1 /*  $Id: wsdlstr.cpp 512472 2016-08-31 12:38:54Z ivanov $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Andrei Gourianov
27 *
28 * File Description:
29 *   Type info for class generation: includes, used classes, C code etc.
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include "exceptions.hpp"
34 #include "type.hpp"
35 #include "blocktype.hpp"
36 #include "unitype.hpp"
37 #include "classstr.hpp"
38 #include "stdstr.hpp"
39 #include "code.hpp"
40 #include "srcutil.hpp"
41 #include "comments.hpp"
42 #include "statictype.hpp"
43 #include "value.hpp"
44 
45 BEGIN_NCBI_SCOPE
46 
47 
CWsdlTypeStrings(const string & externalName,const string & className,const string & namespaceName,const CDataType * dataType,const CComments & comments)48 CWsdlTypeStrings::CWsdlTypeStrings(
49     const string& externalName,  const string& className,
50     const string& namespaceName, const CDataType* dataType, const CComments& comments)
51     : CParent(externalName, className, namespaceName, dataType, comments)
52 {
53 }
54 
~CWsdlTypeStrings(void)55 CWsdlTypeStrings::~CWsdlTypeStrings(void)
56 {
57 }
58 
59 static
DeclareConstructor(CNcbiOstream & out,const string className)60 CNcbiOstream& DeclareConstructor(CNcbiOstream& out, const string className)
61 {
62     return out <<
63         "    // constructor\n"
64         "    "<<className<<"(void);\n";
65 }
66 
67 static
DeclareDestructor(CNcbiOstream & out,const string className,bool virt)68 CNcbiOstream& DeclareDestructor(CNcbiOstream& out, const string className,
69                                 bool virt)
70 {
71     out <<
72         "    // destructor\n"
73         "    ";
74     if ( virt )
75         out << "virtual ";
76     return out << '~'<<className<<"(void);\n"
77         "\n";
78 }
79 
GenerateTypeCode(CClassContext & ctx) const80 void CWsdlTypeStrings::GenerateTypeCode(CClassContext& ctx) const
81 {
82     string httpclient("CSoapHttpClient");
83     string codeClassName = GetClassNameDT();
84     bool haveUserClass = HaveUserClass();
85     if ( haveUserClass )
86         codeClassName += "_Base";
87     CClassCode code(ctx, codeClassName);
88     code.HPPIncludes().insert("serial/soap/soap_client");
89     code.SetParentClass(httpclient, CNamespace::KNCBINamespace);
90     string methodPrefix = code.GetMethodPrefix();
91 
92     DeclareConstructor(code.ClassPublic(), codeClassName);
93     DeclareDestructor(code.ClassPublic(), codeClassName, haveUserClass);
94 
95     BeginClassDeclaration(ctx);
96     GenerateClassCode(code,
97                       code.ClassPublic(),
98                       methodPrefix, haveUserClass, ctx.GetMethodPrefix());
99 
100     // constructors/destructor code
101     string location("\"\"");
102     ITERATE ( TMembers, i, m_Members ) {
103         if (i->dataType->IsStdType() && i->externalName == "#location") {
104             location = i->defaultValue;
105         }
106     }
107     CNcbiOstream& methods = code.Methods();
108     methods <<
109         "// constructor\n"<<
110         methodPrefix<<codeClassName<<"(void)\n";
111     methods <<
112         "    : " << httpclient << "(\n";
113     methods <<
114         "        " << location << ",\n" <<
115         "        \"" << GetNamespaceName() << "\")\n";
116 
117     methods <<
118         "{\n";
119     code.WriteConstructionCode(methods);
120     methods <<
121         "}\n"
122         "\n";
123 
124     methods <<
125         "// destructor\n"<<
126         methodPrefix<<"~"<<codeClassName<<"(void)\n"
127         "{\n";
128     code.WriteDestructionCode(methods);
129     methods <<
130         "}\n"
131         "\n";
132 }
133 
134 static inline
x_WsdlDataType(const CDataType * type)135 const CWsdlDataType* x_WsdlDataType(const CDataType *type)
136 {
137     return dynamic_cast<const CWsdlDataType*>(type);
138 }
139 
140 static
x_CollectMembers(list<CWsdlTypeStrings::TMembers::const_iterator> & container,const CWsdlDataType * memb_type,const CWsdlTypeStrings::TMembers & members)141 void x_CollectMembers(
142     list<CWsdlTypeStrings::TMembers::const_iterator>& container,
143     const CWsdlDataType* memb_type,
144     const CWsdlTypeStrings::TMembers& members)
145 {
146     CDataMemberContainerType::TMembers memin = memb_type->GetMembers();
147     ITERATE( CDataMemberContainerType::TMembers, mi, memin) {
148         const string& name = (*mi)->GetName();
149         ITERATE ( CWsdlTypeStrings::TMembers, ii, members ) {
150             if (!x_WsdlDataType(ii->dataType) && ii->externalName == name) {
151                 container.push_back(ii);
152             }
153         }
154     }
155 }
156 static
x_IsNullDataType(CWsdlTypeStrings::TMembers::const_iterator i)157 bool x_IsNullDataType(CWsdlTypeStrings::TMembers::const_iterator i)
158 {
159     if (i->ref && i->dataType) {
160         return dynamic_cast<const CNullDataType*>(i->dataType->Resolve()) != 0;
161     }
162     return false;
163 }
164 
GenerateClassCode(CClassCode & code,CNcbiOstream &,const string & methodPrefix,bool,const string &) const165 void CWsdlTypeStrings::GenerateClassCode(
166     CClassCode& code, CNcbiOstream& /*setters*/,
167     const string& methodPrefix, bool /*haveUserClass*/,
168     const string& /*classPrefix*/) const
169 {
170     string ncbiNamespace =
171         code.GetNamespace().GetNamespaceRef(CNamespace::KNCBINamespace);
172     CNcbiOstream& methods = code.Methods();
173     CNcbiOstream& header = code.ClassPublic();
174 
175 // generate member methods
176     ITERATE ( TMembers, i, m_Members ) {
177         const CWsdlDataType* type = x_WsdlDataType(i->dataType);
178         if (!type && i->externalName != "#location") {
179             if ( i->ref ) {
180                 i->type->GeneratePointerTypeCode(code);
181             }
182             else {
183                 i->type->GenerateTypeCode(code);
184             }
185         }
186     }
187 
188     set<string> regOut;
189     ITERATE ( TMembers, i, m_Members ) {
190 
191 // collect operation inputs and outputs
192         const CWsdlDataType* type = x_WsdlDataType(i->dataType);
193         if (!type || type->GetWsdlType() != CWsdlDataType::eWsdlOperation) {
194             continue;
195         }
196 
197         string soapaction("");
198         list<TMembers::const_iterator> headerinputs;
199         list<TMembers::const_iterator> inputs;
200         list<TMembers::const_iterator> headeroutputs;
201         list<TMembers::const_iterator> outputs;
202         // operation
203         CDataMemberContainerType::TMembers memb = type->GetMembers();
204         ITERATE( CDataMemberContainerType::TMembers, m, memb) {
205             const CWsdlDataType* memb_type = x_WsdlDataType((*m)->GetType());
206             if (!memb_type) {
207                 const CDataType* st = (*m)->GetType();
208                 if (st->IsStdType() && st->GetMemberName() == "#soapaction" && st->GetDataMember()) {
209                     soapaction = st->GetDataMember()->GetDefault()->GetXmlString();
210                 }
211                 continue;
212             }
213             switch (memb_type->GetWsdlType()) {
214             case CWsdlDataType::eWsdlHeaderInput:
215                 x_CollectMembers( headerinputs,memb_type, m_Members);
216                 break;
217             case CWsdlDataType::eWsdlInput:
218                 x_CollectMembers( inputs,memb_type, m_Members);
219                 break;
220             case CWsdlDataType::eWsdlHeaderOutput:
221                 x_CollectMembers( headeroutputs,memb_type, m_Members);
222                 break;
223             case CWsdlDataType::eWsdlOutput:
224                 x_CollectMembers( outputs,memb_type, m_Members);
225                 break;
226             default:
227                 break;
228             }
229         }
230 
231 // generate operation code
232 
233         //outputs
234         string methodRet("void");
235         list<string> methodOut;
236         int out_counter=0;
237         size_t out_total = headeroutputs.size() + outputs.size();
238 
239         ITERATE( list<TMembers::const_iterator>, out, headeroutputs) {
240             ++out_counter;
241             string reg("RegisterObjectType(");
242             reg += (*out)->type->GetCType(code.GetNamespace());
243             reg += "::GetTypeInfo);";
244             regOut.insert(reg);
245             string out_param = ncbiNamespace + "CConstRef< " +
246                  (*out)->type->GetCType(code.GetNamespace()) + " >";
247             if (out_total == 1) {
248                 methodRet = out_param;
249             } else {
250                 out_param += "& out" + NStr::IntToString(out_counter);
251                 methodOut.push_back(out_param);
252             }
253         }
254         ITERATE( list<TMembers::const_iterator>, out, outputs) {
255             ++out_counter;
256             string reg("RegisterObjectType(");
257             reg += (*out)->type->GetCType(code.GetNamespace());
258             reg += "::GetTypeInfo);";
259             regOut.insert(reg);
260             string out_param = ncbiNamespace + "CConstRef< " +
261                  (*out)->type->GetCType(code.GetNamespace()) + " >";
262             if (out_total == 1) {
263                 methodRet = out_param;
264             } else {
265                 out_param += "& out" + NStr::IntToString(out_counter);
266                 methodOut.push_back(out_param);
267             }
268         }
269 
270         string separator("\n    ");
271         string hpp_separator("\n        ");
272         string comma_separator = "," + separator;
273         string commahpp_separator = "," + hpp_separator;
274         string inout_separator = "," + separator;
275         string inouthpp_separator = "," + hpp_separator;
276         if (methodOut.empty()) {
277             inout_separator = "";
278             inouthpp_separator = "";
279         }
280 
281         // inputs
282         list<string> methodIn;
283         list<string> methodInNull;
284         int in_counter=0, hin_counter=0;
285         ITERATE( list<TMembers::const_iterator>, in, headerinputs) {
286             ++in_counter;
287             string in_type((*in)->type->GetCType(code.GetNamespace()));
288             string in_name(string("in") + NStr::IntToString(in_counter));
289             if (x_IsNullDataType(*in)) {
290                 methodInNull.push_back(in_type + " " + in_name + ";");
291                 methodInNull.push_back(in_name + ".Set();");
292             } else {
293                 methodIn.push_back(string("const ") + in_type + "& " + in_name);
294             }
295         }
296         hin_counter = in_counter;
297         ITERATE( list<TMembers::const_iterator>, in, inputs) {
298             ++in_counter;
299             string in_type((*in)->type->GetCType(code.GetNamespace()));
300             string in_name(string("in") + NStr::IntToString(in_counter));
301             if (x_IsNullDataType(*in)) {
302                 methodInNull.push_back(in_type + " " + in_name + ";");
303                 methodInNull.push_back(in_name + ".Set();");
304             } else {
305                 methodIn.push_back(string("const ") + in_type + "& " + in_name);
306             }
307         }
308         methodIn.push_back(
309             ncbiNamespace + "CConstRef< " + ncbiNamespace + "CSoapFault" + " >* fault");
310 
311         // declaration
312         header << "\n";
313         i->comments.PrintHPPMember(header);
314         header << "    "
315             << methodRet << separator << i->externalName << "(";
316         header << hpp_separator
317             << NStr::Join(methodOut,commahpp_separator)
318             << inouthpp_separator
319             << NStr::Join(methodIn,commahpp_separator)
320             << " = 0) const;\n";
321 
322         // definition
323         methods
324             << methodRet << "\n"
325             << methodPrefix << i->externalName << "(";
326         methods << separator
327             << NStr::Join(methodOut,comma_separator)
328             << inout_separator
329             << NStr::Join(methodIn,comma_separator)
330             << ") const\n{";
331         if (!methodInNull.empty()) {
332             methods << separator
333                 << NStr::Join(methodInNull,separator);
334         }
335         methods << separator
336             << ncbiNamespace << "CSoapMessage request, response;";
337         for (int p=1; p <= in_counter; ++p) {
338             methods << separator
339                 << "request.AddObject( in" << p
340                 << ", "<< ncbiNamespace;
341             if (p <= hin_counter) {
342                 methods <<  "CSoapMessage::eMsgHeader";
343             } else {
344                 methods <<  "CSoapMessage::eMsgBody";
345             }
346             methods <<  ");";
347         }
348         methods << separator << "Invoke(response,request,fault";
349         if (!soapaction.empty()) {
350             methods << "," << "\"" << soapaction << "\"";
351         }
352         methods << ");";
353         out_counter=0;
354         ITERATE( list<TMembers::const_iterator>, out, headeroutputs) {
355             ++out_counter;
356             methods << separator;
357             if (out_total == 1) {
358                 methods << "return ";
359             } else {
360                 methods << "out" << out_counter << " = ";
361             }
362             methods
363                 << ncbiNamespace << "SOAP_GetKnownObject< "
364                 << (*out)->type->GetCType(code.GetNamespace())
365                 << " >(response, " << ncbiNamespace << "CSoapMessage::eMsgHeader);";
366         }
367         ITERATE( list<TMembers::const_iterator>, out, outputs) {
368             ++out_counter;
369             methods << separator;
370             if (out_total == 1) {
371                 methods << "return ";
372             } else {
373                 methods << "out" << out_counter << " = ";
374             }
375             methods
376                 << ncbiNamespace << "SOAP_GetKnownObject< "
377                 << (*out)->type->GetCType(code.GetNamespace())
378                 << " >(response, " << ncbiNamespace << "CSoapMessage::eMsgBody);";
379         }
380         methods << "\n}\n\n";
381     }
382     ITERATE( set<string>, reg, regOut) {
383         code.AddConstructionCode(*reg);
384     }
385 }
386 
387 END_NCBI_SCOPE
388