Read and process a Dissemino Sphere config XML document. Programs using the Dissemino method (DM) to serve HTTP/S, are invoked with a single XML config file. In the case of the DWE this must either be that of a single webapp with a <webappCfg> root tag, or that of a Dissemino Sphere (a set of one or more webapps), with a <sphereCfg> root tag. Where the program only handles a single webapp (the usual case), the config file must begin with <webappCfg> and describe a single webapp. Only the DWE requires a Dissemino Sphere and thus only the DWE calls this function. Within the <sphereCfg> tag, webapps are declared by either a <webappInternal> OR a <webappProxy> tag. In all cases the DWE will be accepting client connections on behalf of the webaps. Listening ports for the HTTP and/or HTTPS service must be specified, as must the location of any webapp specific security certificates. These parameters in the internal case, are supplied in the webapp config file. In the by proxy case, they are supplied in the <webapp> tag. Indeed, it is the presence of a listening port attribute in the <webapp> tag, that indicates that the webapp is by proxy. Note that should a multiple domain certificate apply, the files for this will be specified as attributes in the <sphereCfg> tag. Note also that webapps are usually in their own directory so where multiple webapps are to be hosted, the sphere file (containing the <sphereCfg> tag), should ideally be in none of them.

Return TypeFunction nameArguments
hzEcodehdsSphere::ReadSphere(hzXmlNode*,)

Declared in file: hzDissemino.h
Defined in file : hdsConfig.cpp

Function Logic:

0:START 1:items 2:unknown 3:items 4:Return E_CONFIG 5:unknown 6:unknown 7:m_dfltSSL_PvtKey 8:ai.NameEQ(sslCert) 9:m_dfltSSL_Cert 10:ai.NameEQ(sslCertCA) 11:m_dfltSSL_CertCA 12:ai.NameEQ(portSTD) 13:items 14:ai.NameEQ(portSSL) 15:items 16:ai.NameEQ(blacklist) 17:m_Blacklist 18:items rc 19:unknown 20:rc items 21:unknown 22:rc items 23:unknown 24:rc items 25:unknown 26:Return rc 27:unknown 28:bReal nPortSSL nPortSTD items items items items items items items 29:unknown 30:unknown 31:unknown 32:appname 33:ai.NameEQ(domain) 34:domain 35:ai.NameEQ(portSTD) 36:items 37:ai.NameEQ(portSSL) 38:items 39:items rc 40:unknown 41:rc items 42:unknown 43:rc items 44:pN->NameEQ(webappInternal) 45:unknown 46:unknown 47:appname 48:ai.NameEQ(domain) 49:domain 50:ai.NameEQ(basedir) 51:baseDir 52:ai.NameEQ(rootfile) 53:rootFile 54:ai.NameEQ(sslPvtKey) 55:pvtKey 56:ai.NameEQ(sslCert) 57:cert 58:ai.NameEQ(sslCertCA) 59:certCA 60:ai.NameEQ(portSTD) 61:items 62:ai.NameEQ(portSSL) 63:items 64:items rc 65:unknown 66:rc items 67:unknown 68:rc items 69:unknown 70:rc items 71:unknown 72:rc items 73:unknown 74:rc items 75:unknown 76:rc items 77:bReal 78:rc items 79:unknown 80:rc items 81:items 82:unknown 83:rc items 84:items 85:unknown 86:rc items 87:items 88:unknown 89:pSE pSE pSE pSE pSE pSE pSE 90:unknown 91:pSE 92:pApp pApp pApp pApp pApp 93:items items 94:items 95:unknown 96:pSE 97:unknown 98:items 99:pApp rc 100:unknown 101:items 102:unknown 103:items 104:items items cfgfile cfgfile cfgfile items rc 105:unknown 106:items 107:items items rc 108:unknown 109:items 110:Return rc

Function body:

