Back to index

nordugrid-arc-nox  1.1.0~rc6
SOAPEnvelope.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <cstring>
00006 
00007 #include "SOAPEnvelope.h"
00008 
00009 namespace Arc {
00010 
00011 SOAPEnvelope::SOAPEnvelope(const std::string& s):XMLNode(s) {
00012   set();
00013 }
00014 
00015 SOAPEnvelope::SOAPEnvelope(const char* s,int l):XMLNode(s,l) {
00016   set();
00017 }
00018 
00019 SOAPEnvelope::SOAPEnvelope(const SOAPEnvelope& soap):XMLNode(),fault(NULL) {
00020   soap.envelope.New(*this);
00021   set();
00022 }
00023 
00024 SOAPEnvelope::SOAPEnvelope(const NS& ns,bool f):XMLNode(ns,"Envelope"),fault(NULL) {
00025   XMLNode& it = *this;
00026   if(!it) return;
00027   ver12=false;
00028   for(NS::const_iterator i = ns.begin();i!=ns.end();++i) {
00029     if(i->second == "http://www.w3.org/2003/05/soap-envelope") {
00030       ver12=true; break;
00031     };
00032   };
00033   NS ns_;
00034   if(ver12) {
00035     ns_["soap-enc"]="http://www.w3.org/2003/05/soap-encoding";
00036     ns_["soap-env"]="http://www.w3.org/2003/05/soap-envelope";
00037   } else {
00038     ns_["soap-enc"]="http://schemas.xmlsoap.org/soap/encoding/";
00039     ns_["soap-env"]="http://schemas.xmlsoap.org/soap/envelope/";
00040   };
00041   ns_["xsi"]="http://www.w3.org/2001/XMLSchema-instance";
00042   ns_["xsd"]="http://www.w3.org/2001/XMLSchema";
00043   XMLNode::Namespaces(ns_);
00044   // XMLNode::Namespaces(ns); 
00045   XMLNode::Name("soap-env:Envelope"); // Fixing namespace
00046   header=XMLNode::NewChild("soap-env:Header");
00047   body=XMLNode::NewChild("soap-env:Body");
00048   envelope=it; ((SOAPEnvelope*)(&envelope))->is_owner_=true;
00049   XMLNode::is_owner_=false; XMLNode::node_=((SOAPEnvelope*)(&body))->node_;
00050   if(f) {
00051     XMLNode fault_n = body.NewChild("soap-env:Fault");
00052     if(ver12) {
00053       XMLNode code_n = fault_n.NewChild("soap-env:Code");
00054       XMLNode reason_n = fault_n.NewChild("soap-env:Reason");
00055       reason_n.NewChild("soap-env:Text")="unknown";
00056       code_n.NewChild("soap-env:Value")="soap-env:Receiver";
00057     } else {
00058       XMLNode code_n = fault_n.NewChild("soap-env:faultcode");
00059       XMLNode reason_n = fault_n.NewChild("soap-env:faultstring");
00060       reason_n.NewChild("soap-env:Text")="unknown";
00061       code_n.NewChild("soap-env:Value")="soap-env:Server";
00062     };
00063     fault=new SOAPFault(body);
00064   };
00065 }
00066 
00067 SOAPEnvelope::SOAPEnvelope(XMLNode root):XMLNode(root),fault(NULL) {
00068   if(!node_) return;
00069   if(node_->type != XML_ELEMENT_NODE) { node_=NULL; return; };
00070   set();
00071 }
00072 
00073 SOAPEnvelope::~SOAPEnvelope(void) {
00074   if(fault) delete fault;
00075 }
00076 
00077 // This function is only called from constructor
00078 void SOAPEnvelope::set(void) {
00079   fault=NULL;
00080   XMLNode& it = *this;
00081   if(!it) return;
00082   ver12=false;
00083   if(!it.NamespacePrefix("http://www.w3.org/2003/05/soap-envelope").empty()) ver12=true;
00084   NS ns;
00085   if(ver12) {
00086     ns["soap-enc"]="http://www.w3.org/2003/05/soap-encoding";
00087     ns["soap-env"]="http://www.w3.org/2003/05/soap-envelope";
00088   } else {
00089     ns["soap-enc"]="http://schemas.xmlsoap.org/soap/encoding/";
00090     ns["soap-env"]="http://schemas.xmlsoap.org/soap/envelope/";
00091   };
00092   ns["xsi"]="http://www.w3.org/2001/XMLSchema-instance";
00093   ns["xsd"]="http://www.w3.org/2001/XMLSchema";
00094   // Do not apply deeper than Envelope + Header/Body + Fault
00095   it.Namespaces(ns,true,2);
00096   envelope = it;
00097   if((!envelope) || (!MatchXMLName(envelope,"soap-env:Envelope"))) {
00098     // No SOAP Envelope found
00099     if(is_owner_) xmlFreeDoc(node_->doc); node_=NULL;
00100     return;
00101   };
00102   if(MatchXMLName(envelope.Child(0),"soap-env:Header")) {
00103     // SOAP has Header
00104     header=envelope.Child(0);
00105     body=envelope.Child(1);
00106   } else {
00107     // SOAP has no header - create an empty one
00108     body=envelope.Child(0);
00109     header=envelope.NewChild("soap-env:Header",0,true);
00110   };
00111   if(!MatchXMLName(body,"soap-env:Body")) {
00112     // No SOAP Body found
00113     if(is_owner_) xmlFreeDoc(node_->doc); node_=NULL;
00114     return;
00115   };
00116   // Transfer ownership.
00117   ((SOAPEnvelope*)(&envelope))->is_owner_=is_owner_; // true
00118   // Make this object represent SOAP Body
00119   is_owner_=false; 
00120   this->node_=((SOAPEnvelope*)(&body))->node_;
00121   // Check if this message is fault
00122   fault = new SOAPFault(body);
00123   if(!(*fault)) {
00124     delete fault; fault=NULL;
00125   } else {
00126     // Apply namespaces to Fault element
00127     body.Namespaces(ns);
00128   }
00129 }
00130 
00131 SOAPEnvelope* SOAPEnvelope::New(void) {
00132   XMLNode new_envelope;
00133   envelope.New(new_envelope);
00134   SOAPEnvelope* new_soap = new SOAPEnvelope(new_envelope);
00135   if(new_soap) {
00136     ((SOAPEnvelope*)(&(new_soap->envelope)))->is_owner_=true;
00137     ((SOAPEnvelope*)(&new_envelope))->is_owner_=false;
00138   };
00139   return new_soap;
00140 }
00141 
00142 void SOAPEnvelope::Swap(SOAPEnvelope& soap) {
00143   bool ver12_tmp = ver12;
00144   ver12=soap.ver12; soap.ver12=ver12_tmp;
00145   SOAPFault* fault_tmp = fault;
00146   fault=soap.fault; soap.fault=fault_tmp;
00147   envelope.Swap(soap.envelope);
00148   header.Swap(soap.header);
00149   body.Swap(soap.body);
00150   XMLNode::Swap(soap);
00151 }
00152 
00153 void SOAPEnvelope::Swap(Arc::XMLNode& soap) {
00154   XMLNode& it = *this;
00155   envelope.Swap(soap);
00156   it.Swap(envelope);
00157   envelope=XMLNode();
00158   body=XMLNode();
00159   header=XMLNode();
00160   ver12=false;
00161   fault=NULL;
00162   set();
00163 }
00164 
00165 void SOAPEnvelope::Namespaces(const NS& namespaces) {
00166   envelope.Namespaces(namespaces);
00167 }
00168 
00169 NS SOAPEnvelope::Namespaces(void) {
00170   return (envelope.Namespaces());
00171 }
00172 
00173 void SOAPEnvelope::GetXML(std::string& out_xml_str,bool user_friendly) const {
00174   if(header.Size() == 0) {
00175     SOAPEnvelope& it = *(SOAPEnvelope*)this;
00176     it.header.Destroy();
00177     envelope.GetXML(out_xml_str,user_friendly);
00178     it.header=it.envelope.NewChild("soap-env:Header",0,true);
00179     return;
00180   };
00181   envelope.GetXML(out_xml_str,user_friendly);
00182 }
00183 
00184 SOAPFault::SOAPFault(XMLNode body) {
00185   // TODO: set namespaces
00186   if(body.Size() != 1) return;
00187   fault=body.Child(0);
00188   if(!MatchXMLName(fault,"soap-env:Fault")) { fault=XMLNode(); return; };
00189   code=fault["soap-env:faultcode"];
00190   if(code) {
00191     ver12=false;
00192     reason=fault["soap-env:faultstring"];
00193     node=fault["soap-env:faultactor"];
00194     role=XMLNode();
00195     detail=fault["soap-env:detail"];
00196     return;
00197   };
00198   code=fault["soap-env:Code"];
00199   if(code) {
00200     ver12=true;
00201     reason=fault["soap-env:Reason"];
00202     node=fault["soap-env:Node"];
00203     role=fault["soap-env:Role"];
00204     detail=fault["soap-env:Detail"];
00205     return;
00206   };
00207   fault=XMLNode();
00208   return;
00209 }
00210 
00211 SOAPFault::SOAPFault(XMLNode body,SOAPFaultCode c,const char* r) {
00212   //bool ver12 = (body.Namespace() == "http://www.w3.org/2003/05/soap-envelope");
00213   fault=body.NewChild("soap-env:Fault");
00214   if(!fault) return;
00215   Code(c);
00216   Reason(0,r);
00217 }
00218 
00219 SOAPFault::SOAPFault(XMLNode body,SOAPFaultCode c,const char* r,bool v12) {
00220   ver12=v12;
00221   fault=body.NewChild("soap-env:Fault");
00222   if(!fault) return;
00223   Code(c);
00224   Reason(0,r);
00225 }
00226 
00227 std::string SOAPFault::Reason(int num) {
00228   if(ver12) return reason.Child(num);
00229   if(num != 0) return "";
00230   return reason; 
00231 }
00232 
00233 void SOAPFault::Reason(int num,const char* r) {
00234   if(ver12) {
00235     if(!reason) reason=fault.NewChild("soap-env:Reason");
00236     XMLNode rn = reason.Child(num);
00237     if(!rn) rn=reason.NewChild("soap-env:Text");
00238     rn=r;
00239     return;
00240   };
00241   if(!reason) reason=fault.NewChild("soap-env:faultstring");
00242   reason=r;
00243   return;
00244 }
00245 
00246 std::string SOAPFault::Node(void) {
00247   return node;
00248 }
00249 
00250 void SOAPFault::Node(const char* n) {
00251   if(!node) {
00252     if(ver12) {
00253       node=fault.NewChild("soap-env:Node");
00254     } else {
00255       node=fault.NewChild("soap-env:faultactor");
00256     };
00257   };
00258   node=n;
00259 }
00260 
00261 std::string SOAPFault::Role(void) {
00262   return role;
00263 }
00264 
00265 void SOAPFault::Role(const char* r) {
00266   if(ver12) {
00267     if(!role) role=fault.NewChild("soap-env:Role");
00268     role=r;
00269   };
00270 }
00271 
00272 static const char* FaultCodeMatch(const char* base,const char* code) {
00273   int l = strlen(base);
00274   if(strncasecmp(base,code,l) != 0) return NULL;
00275   if(code[l] == 0) return code+l;
00276   if(code[l] == '.') return code+l+1;
00277   return NULL;
00278 }
00279 
00280 SOAPFault::SOAPFaultCode SOAPFault::Code(void) {
00281   if(!code) return undefined;
00282   if(ver12) {
00283     std::string c = code["soap-env:Value"];
00284     if(strcasecmp("soap-env:VersionMismatch",c.c_str()) == 0) 
00285       return VersionMismatch;
00286     if(strcasecmp("soap-env:MustUnderstand",c.c_str()) == 0) 
00287       return MustUnderstand;
00288     if(strcasecmp("soap-env:DataEncodingUnknown",c.c_str()) == 0) 
00289       return DataEncodingUnknown;
00290     if(strcasecmp("soap-env:Sender",c.c_str()) == 0) 
00291       return Sender;
00292     if(strcasecmp("soap-env:Receiver",c.c_str()) == 0) 
00293       return Receiver;
00294     return unknown;
00295   } else {
00296     std::string c = code;
00297     if(FaultCodeMatch("soap-env:VersionMismatch",c.c_str())) 
00298       return VersionMismatch;
00299     if(FaultCodeMatch("soap-env:MustUnderstand",c.c_str())) 
00300       return MustUnderstand;
00301     if(FaultCodeMatch("soap-env:Client",c.c_str())) 
00302       return Sender;
00303     if(FaultCodeMatch("soap-env:Server",c.c_str())) 
00304       return Receiver;
00305     return unknown;
00306   };
00307 }
00308 
00309 void SOAPFault::Code(SOAPFaultCode c) {
00310   if(ver12) {
00311     if(!code) code=fault.NewChild("soap-env:Code");
00312     XMLNode value = code["soap-env:Value"];
00313     if(!value) value=code.NewChild("soap-env:Value");
00314     switch(c) {
00315       case VersionMismatch: value="soap-env:VersionMismatch"; break;
00316       case MustUnderstand: value="soap-env:MustUnderstand"; break;
00317       case DataEncodingUnknown: value="soap-env:DataEncodingUnknown"; break;
00318       case Sender: value="soap-env:Sender"; break;
00319       case Receiver: value="soap-env:Receiver"; break;
00320       default: value="";
00321     };
00322   } else {
00323     if(!code) code=fault.NewChild("soap-env:faultcode");
00324     switch(c) {
00325       case VersionMismatch: code="soap-env:VersionMismatch"; break;
00326       case MustUnderstand: code="soap-env:MustUnderstand"; break;
00327       case Sender: code="soap-env:Client"; break;
00328       case Receiver: code="soap-env:Server"; break;
00329       default: code="";
00330     };
00331   };
00332 }
00333 
00334 std::string SOAPFault::Subcode(int level) {
00335   if(!ver12) return "";
00336   if(level < 0) return "";
00337   if(!code) return "";
00338   XMLNode subcode = code;
00339   for(;level;--level) {
00340     subcode=subcode["soap-env:Subcode"];
00341     if(!subcode) return "";
00342   };
00343   return subcode["soap-env:Value"];
00344 }
00345 
00346 void SOAPFault::Subcode(int level,const char* s) {
00347   if(!ver12) return;
00348   if(level < 0) return;
00349   if(!code) code=fault.NewChild("soap-env:Code");
00350   XMLNode subcode = code;
00351   for(;level;--level) {
00352     XMLNode subcode_ = subcode["soap-env:Subcode"];
00353     if(!subcode_) subcode_=subcode.NewChild("soap-env:Subcode");
00354     subcode=subcode_;
00355   };
00356   if(!subcode["soap-env:Value"]) {
00357     subcode.NewChild("soap-env:Value")=s;
00358   } else {
00359     subcode["soap-env:Value"]=s;
00360   };
00361 }
00362 
00363 XMLNode SOAPFault::Detail(bool create) {
00364   if(detail) return detail;
00365   if(!create) return XMLNode();
00366   if(!ver12) {
00367     detail=fault.NewChild("soap-env:detail");
00368   } else {
00369     detail=fault.NewChild("soap-env:Detail");
00370   };
00371   return detail;
00372 }
00373 
00374 SOAPEnvelope& SOAPEnvelope::operator=(const SOAPEnvelope& soap) {
00375   if(fault) delete fault;
00376   fault=NULL;
00377   envelope=XMLNode();
00378   header=XMLNode();
00379   body=XMLNode();
00380   soap.envelope.New(*this);
00381   set();
00382   return *this;
00383 }
00384 
00385 SOAPEnvelope* SOAPFault::MakeSOAPFault(SOAPFaultCode code,const std::string& reason) {
00386   SOAPEnvelope* out = new SOAPEnvelope(NS(),true);
00387   if(!out) return NULL;
00388   SOAPFault* fault = out->Fault();
00389   if(!fault) { delete out; return NULL; };
00390   fault->Code(code);
00391   fault->Reason(reason);
00392   return out;
00393 }
00394 
00395 } // namespace Arc