hzEcode hdsSphere::ReadSphere (hzXmlNode* pRoot)
{
   //  Category: Dissemino Config
   //  
   //  Read and process a Dissemino Sphere config XML document.
   //  
   //  Programs using the Dissemino method (DM) to serve HTTP/S, are invoked with a single XML config file. In the case of the DWE this must either be that of a single webapp with
   //  a <webappCfg> root tag, or that of a Dissemino Sphere (a set of one or more webapps), with a <sphereCfg> root tag. Where the program only handles a single webapp (the usual
   //  case), the config file must begin with <webappCfg> and describe a single webapp.
   //  
   //  Only the DWE requires a Dissemino Sphere and thus only the DWE calls this function.
   //  
   //  Within the <sphereCfg> tag, webapps are declared by either a <webappInternal> OR a <webappProxy> tag. In all cases the DWE will be accepting client connections on behalf of
   //  the webaps. Listening ports for the HTTP and/or HTTPS service must be specified, as must the location of any webapp specific security certificates. These parameters in the
   //  internal case, are supplied in the webapp config file. In the by proxy case, they are supplied in the <webapp> tag. Indeed, it is the presence of a listening port attribute
   //  in the <webapp> tag, that indicates that the webapp is by proxy.
   //  
   //  Note that should a multiple domain certificate apply, the files for this will be specified as attributes in the <sphereCfg> tag.
   //  
   //  Note also that webapps are usually in their own directory so where multiple webapps are to be hosted, the sphere file (containing the <sphereCfg> tag), should ideally be in
   //  none of them.
   _hzfunc("hdsSphere::ReadSphere") ;
   hzSet   <hzString>  appnames ;  //  Used for checking if appnames are unique
   hzSet   <uint32_t>  ports ;     //  Used for checking if ports are unique
   hzDocXml        X ;             //  The config document
   hzXmlNode*      pN ;            //  Current node
   hdsApp*         pApp ;          //  Webapp pointer
   _sphere_app*    pSE ;           //  Sphere app entry
   hzAttrset       ai ;            //  XML node attribute iterator
   hzDomain        domain ;        //  Webapp domain name
   hzDomain        subdom ;        //  ALternative way of reaching site
   hzString        appname ;       //  Webapp name
   hzString        baseDir ;       //  Webapp base directory
   hzString        rootFile ;      //  Webapp root filename
   hzString        cfgfile ;       //  Webapp config file
   hzString        cookieBase ;    //  Cookie base is set at global level
   hzString        pvtKey ;        //  Webapp private key
   hzString        cert ;          //  Webapp certificate
   hzString        certCA ;        //  Webapp certificate authority
   uint32_t        nA ;            //  Webapp iterator
   uint32_t        nPortSTD ;      //  HTTP port
   uint32_t        nPortSSL ;      //  HTTPS port
   bool            bReal ;         //  Internal app
   hzEcode         rc = E_OK ;     //  Return code
   InitJS_Events() ;
   if (!pRoot->NameEQ("sphereCfg"))
       { m_pLog->Log("Expected root tag of <sphereCfg>. Tag <%s> disallowed\n", pRoot->txtName()) ; return E_CONFIG ; }
   /*
   **  ** Get sphere parameters 
   **      */
   for (ai = pRoot ; ai.Valid() ; ai.Advance())
   {
       if      (ai.NameEQ("sslPvtKey"))    m_dfltSSL_PvtKey = ai.Value() ;
       else if (ai.NameEQ("sslCert"))      m_dfltSSL_Cert = ai.Value() ;
       else if (ai.NameEQ("sslCertCA"))    m_dfltSSL_CertCA = ai.Value() ;
       else if (ai.NameEQ("portSTD"))      m_nCommonPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
       else if (ai.NameEQ("portSSL"))      m_nCommonPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
       else if (ai.NameEQ("blacklist"))    m_Blacklist = ai.Value() ;
       else
       {
           m_pLog->Log("File %s Line %d <sphereCfg> tag: Expect name|basedir|sslPvtKey|sslCert|sslCertCA|portSTD|portSSL only. Invalid param (%s=%s)\n",
               pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
           rc = E_CONFIG ;
       }
   }
   //  Check ports are legal
   if (!m_nCommonPortSTD || m_nCommonPortSTD > 0xffff)
       { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> No HTTP port set in the Sphere or the APP\n", pRoot->Fname(), pRoot->Line()) ; }
   if (!m_nCommonPortSSL || m_nCommonPortSSL > 0xffff)
       { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> No HTTP port set in the Sphere or the APP\n", pRoot->Fname(), pRoot->Line()) ; }
   //  SSL all or none!
   if ((m_dfltSSL_PvtKey || m_dfltSSL_Cert || m_dfltSSL_CertCA) && !(m_dfltSSL_PvtKey && m_dfltSSL_Cert && m_dfltSSL_CertCA))
       { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <sphereCfg> Must set NONE or ALL SSL params\n", pRoot->Fname(), pRoot->Line()) ; }
   if (rc != E_OK)
       return rc ;
   /*
   **  ** Get initial parameters for each application
   **      */
   for (pN = pRoot->GetFirstChild() ; rc == E_OK && pN ; pN = pN->Sibling())
   {
       bReal = false ;
       nPortSTD = nPortSSL = 0;
       appname.Clear() ;
       domain.Clear() ;
       baseDir.Clear() ;
       rootFile.Clear() ;
       pvtKey.Clear() ;
       cert.Clear() ;
       certCA.Clear() ;
       if (pN->NameEQ("webappProxy"))
       {
           for (ai = pN ; ai.Valid() ; ai.Advance())
           {
               if      (ai.NameEQ("appname"))      appname = ai.Value() ;
               else if (ai.NameEQ("domain"))       domain = ai.Value() ;
               else if (ai.NameEQ("portSTD"))      nPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
               else if (ai.NameEQ("portSSL"))      nPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
               else
               {
                   m_pLog->Log("File %s Line %d <webappProxy> tag: Expect appname|domain|portSTD|portSSL only. Invalid param (%s=%s)\n",
                       pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
                   rc = E_CONFIG ;
               }
           }
           //  In the by-proxy case, the ports are compulsory
           if (nPortSTD == 0|| nPortSTD > 0xffff)
               { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webapp> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
           if (nPortSSL == 0|| nPortSSL > 0xffff)
               { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webapp> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
       }
       else if (pN->NameEQ("webappInternal"))
       {
           for (ai = pN ; ai.Valid() ; ai.Advance())
           {
               if      (ai.NameEQ("appname"))      appname = ai.Value() ;
               else if (ai.NameEQ("domain"))       domain = ai.Value() ;
               else if (ai.NameEQ("basedir"))      baseDir = ai.Value() ;
               else if (ai.NameEQ("rootfile"))     rootFile = ai.Value() ;
               else if (ai.NameEQ("sslPvtKey"))    pvtKey = ai.Value() ;
               else if (ai.NameEQ("sslCert"))      cert = ai.Value() ;
               else if (ai.NameEQ("sslCertCA"))    certCA = ai.Value() ;
               else if (ai.NameEQ("portSTD"))      nPortSTD = ai.Value() ? atoi(ai.Value()) : 0;
               else if (ai.NameEQ("portSSL"))      nPortSSL = ai.Value() ? atoi(ai.Value()) : 0;
               else
               {
                   m_pLog->Log("File %s Line %d <webapp> tag: Expect name|domain|basedir|rootfile|index|portSTD|portSSL only. Invalid param (%s=%s)\n",
                       pRoot->Fname(), pRoot->Line(), ai.Name(), ai.Value()) ;
                   rc = E_CONFIG ;
               }
           }
           //  Must have appname, domain, baseDir and rootFile
           if (!appname)   { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No Appname\n", pRoot->Fname(), pRoot->Line()) ; }
           if (!domain)    { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No Domain\n", pRoot->Fname(), pRoot->Line()) ; }
           if (!baseDir)   { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No basedir\n", pRoot->Fname(), pRoot->Line()) ; }
           if (!rootFile)  { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> No config file\n", pRoot->Fname(), pRoot->Line()) ; }
           //  Ports not compulsory but if supplied, must be legal
           if (nPortSTD && nPortSTD > 0xffff)
               { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
           if (nPortSSL && nPortSSL > 0xffff)
               { rc = E_CONFIG ; m_pLog->Log("File %s Line %d <webappInternal> HTTP port illegal (%u)\n", pRoot->Fname(), pRoot->Line(), nPortSTD) ; }
           bReal = true ;
       }
       else
       {
           rc = E_CONFIG ;
           m_pLog->Log("File %s Line %d. Expected <webappInternal> or <webappProxy> tag, not <%s>\n", pN->Fname(), pN->Line(), pN->txtName()) ;
           break ;
       }
       //  Check appname is unique
       if (appnames.Exists(appname))
       {
           rc = E_DUPLICATE ;
           m_pLog->Log("File %s Line %d <%s> Appname %s already taken\n", pN->Fname(), pN->Line(), pN->txtName(), *appname) ;
           break ;
       }
       appnames.Insert(appname) ;
       //  Check port settings do not conflict
       if (nPortSTD && ports.Exists(nPortSTD))
           { rc = E_DUPLICATE ; m_pLog->Log("File %s Line %d <%s> Port %u already taken\n", pN->Fname(), pN->Line(), pN->txtName(), nPortSTD) ; }
       ports.Insert(nPortSTD) ;
       if (nPortSSL && ports.Exists(nPortSSL))
           { rc = E_DUPLICATE ; m_pLog->Log("File %s Line %d <%s> Port %u already taken\n", pN->Fname(), pN->Line(), pN->txtName(), nPortSTD) ; }
       ports.Insert(nPortSSL) ;
       if (rc != E_OK)
           break ;
       //  Add the webapp to the sphere
       pSE = new _sphere_app() ;
       pSE->m_Appname = appname ;
       pSE->m_Domain = domain ;
       pSE->m_Basedir = baseDir ;
       pSE->m_CfgFile = rootFile ;
       pSE->m_PortHTTP = nPortSTD ;
       pSE->m_PortHTTPS = nPortSSL ;
       if (bReal)
       {
           //  Create and initialize (pre-config), the hdsApp instance
           pApp = pSE->m_pApp = hdsApp::GetInstance(*m_pLog) ;
           pApp->m_Appname = pSE->m_Appname ;
           pApp->m_Domain = pSE->m_Domain ;
           pApp->m_BaseDir = pSE->m_Basedir ;
           pApp->m_RootFile = pSE->m_CfgFile ;
       }
       m_AppsByHost.Insert(pSE->m_Domain, pSE) ;
       m_pLog->Log("Added webapp %s %s\n", *appname, *domain) ;
   }
   m_pLog->Log("Initalizing Apps\n") ;
   //  INIT the Apps
   for (nA = 0; rc == E_OK && nA < _hzGlobal_Sphere->Count() ; nA++)
   {
       pSE = m_AppsByHost.GetObj(nA) ;
       if (!pSE->m_pApp)
       {
           m_pLog->Log("Webapp %s:- Hosted by proxy\n", *pSE->m_Appname) ;
           continue ;
       }
       //  App is to be hosted internally
       pApp = pSE->m_pApp ;
       rc = pApp->m_ADP.InitStandard(pSE->m_Appname) ;
       if (rc != E_OK)
           m_pLog->Log("Init Standard Failed err=%s\n", Err2Txt(rc)) ;
       if (pApp->m_OpFlags & DS_APP_SITEINDEX)
           pApp->m_ADP.InitSiteIndex("../data") ;
       pApp->SetStdTypeValidations() ;
       m_pLog->Log("Webapp %s:- Standard Types created\n", *pApp->m_Appname) ;
       cfgfile = pApp->m_BaseDir ;
       cfgfile += "/config/" ;
       cfgfile += pApp->m_RootFile ;
       m_pLog->Log("Processing Webapp Cfg File [%s]\n", *cfgfile) ;
       rc = pApp->ReadWebappCfg(cfgfile) ;
       if (rc != E_OK)
           m_pLog->Log("ReadWebapp failed: err=%s\n", Err2Txt(rc)) ;
       else
       {
           pApp->SetupMasterMenu() ;
           m_pLog->Log("Webapp %s:- Data Model Editing initialized\n", *pApp->m_Domain) ;
           rc = pApp->CheckProject() ;
           if (rc != E_OK)
               m_pLog->Log("Check project failed: err=%s\n", Err2Txt(rc)) ;
       }
   }
   return rc ;
}