浏览代码

HPCC-18153 Merge DESDL functionality into ESP itself

- Create a centralized subscription/monitoring mechanism that would handle
  changes for all esdl bindings and definitions. (HPCC-18754)
- Be able to add esdl binding without requiring a static binding (HPCC-17860)
- Support hybrid mode, methods of a static esp service and those of
  a dynamic esdl service in one service (HPCC-18123)
- Be able to bind multiple esdl services on one port (HPCC-17379)
- Improve binding manipulation methods to solely use bindingId. (HPCC-18126)
- Other command line fixes and improvements (HPCC-18733)
- ESDL Engine should consider sharing ESDL definition objects (HPCC-13057)
- ESDL Publish command should not require ESDL service name (HPCC-18133)
- Decoupling of definition name and ESDL service name.
- Changes needed for merging with recent dali detach and attach changes.
- De-clutter esdl store code by removing unnecessary closes and
  queryroot() nullptr checks
- Remove one unnecessary method from esdl store.
- Fix a reference count issue by replacing Owned With Linked
- Memory leak fixes
- More changes based on code review comments and Valgrind MemCheck output

Signed-off-by: mayx <yanrui.ma@lexisnexisrisk.com>
mayx 7 年之前
父节点
当前提交
1647738c28

+ 13 - 0
esp/bindings/http/platform/httpbinding.cpp

@@ -539,6 +539,19 @@ int EspHttpBinding::getMethodHelp(IEspContext &context, const char *serv, const
     return 0;
 }
 
+bool EspHttpBinding::isMethodInService(IEspContext& context, const char *servname, const char *methname)
+{
+    StringBuffer serviceQName;
+    StringBuffer methodQName;
+    if (!qualifyServiceName(context, servname, methname, serviceQName, &methodQName))
+        return false;
+
+    if (methodQName.length() > 0)
+        return true;
+
+    return isMethodInSubService(context, servname, methname);
+}
+
 bool EspHttpBinding::qualifySubServiceName(IEspContext &context, const char *servname, const char *methname, StringBuffer &servQName, StringBuffer *methQName)
 {
     if (m_subservices)

+ 1 - 0
esp/bindings/http/platform/httpbinding.hpp

@@ -317,6 +317,7 @@ public:
 
     virtual int getMethodDescription(IEspContext &context, const char *serv, const char *method, StringBuffer &page);
     virtual int getMethodHelp(IEspContext &context, const char *serv, const char *method, StringBuffer &page);
+    bool isMethodInService(IEspContext& context, const char *servname, const char *methname);
 
     virtual int getMethodHtmlForm(IEspContext &context, CHttpRequest* request, const char *serv, const char *method, StringBuffer &page, bool bIncludeFormTag){return 0;}
     virtual bool hasSubService(IEspContext &context, const char *name);

+ 29 - 39
esp/bindings/http/platform/httpservice.cpp

@@ -96,37 +96,6 @@ CEspHttpServer::~CEspHttpServer()
     }
 }
 
-bool CEspHttpServer::rootAuth(IEspContext* ctx)
-{
-    if (!m_apport->rootAuthRequired())
-        return true;
-
-    bool ret=false;
-    EspHttpBinding* thebinding=getBinding();
-    if (thebinding)
-    {
-        thebinding->populateRequest(m_request.get());
-        if(!thebinding->authRequired(m_request.get()) || thebinding->doAuth(ctx))
-            ret=true;
-        else
-        {
-            ISecUser *user = ctx->queryUser();
-            if (user && user->getAuthenticateStatus() == AS_PASSWORD_VALID_BUT_EXPIRED)
-            {
-                m_response->redirect(*m_request.get(), "/esp/updatepasswordinput");
-                ret = true;
-            }
-            else
-            {
-                DBGLOG("User authentication required");
-                m_response->sendBasicChallenge(thebinding->getChallengeRealm(), true);
-            }
-        }
-    }
-
-    return ret;
-}
-
 const char* getSubServiceDesc(sub_service stype)
 {
 #define DEF_CASE(s) case s: return #s;
@@ -242,8 +211,8 @@ int CEspHttpServer::processRequest()
 
     try
     {
-        
-        EspHttpBinding* thebinding=NULL;
+        EspHttpBinding* thebinding = nullptr;
+        Owned<IInterface> theBindingHolder; //hold on to the binding in case it gets released in the middle of processing a request
         
         StringBuffer method;
         m_request->getMethod(method);
@@ -322,6 +291,8 @@ int CEspHttpServer::processRequest()
         {
             int ordinality=m_apport->getBindingCount();
             bool isSubService = false;
+            EspHttpBinding* exactBinding = nullptr;
+            bool exactIsSubService = false;
             if (ordinality>0)
             {
                 if (ordinality==1)
@@ -336,25 +307,44 @@ int CEspHttpServer::processRequest()
                 else
                 {
                     EspHttpBinding* lbind=NULL;
-                    for (int index=0; !thebinding && index<ordinality; index++)
+                    for (int index=0; !exactBinding && index<ordinality; index++)
                     {
                         CEspBindingEntry *entry = m_apport->queryBindingItem(index);
                         lbind = (entry) ? dynamic_cast<EspHttpBinding*>(entry->queryBinding()) : NULL;
                         if (lbind)
                         {
-                            if (!thebinding && lbind->isValidServiceName(*ctx, serviceName.str()))
+                            if (lbind->isValidServiceName(*ctx, serviceName.str()))
                             {
-                                thebinding=lbind;
-                                StringBuffer bindSvcName;
-                                if (stricmp(serviceName, lbind->getServiceName(bindSvcName)))
-                                    isSubService = true;
+                                if (!thebinding)
+                                {
+                                    thebinding=lbind;
+                                    StringBuffer bindSvcName;
+                                    if (!streq(serviceName, lbind->getServiceName(bindSvcName)))
+                                        isSubService = true;
+                                }
+                                if (methodName.length() != 0 && lbind->isMethodInService(*ctx, serviceName.str(), methodName.str()))
+                                {
+                                    exactBinding = lbind;
+                                    StringBuffer bindSvcName;
+                                    if (!streq(serviceName, lbind->getServiceName(bindSvcName)))
+                                        exactIsSubService = true;
+                                }
                             }                           
                         }
                     }
                 }
+                if (exactBinding)
+                {
+                    thebinding = exactBinding;
+                    isSubService = exactIsSubService;
+                }
                 if (!thebinding && m_defaultBinding)
                     thebinding=dynamic_cast<EspHttpBinding*>(m_defaultBinding.get());
             }
+
+            if (thebinding)
+                theBindingHolder.set(dynamic_cast<IInterface*>(thebinding));
+
             checkSetCORSAllowOrigin(m_request, m_response);
 
             if (thebinding!=NULL)

+ 0 - 1
esp/bindings/http/platform/httpservice.hpp

@@ -111,7 +111,6 @@ public:
     {
         return true;
     }
-    bool rootAuth(IEspContext* ctx);
 
     virtual int processRequest();
 

+ 46 - 23
esp/esdllib/esdl_def.cpp

@@ -37,8 +37,9 @@ typedef CopyReferenceArrayOf<IEsdlDefMethod> EsdlDefMethodArray;
 #define IMPLEMENT_ESDL_DEFOBJ \
     virtual const char *queryName() { return EsdlDefObject::queryName(); } \
     virtual const char *queryProp(const char *name) { return EsdlDefObject::queryProp(name); } \
-virtual bool hasProp(const char* name) { return EsdlDefObject::hasProp(name); } \
+    virtual bool hasProp(const char* name) { return EsdlDefObject::hasProp(name); } \
     virtual int getPropInt(const char *pname, int def=0){return props->getPropInt(pname,def);} \
+    virtual bool getPropBool(const char *pname, bool def=false){return props->getPropBool(pname,def);} \
     virtual bool checkVersion(double ver) { return EsdlDefObject::checkVersion(ver); } \
     virtual bool checkFLVersion(double ver) { return EsdlDefObject::checkFLVersion(ver); } \
     virtual bool checkOptional(IProperties *opts ) { return EsdlDefObject::checkOptional(opts); }\
@@ -185,6 +186,7 @@ public:
     const char *queryProp(const char *pname){return props->queryProp(pname);}
     bool hasProp(const char*pname) { return props->hasProp(pname); }
     int getPropInt(const char *pname, int def=0){return props->getPropInt(pname,def);}
+    bool getPropBool(const char *pname, bool def=false){return props->getPropBool(pname,def);}
     const char *queryName(){return queryProp("name");}
 
     virtual IPropertyIterator* getProps()
@@ -1464,6 +1466,7 @@ public:
     unsigned walkChildrenDepthFirst( AddedObjs& foundByName, EsdlDefObjectWrapperArray& dependencies, IEsdlDefObject* esdlObj, double requestedVer, IProperties *opts, int level=0, unsigned flags=0);
     bool shouldGenerateArrayOf( IEsdlDefObject& child, unsigned flags, unsigned& stateOut );
     bool setWrapperFlagStringArray( AddedObjs& foundByName, EsdlDefObjectWrapper* wrapper, unsigned state );
+    virtual bool isShared() override { return IsShared(); }
 };
 
 bool EsdlDefinition::shouldGenerateArrayOf( IEsdlDefObject& child, unsigned flags, unsigned& stateOut )
@@ -1535,21 +1538,30 @@ IEsdlDefObjectIterator* EsdlDefinition::getDependencies( const char* service, co
     return getDependencies( service, methods, requestedVer, opts, flags );
 }
 
+void getServiceMethods(IEsdlDefService* serviceDef, EsdlDefObjectArray& methodArray, unsigned flags)
+{
+    Owned<IEsdlDefMethodIterator> methodIter = serviceDef->getMethods();
+    for( methodIter->first(); methodIter->isValid(); methodIter->next() )
+    {
+        if ((flags & DEPFLAG_ECL_ONLY) && methodIter->query().getPropBool("ecl_hide"))
+            continue;
+        methodArray.append( methodIter->query() );
+    }
+}
+
 IEsdlDefObjectIterator* EsdlDefinition::getDependencies( const char* service, StringArray &methods, double requestedVer, IProperties *opts, unsigned flags)
 {
-    IEsdlDefService* serviceDef;
-    IEsdlDefMethod* methodDef;
-    EsdlDefObjectArray serviceArray;
+    IEsdlDefService* serviceDef = nullptr;
     EsdlDefObjectArray methodArray;
-    EsdlDefObjectWrapperArray* dependencies = new EsdlDefObjectWrapperArray();
-    Owned<IEsdlDefMethodIterator> methodIter;
+    OwnedPtr<EsdlDefObjectWrapperArray> dependencies(new EsdlDefObjectWrapperArray());
 
     // I think it's just a namespace/xml_tag/structure name naming difference
     // but be sure to know where these structures listed in the schema are
     // coming from and how they're defined:
     // Exceptions, ArrayOfEspException, EspException
     TimeSection ts("EsdlDefinition::getDependencies");
-    if(service && *service)
+
+    if (service && *service)
     {
         serviceDef = this->queryService(service);
 
@@ -1558,30 +1570,30 @@ IEsdlDefObjectIterator* EsdlDefinition::getDependencies( const char* service, St
             throw( MakeStringException(0, "ESDL Service Definition not found for %s", service) );
         }
     }
-    else
+    else if (methods.length() != 0) //Only require service name when "methods" is provided
     {
         throw( MakeStringException(0, "No ESDL Service Definition provided, need to have a service to search in for methods") );
     }
 
-    if( methods.length() < 1 )
+    if (methods.length() == 0)
     {
-        methodIter.setown(serviceDef->getMethods());
-        for( methodIter->first(); methodIter->isValid(); methodIter->next() )
+        if (serviceDef)
+            getServiceMethods(serviceDef, methodArray, flags);
+        else
         {
-            if ((flags & DEPFLAG_ECL_ONLY) && methodIter->query().getPropInt("ecl_hide"))
-                continue;
-            methodArray.append( methodIter->query() );
+            ForEachItemIn(idx, this->services)
+                getServiceMethods(&this->services.item(idx), methodArray, flags);
         }
     }
     else
     {
         ForEachItemIn( i, methods )
         {
-            methodDef = serviceDef->queryMethodByName(methods.item(i));
+            IEsdlDefMethod* methodDef = serviceDef->queryMethodByName(methods.item(i));
 
-            if(!methodDef)
+            if (!methodDef)
                 throw( MakeStringException(0, "ESDL Method Definition not found for %s in service %s", methods.item(i), service) );
-            if ((flags & DEPFLAG_ECL_ONLY) && methodDef->getPropInt("ecl_hide"))
+            if ((flags & DEPFLAG_ECL_ONLY) && methodDef->getPropBool("ecl_hide"))
                 continue;
             methodArray.append( *methodDef );
         }
@@ -1590,13 +1602,24 @@ IEsdlDefObjectIterator* EsdlDefinition::getDependencies( const char* service, St
     this->gatherMethodDependencies( *dependencies, methodArray, requestedVer, opts, flags );
 
     bool allTypes = !(flags & DEPFLAG_INCLUDE_TYPES); //not asking for any explicit types indicates all types
-    if(serviceDef && (allTypes || (flags & DEPFLAG_INCLUDE_SERVICE)))
+    if (allTypes || (flags & DEPFLAG_INCLUDE_SERVICE))
     {
-        EsdlDefObjectWrapper* wrapper = new EsdlDefObjectWrapper( *serviceDef );
-        dependencies->append( *wrapper );
+        if (serviceDef)
+        {
+            EsdlDefObjectWrapper* wrapper = new EsdlDefObjectWrapper( *serviceDef );
+            dependencies->append( *wrapper );
+        }
+        else
+        {
+            ForEachItemIn(idx, this->services)
+            {
+                IEsdlDefService* oneServiceDef = &this->services.item(idx);
+                EsdlDefObjectWrapper* wrapper = new EsdlDefObjectWrapper( *oneServiceDef );
+                dependencies->append( *wrapper );
+            }
+        }
     }
-
-    return new OwnedEsdlDefObjectArrayIterator(dependencies);
+    return new OwnedEsdlDefObjectArrayIterator(dependencies.getClear());
 }
 
 void EsdlDefinition::gatherMethodDependencies( EsdlDefObjectWrapperArray& dependencies, EsdlDefObjectArray& methods, double requestedVer, IProperties *opts, unsigned flags )
@@ -1659,7 +1682,7 @@ unsigned EsdlDefinition::walkChildrenDepthFirst( AddedObjs& foundByName, EsdlDef
             while( children->isValid() )
             {
                 IEsdlDefObject& child = children->query();
-                if ((flags & DEPFLAG_ECL_ONLY) && child.getPropInt("ecl_hide"))
+                if ((flags & DEPFLAG_ECL_ONLY) && child.getPropBool("ecl_hide"))
                 {
                     children->next();
                     continue;

+ 3 - 0
esp/esdllib/esdl_def.hpp

@@ -84,6 +84,7 @@ interface IEsdlDefObject : extends IInterface
     virtual const char *queryProp(const char *name)=0;
     virtual bool hasProp(const char *name)=0;
     virtual int getPropInt(const char *pname, int def = 0)=0;
+    virtual bool getPropBool(const char *pname, bool def = false)=0;
     virtual void toXML(StringBuffer &xml, double version = 0, IProperties *opts=NULL, unsigned flags=0)=0;
     virtual EsdlDefTypeId getEsdlType()=0;
     virtual bool checkVersion(double ver)=0;
@@ -217,6 +218,8 @@ interface IEsdlDefinition : extends IInterface
     virtual bool hasXMLDefintionLoaded(const char *esdlDefName, int ver)=0;
     virtual bool hasXMLDefintionLoaded(const char *esdlDefId)=0;
     virtual EsdlBasicElementType translateSimpleType(const char *type)=0;
+
+    virtual bool isShared() = 0;
 };
 
 esdl_decl IEsdlDefinition *createNewEsdlDefinition(const char *esdl_ns=NULL);

+ 1 - 0
esp/platform/espbinding.hpp

@@ -107,6 +107,7 @@ public:
     virtual bool qualifyServiceName(IEspContext & context, const char * servname, const char * methname, StringBuffer & servQName, StringBuffer * methQName){return false;}
     virtual IRpcRequestBinding *createReqBinding(IEspContext &context, IHttpMessage *request, const char *service, const char *method){return NULL;}
     virtual bool isDynamicBinding() const { return false; }
+    virtual bool isBound() const { return false; }
 };
 
 #endif

+ 70 - 25
esp/platform/espcfg.cpp

@@ -256,7 +256,7 @@ CEspConfig::CEspConfig(IProperties* inputs, IPropertyTree* envpt, IPropertyTree*
     m_cfg.setown(procpt);
 
     loadBuiltIns();   
-   
+
     // load options
     const char* level = m_cfg->queryProp("@logLevel");
     m_options.logLevel = level ? atoi(level) : LogMin;
@@ -465,32 +465,35 @@ CEspConfig::CEspConfig(IProperties* inputs, IPropertyTree* envpt, IPropertyTree*
                 ptree = &pt_iter->query();
                 if (ptree)
                 {
-                    binding_cfg *bcfg = new binding_cfg;
-                    
+                    OwnedPtr<binding_cfg> bcfg(new binding_cfg);
                     ptree->getProp("@name", bcfg->name);
-                    ptree->getProp("@type", bcfg->type);
-                    ptree->getProp("@plugin", bcfg->plugin);
-                    fixPlugin(bcfg->plugin);
-                    bcfg->isDefault = ptree->getPropBool("@defaultBinding", false);
-                    
-                    StringBuffer addr;
-                    ptree->getProp("@netAddress", addr);
-                    if(strcmp(addr.str(), ".") == 0)
-                    {
-                        bcfg->address.append("0.0.0.0");
-                    }
+                    bcfg->port = ptree->getPropInt("@port", 0);
+                    if (bcfg->port == 0)
+                        DBGLOG("Binding %s is configured with port 0, do not load it.", bcfg->name.str());
                     else
                     {
-                        bcfg->address.append(addr.str());
+                        ptree->getProp("@type", bcfg->type);
+                        ptree->getProp("@plugin", bcfg->plugin);
+                        fixPlugin(bcfg->plugin);
+                        bcfg->isDefault = ptree->getPropBool("@defaultBinding", false);
+
+                        StringBuffer addr;
+                        ptree->getProp("@netAddress", addr);
+                        if (strcmp(addr.str(), ".") == 0)
+                        {
+                            // Here we interpret '.' as binding to all interfaces, so convert it to "0.0.0.0"
+                            bcfg->address.append("0.0.0.0");
+                        }
+                        else
+                        {
+                            bcfg->address.append(addr.str());
+                        }
+
+                        ptree->getProp("@service", bcfg->service_name);
+                        ptree->getProp("@protocol", bcfg->protocol_name);
+
+                        m_bindings.push_back(bcfg.getClear());
                     }
-                    
-                    StringBuffer portstr;
-                    ptree->getProp("@port", portstr);
-                    bcfg->port = atoi(portstr.str());
-                    ptree->getProp("@service", bcfg->service_name);
-                    ptree->getProp("@protocol", bcfg->protocol_name);
-                    
-                    m_bindings.push_back(bcfg);
                 }
                 
                 pt_iter->next();
@@ -559,7 +562,7 @@ void CEspConfig::loadBinding(binding_cfg &xcfg)
 
     if(sit == m_services.end())
     {
-        DBGLOG("Warning: Service %s not found for the binding", xcfg.service_name.str());
+        DBGLOG("Warning: Service %s not found for binding %s", xcfg.service_name.str(), xcfg.name.str());
     }
     else
     {
@@ -568,7 +571,7 @@ void CEspConfig::loadBinding(binding_cfg &xcfg)
 
     if(pit == m_protocols.end())
     {
-        throw MakeStringException(-1, "Protocol %s not found for the binding", xcfg.protocol_name.str());
+        throw MakeStringException(-1, "Protocol %s not found for binding %s", xcfg.protocol_name.str(), xcfg.name.str());
     }
     else
     {
@@ -717,6 +720,37 @@ void CEspConfig::loadBindings()
     }
 }
 
+void CEspConfig::startEsdlMonitor()
+{
+    start_esdl_monitor_t xproc = nullptr;
+    Owned<IEspPlugin> pplg = getPlugin("esdl_svc_engine");
+    if (pplg)
+    {
+        DBGLOG("Plugin esdl_svc_engine loaded.");
+        xproc = (start_esdl_monitor_t) pplg->getProcAddress("startEsdlMonitor");
+    }
+    else
+        throw MakeStringException(-1, "Plugin esdl_svc_engine can't be loaded");
+
+    if (xproc)
+    {
+        DBGLOG("Procedure startEsdlMonitor loaded, now calling it...");
+        xproc();
+    }
+    else
+        throw MakeStringException(-1, "procedure startEsdlMonitor can't be loaded");
+}
+
+void CEspConfig::stopEsdlMonitor()
+{
+    stop_esdl_monitor_t xproc = nullptr;
+    Owned<IEspPlugin> pplg = getPlugin("esdl_svc_engine");
+    if (pplg)
+        xproc = (stop_esdl_monitor_t) pplg->getProcAddress("stopEsdlMonitor");
+    if (xproc)
+        xproc();
+}
+
 class ESPxsltIncludeHandler : public CInterface, implements IIncludeHandler
 {
 public:
@@ -1101,3 +1135,14 @@ bool CEspConfig::canAllBindingsDetachFromDali()
     }
     return true;
 }
+
+IEspRpcBinding* CEspConfig::queryBinding(const char* name)
+{
+    for (auto binding : m_bindings)
+    {
+        if (strcmp(binding->name.str(), name) == 0)
+            return binding->bind.get();
+    }
+    return nullptr;
+}
+

+ 19 - 0
esp/platform/espcfg.ipp

@@ -239,6 +239,7 @@ public:
     void loadProtocols();
     void loadServices();
     void loadBindings();
+    void startEsdlMonitor();
 
     void loadAll()
     {
@@ -255,6 +256,8 @@ public:
         }
         loadProtocols();
         loadBindings();
+        if(useDali)
+            startEsdlMonitor();
 
         if (m_cfg->getPropBool("@ensureESPCache", false) && !checkESPCache())
             throw MakeStringException(-1, "Failed in checking ESP cache service using %s", m_cfg->queryProp("@espCacheInitString"));
@@ -281,12 +284,15 @@ public:
     void unloadServices();
     void unloadProtocols();
     void saveAttachState();
+    void stopEsdlMonitor();
 
     void clear()
     {
         unloadBindings();
         unloadServices();
         unloadProtocols();
+        if(useDali)
+           stopEsdlMonitor();
 
         serverstatus=NULL;
         
@@ -309,7 +315,20 @@ public:
         closeEnvironment();
     }
 
+    IPropertyTree* queryProcConfig()
+    {
+        return m_cfg.get();
+    }
+
+    IEspProtocol* queryProtocol(const char* name)
+    {
+        map<string, protocol_cfg*>::iterator pit = m_protocols.find(name);
+        if (pit != m_protocols.end())
+            return (*pit).second->prot;
+        return nullptr;
+    }
 
+    IEspRpcBinding* queryBinding(const char* name);
 };
 
 

+ 5 - 0
esp/platform/espcontext.cpp

@@ -938,3 +938,8 @@ const char* getBuildLevel()
 {
     return g_buildLevel.str();
 }
+
+IEspServer* queryEspServer()
+{
+    return dynamic_cast<IEspServer*>(getESPContainer());
+}

+ 1 - 0
esp/platform/espcontext.hpp

@@ -131,5 +131,6 @@ ESPHTTP_API void setBuildVersion(const char* buildVersion);
 ESPHTTP_API const char* getBuildVersion();
 ESPHTTP_API void setBuildLevel(const char* buildLevel);
 ESPHTTP_API const char* getBuildLevel();
+ESPHTTP_API IEspServer* queryEspServer();
 #endif
 

+ 44 - 0
esp/platform/espp.hpp

@@ -63,6 +63,7 @@ private:
     Mutex abortMutex;
     bool m_SEHMappingEnabled;
     CEspConfig* m_config;
+    CriticalSection m_BindingCritSect;
 
 public:
     IMPLEMENT_IINTERFACE;
@@ -191,6 +192,7 @@ public:
 
         LOG(MCprogress, "binding %s, on %s:%d", name, strIP.str(), port);
 
+        CriticalBlock cb(m_BindingCritSect);
         ISocket **socketp = m_srvSockets.getValue(port);
         ISocket *socket=(socketp!=NULL) ? *socketp : NULL;
 
@@ -232,6 +234,48 @@ public:
         }
     }
 
+    virtual void removeBinding(unsigned short port, IEspRpcBinding & bind)
+    {
+        IEspProtocol* prot = dynamic_cast<IEspProtocol*>(bind.queryListener());
+        if (prot)
+        {
+            CriticalBlock cb(m_BindingCritSect);
+            int left = prot->removeBindingMap(port, &bind);
+            if (left == 0)
+            {
+                DBGLOG("No more bindings on port %d, so freeing up the port.",port);
+                ISocket **socketp = m_srvSockets.getValue(port);
+                ISocket *socket=(socketp!=nullptr) ? *socketp : nullptr;
+                if (socket != nullptr)
+                {
+                    remove(socket);
+                    m_srvSockets.remove(port);
+                    socket->close();
+                }
+            }
+        }
+    }
+
+    virtual IPropertyTree* queryProcConfig()
+    {
+        return m_config->queryProcConfig();
+    }
+
+    virtual IEspProtocol* queryProtocol(const char* name)
+    {
+        return m_config->queryProtocol(name);
+    }
+
+    virtual IEspRpcBinding* queryBinding(const char* name)
+    {
+        return m_config->queryBinding(name);
+    }
+
+    virtual const char* getProcName()
+    {
+        return m_config->getProcName();
+    }
+
 //ISocketHandler
     void start()
     {

+ 2 - 0
esp/platform/espplugin.hpp

@@ -28,6 +28,8 @@
 typedef IEspService * (*esp_service_factory_t)(const char *name,  const char* type, IPropertyTree* cfg, const char *process);
 typedef IEspRpcBinding * (*esp_binding_factory_t)(const char *name,  const char* type, IPropertyTree* cfg, const char *process);
 typedef IEspProtocol * (*esp_protocol_factory_t)(const char *name,  const char* type, IPropertyTree* cfg, const char *process);
+typedef void (*start_esdl_monitor_t)();
+typedef void (*stop_esdl_monitor_t)();
 
 
 extern "C" {

+ 107 - 30
esp/platform/espprotocol.cpp

@@ -68,6 +68,9 @@ CEspApplicationPort::CEspApplicationPort(bool viewcfg, CEspProtocol* prot) : bin
 
 void CEspApplicationPort::appendBinding(CEspBindingEntry* entry, bool isdefault)
 {
+    WriteLockBlock wblock(rwLock);
+    if (bindingCount + 1 == MAX_ESP_BINDINGS)
+        throw MakeStringException(0,"Error - reached maximum number of bindings allowed.");
     bindings[bindingCount]=entry;
     if (isdefault)
         defBinding=bindingCount;
@@ -90,6 +93,34 @@ void CEspApplicationPort::appendBinding(CEspBindingEntry* entry, bool isdefault)
     }
 }
 
+void CEspApplicationPort::removeBinding(IEspRpcBinding* binding)
+{
+    CEspBindingEntry* targetEntry = nullptr;
+    {
+        WriteLockBlock wblock(rwLock);
+        for (int i = 0; i < bindingCount; i++)
+        {
+            if (!bindings[i])
+                continue;
+            IEspRpcBinding* currentBinding = bindings[i]->queryBinding();
+            if (currentBinding && currentBinding == binding)
+            {
+                targetEntry = bindings[i];
+                bindings[i] = nullptr;
+                if (i != bindingCount-1)
+                {
+                    bindings[i] = bindings[bindingCount-1];
+                    bindings[bindingCount-1] = nullptr;
+                }
+                bindingCount--;
+                break;
+            }
+        }
+    }
+    if(targetEntry != nullptr)
+        targetEntry->Release();
+}
+
 const StringBuffer &CEspApplicationPort::getAppFrameHtml(time_t &modified, const char *inner, StringBuffer &html, IEspContext* ctx)
 {
     if (!xslp)
@@ -184,9 +215,12 @@ const StringBuffer &CEspApplicationPort::getNavBarContent(IEspContext &context,
     if (xslp)
     {
         Owned<IPropertyTree> navtree=createPTree("EspNavigationData");
-        int count = getBindingCount();
-        for (int idx = 0; idx<count; idx++)
-            bindings[idx]->queryBinding()->getNavigationData(context, *navtree.get());
+        {
+            ReadLockBlock rblock(rwLock);
+            int count = getBindingCount();
+            for (int idx = 0; idx<count; idx++)
+                bindings[idx]->queryBinding()->getNavigationData(context, *navtree.get());
+        }
 
         StringBuffer xml;
         buildNavTreeXML(navtree.get(), xml);
@@ -227,9 +261,12 @@ const StringBuffer &CEspApplicationPort::getDynNavData(IEspContext &context, IPr
 {
     Owned<IPropertyTree> navtree=createPTree("EspDynNavData");
     bVolatile = false;
-    int count = getBindingCount();
-    for (int idx = 0; idx<count; idx++)
-        bindings[idx]->queryBinding()->getDynNavData(context, params, *navtree.get());
+    {
+        ReadLockBlock rblock(rwLock);
+        int count = getBindingCount();
+        for (int idx = 0; idx<count; idx++)
+            bindings[idx]->queryBinding()->getDynNavData(context, params, *navtree.get());
+    }
 
     if (!bVolatile)
         bVolatile = navtree->getPropBool("@volatile", false);
@@ -240,6 +277,7 @@ const StringBuffer &CEspApplicationPort::getDynNavData(IEspContext &context, IPr
 int CEspApplicationPort::onGetNavEvent(IEspContext &context, IHttpMessage* request, IHttpMessage* response)
 {
     int handled=0;
+    ReadLockBlock rblock(rwLock);
     int count = getBindingCount();
     for (int idx = 0; !handled && idx<count; idx++)
     {
@@ -254,6 +292,7 @@ int CEspApplicationPort::onBuildSoapRequest(IEspContext &context, IHttpMessage*
     CHttpResponse *response=dynamic_cast<CHttpResponse*>(iresp);
 
     int handled=0;
+    ReadLockBlock rblock(rwLock);
     int count = getBindingCount();
     for (int idx = 0; !handled && idx<count; idx++)
     {
@@ -479,22 +518,28 @@ void CEspBinding::getNavigationData(IEspContext &context, IPropertyTree & data)
                 params.appendf("%cver_=%g", params.length()?'&':'?', context.getClientVersion());
         }
 
-        IPropertyTree *folder=createPTree("Folder");
-        folder->addProp("@name", serviceName.str());
-        folder->addProp("@info", serviceName.str());
-
         StringBuffer encodedparams;
         if (params.length())
             encodeUtf8XML(params.str(), encodedparams, 0);
 
-        folder->addProp("@urlParams", encodedparams);
-        if (showSchemaLinks())
-            folder->addProp("@showSchemaLinks", "true");
-
         if (params.length())
             params.setCharAt(0,'&'); //the entire params string will follow the initial param: "?form"
 
-        folder->addPropBool("@isDynamicBinding", isDynamicBinding());
+        VStringBuffer folderpath("Folder[@name='%s']", serviceName.str());
+
+        IPropertyTree *folder = data.queryPropTree(folderpath.str());
+        if(!folder)
+        {
+            folder=createPTree("Folder");
+            folder->addProp("@name", serviceName.str());
+            folder->addProp("@info", serviceName.str());
+            folder->addProp("@urlParams", encodedparams);
+            if (showSchemaLinks())
+                folder->addProp("@showSchemaLinks", "true");
+            folder->addPropBool("@isDynamicBinding", isDynamicBinding());
+            folder->addPropBool("@isBound", isBound());
+            data.addPropTree("Folder", folder);
+        }
 
         MethodInfoArray methods;
         wsdl->getQualifiedNames(context, methods);
@@ -510,8 +555,6 @@ void CEspBinding::getNavigationData(IEspContext &context, IPropertyTree & data)
 
             folder->addPropTree("Link", link);
         }
-
-        data.addPropTree("Folder", folder);
     }
 }
 
@@ -654,27 +697,31 @@ void CEspProtocol::addBindingMap(ISocket *sock, IEspRpcBinding* binding, bool is
     char name[256];
     int port = sock->name(name, 255);
 
-    CApplicationPortMap::iterator apport_it = m_portmap.find(port);
+    {
+        WriteLockBlock wblock(rwLock);
+        CApplicationPortMap::iterator apport_it = m_portmap.find(port);
 
-    CEspApplicationPort *apport=NULL;
+        CEspApplicationPort *apport = nullptr;
 
-    if (apport_it!=m_portmap.end())
-    {
-        apport = (*apport_it).second;
-        apport->appendBinding(entry, isdefault);
-    }
-    else
-    {
-        apport = new CEspApplicationPort(m_viewConfig, this);
-        apport->appendBinding(entry, isdefault);
+        if (apport_it!=m_portmap.end())
+        {
+            apport = (*apport_it).second;
+            apport->appendBinding(entry, isdefault);
+        }
+        else
+        {
+            apport = new CEspApplicationPort(m_viewConfig, this);
+            apport->appendBinding(entry, isdefault);
 
-        CApplicationPortMap::value_type vt(port, apport);
-        m_portmap.insert(vt);
+            CApplicationPortMap::value_type vt(port, apport);
+            m_portmap.insert(vt);
+        }
     }
 }
 
 CEspApplicationPort* CEspProtocol::queryApplicationPort(int port)
 {
+    ReadLockBlock rblock(rwLock);
     CApplicationPortMap::iterator apport_it = m_portmap.find(port);
     return (apport_it != m_portmap.end()) ? (*apport_it).second : NULL;
 }
@@ -709,3 +756,33 @@ void CEspProtocol::initPersistentHandler(IPropertyTree * proc_cfg)
     }
     m_persistentHandler.setown(createPersistentHandler(this, maxIdleTime, maxReqs, static_cast<PersistentLogLevel>(getEspLogLevel())));
 }
+
+int CEspProtocol::removeBindingMap(int port, IEspRpcBinding* binding)
+{
+    WriteLockBlock wblock(rwLock);
+    CApplicationPortMap::iterator apport_it = m_portmap.find(port);
+
+    int left = 0;
+    if (apport_it!=m_portmap.end())
+    {
+        CEspApplicationPort* apport = (*apport_it).second;
+        apport->removeBinding(binding);
+        left = apport->countBindings();
+        if (left == 0)
+        {
+            delete apport;
+            m_portmap.erase(apport_it);
+        }
+    }
+    return left;
+}
+
+int CEspProtocol::countBindings(int port)
+{
+    ReadLockBlock rblock(rwLock);
+    CEspApplicationPort* apport = queryApplicationPort(port);
+    if (!apport)
+        return 0;
+    else
+        return apport->countBindings();
+}

+ 16 - 3
esp/platform/espprotocol.hpp

@@ -82,10 +82,10 @@ public:
 
 class CEspProtocol;
 
-//MAKEPointerArray(CEspBindingEntry*, CEspBindingArray);
+#define MAX_ESP_BINDINGS 512
 class CEspApplicationPort
 {
-    CEspBindingEntry* bindings[100];
+    CEspBindingEntry* bindings[512];
     int bindingCount;
     int defBinding;
 
@@ -101,6 +101,7 @@ class CEspApplicationPort
     HINSTANCE hxsl;
     Owned<IXslProcessor> xslp;
     CEspProtocol* protocol = nullptr;
+    ReadWriteLock rwLock;
 public:
     CEspApplicationPort(bool viewcfg, CEspProtocol* prot);
 
@@ -124,12 +125,18 @@ public:
 
     int getBindingCount(){return bindingCount;}
     void appendBinding(CEspBindingEntry* entry, bool isdefault);
+    void removeBinding(IEspRpcBinding* binding);
 
     bool rootAuthRequired(){return rootAuth;}
 
-    CEspBindingEntry* queryBindingItem(int item){return (item<bindingCount) ? bindings[item] : NULL;}
+    CEspBindingEntry* queryBindingItem(int item)
+    {
+        ReadLockBlock rblock(rwLock);
+        return (item<bindingCount) ? bindings[item] : nullptr;
+    }
     CEspBindingEntry* getDefaultBinding(){return bindings[(defBinding>=0) ? defBinding : 0];}
     CEspProtocol* queryProtocol() { return protocol; }
+    int countBindings() { return bindingCount; }
 #ifdef _USE_OPENLDAP
     unsigned updatePassword(IEspContext &context, IHttpMessage* request, StringBuffer& message);
     void onUpdatePasswordInput(IEspContext &context, StringBuffer &html);
@@ -154,6 +161,8 @@ private:
     IEspContainer *m_container;
     unsigned m_nextSeq;
     Owned<IPersistentHandler> m_persistentHandler;
+    ReadWriteLock rwLock;
+
 public:
     IMPLEMENT_IINTERFACE;
 
@@ -166,6 +175,7 @@ public:
 
     void clear()
     {
+        WriteLockBlock wblock(rwLock);
         map<int, CEspApplicationPort*>::iterator bndi = m_portmap.begin();
         for(;bndi!=m_portmap.end();bndi++)
             if(bndi->second)
@@ -188,6 +198,7 @@ public:
     virtual const char * getProtocolName();
 
     virtual void addBindingMap(ISocket *sock, IEspRpcBinding* binding, bool isdefault);
+    virtual int removeBindingMap(int port, IEspRpcBinding* binding);
     virtual CEspApplicationPort* queryApplicationPort(int handle);
 
     virtual void setMaxRequestEntityLength(int len) {m_MaxRequestEntityLength = len;};
@@ -196,6 +207,8 @@ public:
     virtual void initPersistentHandler(IPropertyTree * proc_cfg);
     virtual bool persistentEnabled() { return m_persistentHandler != nullptr; }
     virtual void addPersistent(ISocket* sock);
+
+    virtual int countBindings(int port);
 };
 
 #endif

+ 7 - 0
esp/scm/esp.ecm

@@ -262,9 +262,11 @@ SCMinterface IEspProtocol(IInterface)
 {
    const char * getProtocolName();
    void addBindingMap(ISocket *sock, IEspRpcBinding* binding, bool isdefault);
+   int removeBindingMap(int port, IEspRpcBinding* binding);
    void clearBindingMap();
    void init(IPropertyTree *cfg, const char *process, const char *protocol);
    void setContainer(IEspContainer *container);
+   int countBindings(int port);
 };
 
 
@@ -364,6 +366,11 @@ SCMinterface IEspServer(IInterface)
 {
    void addProtocol(IEspProtocol &prot);
    void addBinding(const char * name, const char * host, unsigned short port, IEspProtocol &prot, IEspRpcBinding &bind, bool isdefault, IPropertyTree* cfgtree);
+   void removeBinding(unsigned short port, IEspRpcBinding& bind);
+   IEspProtocol* queryProtocol(const char* name);
+   IEspRpcBinding* queryBinding(const char* name);
+   const char* getProcName();
+   virtual IPropertyTree* queryProcConfig();
 };
 
 SCMinterface IEspServiceCfg(IInterface)

+ 36 - 18
esp/scm/ws_esdlconfig.ecm

@@ -35,9 +35,10 @@ ESPStruct ESDLConfiguration
 };
 ESPstruct ESDLBinding
 {
-    string EspProcess;
-    string EspBinding;
     string Id;
+    string EspProcess;
+    [min_ver("1.4")] int Port;
+    [max_ver("1.3")] string EspBinding;
 };
 
 ESPstruct ESDLDefinition
@@ -60,6 +61,7 @@ ESPrequest [nil_remove] GetESDLDefinitionRequest
     string Id;
     [min_ver("1.3")] string Name;
     [min_ver("1.3")] int Seq;
+    string ServiceName;
     [min_ver("1.2")] boolean ReportMethodsAvailable;
 };
 
@@ -94,13 +96,13 @@ ESPresponse [nil_remove, exceptions_inline] PublishESDLDefinitionResponse
 ESPrequest [nil_remove] PublishESDLBindingRequest
 {
     string EspProcName;        //Name of ESP Process
-    string EspBindingName;     //Name of ESP Binding - optional, but we must be able to look it up. We can look it up by EspProc + Esp Port or EspProc + Esp Service.
-    string EspPort;            //Esp Proc + Esp port = ESP Binding
-    string EspServiceName;     //Esp Proc + Esp service name = ESP Binding
-                               //Therefore, either pass in EspBindingName, or Esp Port or ESP ServiceName
+    string EspBindingName;     //Name of ESP Binding
+    string EspPort;            //Port to bind on. You need to specify either EspBindingName or EspPort.
     string EsdlDefinitionID;   // The ESDL definition name.ver
     string EsdlServiceName;    //Name of service as defined in ESDL Definition
 
+    [max_ver("1.3")] string EspServiceName;
+
     boolean Overwrite;
     string Config; // dynamic xml, can have <Binding EspProcess=xxx EspBinding=WsAccurint><Definition name=xx id=xx.yy><Methods><Method>...
                    //              or  <Definition name=xx id=xx.yy><Methods><Method>...
@@ -155,12 +157,13 @@ ESPresponse ListDESDLEspBindingsResp
 
 ESPrequest [nil_remove] ConfigureESDLBindingMethodRequest
 {
-    string EspProcName;       //Name of ESP Process
-    string EspBindingName;    //Name + port = binding
-    string EspPort;            //Esp Proc + Esp port = ESP Binding
-    string EsdlDefinitionID;   // The ESDL definition name.ver
-    string EsdlServiceName;    //Name of service as defined in ESDL Definition
-    //string MethodName;         //If no port is provided
+    [min_ver("1.4")] string EsdlBindingId;
+    [min_ver("1.4")] string MethodName;
+    [max_ver("1.3")] string EspProcName;       //Name of ESP Process
+    [max_ver("1.3")] string EspBindingName;    //Name + port = binding
+    [max_ver("1.3")] string EspPort;            //Esp Proc + Esp port = ESP Binding
+    [max_ver("1.3")] string EsdlDefinitionID;   // The ESDL definition name.ver
+    [max_ver("1.3")] string EsdlServiceName;    //Name of service as defined in ESDL Definition
     boolean Overwrite;
     //string Attributes;        //xml <methods><Method name="name" url="http://vvvzzz.yyy.xxx:9876" password="h7fermX+gmYuuBwUsS-qeZ==" username="myname" queryname="UPS_Services.RightAddressService" status="available" testrepo="0" querytype="roxie"/><Methods>
     string Config; // dynamic xml, can have <Binding EspProcess=xxx EspBinding=WsAccurint><Definition name=xx id=xx.yy><Methods><Method>...
@@ -185,10 +188,10 @@ ESPresponse [nil_remove, exceptions_inline] ConfigureESDLBindingMethodResponse
 
 ESPrequest GetESDLBindingRequest
 {
-    string EspProcName;   //Name of ESP Process
-    string EspBindingName;
-    string EspPort;       //Name + port = service
-    string EsdlBindingId; //espprocname.espbinding
+    string EsdlBindingId;
+    [max_ver("1.3")] string EspProcName;   //Name of ESP Process
+    [max_ver("1.3")] string EspBindingName;
+    [max_ver("1.3")] string EspPort;
     [min_ver("1.1")] bool IncludeInterfaceDefinition;
     [min_ver("1.2")] boolean ReportMethodsAvailable;
 };
@@ -233,6 +236,18 @@ ESPresponse [exceptions_inline] ListESDLDefinitionsResponse
     ESParray<ESPstruct ESDLDefinition, Definition> Definitions;
 };
 
+ESPstruct EspPortStruct
+{
+    int Value;
+    ESParray<ESPstruct ESDLBinding, Binding> Bindings;
+};
+
+ESPstruct EspProcessStruct
+{
+    string Name;
+    ESParray<ESPstruct EspPortStruct, Port> Ports;
+};
+
 ESPrequest [exceptions_inline] ListESDLBindingsRequest
 {
 };
@@ -240,10 +255,13 @@ ESPrequest [exceptions_inline] ListESDLBindingsRequest
 ESPresponse [exceptions_inline] ListESDLBindingsResponse
 {
     string BindingsXML;
-    ESParray<ESPstruct ESDLBinding, Binding> Bindings;
+    [max_ver("1.3")] ESParray<ESPstruct ESDLBinding, Binding> Bindings;
+    [min_ver("1.4")] ESParray<ESPstruct EspProcessStruct, EspProcess> EspProcesses;
 };
 
-ESPservice [auth_feature("ESDLConfigAccess:ACCESS"), version("1.3"), exceptions_inline("./smc_xslt/exceptions.xslt")] WsESDLConfig
+#define VERSION_FOR_ESDLCMD "1.4"
+
+ESPservice [auth_feature("ESDLConfigAccess:ACCESS"), version("1.4"), exceptions_inline("./smc_xslt/exceptions.xslt")] WsESDLConfig
 {
     ESPmethod Echo(EchoRequest, EchoResponse);
     ESPmethod [auth_feature("ESDLConfigAccess:WRITE")] PublishESDLDefinition(PublishESDLDefinitionRequest, PublishESDLDefinitionResponse);

+ 1 - 0
esp/services/esdl_svc_engine/CMakeLists.txt

@@ -29,6 +29,7 @@ set (   SRCS
         esdl_svc_engine_plugin.cpp
         esdl_svc_engine.cpp
         esdl_store.cpp
+        esdl_monitor.cpp
     )
 
 include_directories (

+ 99 - 79
esp/services/esdl_svc_engine/esdl_binding.cpp

@@ -37,6 +37,7 @@
 #include "wuwebview.hpp"
 #include "build-config.h"
 #include "jsmartsock.ipp"
+#include "esdl_monitor.hpp"
 
 #include "loggingagentbase.hpp"
 
@@ -240,6 +241,7 @@ void EsdlServiceImpl::configureJavaMethod(const char *method, IPropertyTree &ent
         {
             DBGLOG(E, "DynamicESDL-JavaMethod:");
             javaExceptionMap.setValue(javaScopedClass, E);
+            E->Release();
         }
     }
 }
@@ -270,7 +272,7 @@ void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entr
         Owned<ISmartSocketFactory> sf = createSmartSocketFactory(iplist, true);
 
         connMap.remove(method);
-        connMap.setValue(method, sf.getClear());
+        connMap.setValue(method, sf.get());
     }
     catch(IException* ie)
     {
@@ -285,14 +287,9 @@ void EsdlServiceImpl::configureUrlMethod(const char *method, IPropertyTree &entr
 
 void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
 {
-    StringBuffer lc(service);
-    StringBuffer xpath;
-    xpath.setf("Definition[@name='%s']/Methods", lc.toLowerCase().str());
-
-    DBGLOG("ESDL Binding: configuring method targets: %s", xpath.str());
-
+    VStringBuffer xpath("Definition[@esdlservice='%s']/Methods", service);
     IPropertyTree *target_cfg = cfg->queryPropTree(xpath.str());
-
+    DBGLOG("ESDL Binding: configuring method targets for esdl service %s", service);
     if (target_cfg)
     {
         m_pServiceMethodTargets.setown(createPTree(ipt_caseInsensitive));
@@ -319,10 +316,11 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
                 configureJavaMethod(method, iter->query(), classPath);
             else
                 configureUrlMethod(method, iter->query());
+            DBGLOG("Method %s configured", method);
         }
     }
     else
-        DBGLOG("ESDL Binding: While configuring method targets: Could not find definition: %s", xpath.str());
+        DBGLOG("ESDL Binding: While configuring method targets: method configuration not found for %s.", service);
 }
 
 #define ROXIEREQ_FLAGS (ESDL_TRANS_START_AT_ROOT | ESDL_TRANS_ROW_OUT | ESDL_TRANS_TRIM | ESDL_TRANS_OUTPUT_XMLTAG)
@@ -925,6 +923,12 @@ void EsdlServiceImpl::getTargetResponseFile(IEspContext & context,
 
 EsdlServiceImpl::~EsdlServiceImpl()
 {
+    for (auto& item : connMap)
+    {
+        ISmartSocketFactory* sf = static_cast<ISmartSocketFactory*>(item.getValue());
+        if(sf)
+            sf->stop();
+    }
 }
 
 EsdlBindingImpl::EsdlBindingImpl()
@@ -960,12 +964,26 @@ EsdlBindingImpl::EsdlBindingImpl(IPropertyTree* cfg, const char *binding,  const
 
     try
     {
-        m_esdlBndCfg.set(fetchESDLBinding(process, binding, m_esdlStateFilesLocation));
+        m_esdlBndCfg.setown(fetchESDLBinding(process, binding, m_esdlStateFilesLocation));
 
         if (!m_esdlBndCfg.get())
             DBGLOG("ESDL Binding: Could not fetch ESDL binding %s for ESP Process %s", binding, process);
+#ifdef _DEBUG
+        else
+        {
+            StringBuffer cfgtext;
+            toXML(m_esdlBndCfg.get(), cfgtext);
+            DBGLOG("ESDL binding configuration:\n%s", cfgtext.str());
+        }
+#endif
 
-        m_pSubscription.setown(createEsdlSubscription(this, process, binding));
+        if (m_esdlBndCfg.get())
+        {
+            m_bindingId.set(m_esdlBndCfg->queryProp("@id"));
+            IEsdlMonitor* monitor = queryEsdlMonitor();
+            monitor->registerBinding(m_bindingId.get(), this);
+            DBGLOG("ESDL binding %s properly registered", m_bindingId.str());
+       }
 
         StringBuffer xpath;
         xpath.appendf("Software/EspProcess[@name=\"%s\"]/EspBinding[@name=\"%s\"]", process, binding);
@@ -1005,7 +1023,7 @@ IPropertyTree* EsdlBindingImpl::fetchESDLBinding(const char *process, const char
 /* if the target ESDL binding contains an ESDL service definition matching this espServiceName, load it.
  * Otherwise, load the first definition available, and report it via the loadedServiceName
  */
-bool EsdlBindingImpl::loadDefinitions(const char * espServiceName, IEsdlDefinition * esdl, IPropertyTree * config, StringBuffer & loadedServiceName, const char * stateFileName)
+bool EsdlBindingImpl::loadDefinitions(const char * espServiceName, Owned<IEsdlDefinition>& esdl, IPropertyTree * config, StringBuffer & loadedServiceName, const char * stateFileName)
 {
     if (!esdl || !config)
         return false;
@@ -1019,12 +1037,24 @@ bool EsdlBindingImpl::loadDefinitions(const char * espServiceName, IEsdlDefiniti
         try
         {
             const char * id = esdlDefinitionConfig->queryProp("@id");
+            PROGLOG("Loading esdl definition for ID %s", id);
+            loadedServiceName.set(esdlDefinitionConfig->queryProp("@esdlservice"));
+            IEsdlShare* esdlshare = queryEsdlShare();
+            Linked<IEsdlDefinition> shareddef = esdlshare->lookup(id);
+            if (shareddef)
+            {
+                PROGLOG("Found esdl definition %s in shared cache, use it directly.", id);
+                esdl.set(shareddef);
+                return true;
+            }
+            else
+                PROGLOG("Esdl definition %s not found in shared cache, loading it from store", id);
             StringBuffer esdlXML;
             m_pCentralStore->fetchDefinition(id, esdlXML);
             if (!esdlXML.length())
             {
                 Owned<IPropertyTree> esdlDefintion;
-                DBGLOG("ESDL Binding: Could not load ESDL definition: '%s' from Dali, attempting to load from local state store", id);
+                PROGLOG("ESDL Binding: Could not load ESDL definition: '%s' from Dali, attempting to load from local state store", id);
                 Owned<IPTree> pt = createPTreeFromXMLFile(stateFileName);
 
                 if (pt)
@@ -1040,9 +1070,7 @@ bool EsdlBindingImpl::loadDefinitions(const char * espServiceName, IEsdlDefiniti
 #ifdef _DEBUG
             DBGLOG("\nESDL Definition to be loaded:\n%s", esdlXML.str());
 #endif
-
             esdl->addDefinitionFromXML(esdlXML, id);
-            loadedServiceName.set(esdlDefinitionConfig->queryProp("@name"));
 
             if (strcmp(loadedServiceName.str(), espServiceName)!=0)
                 DBGLOG("ESDL Binding: ESP service %s now based off of ESDL Service def: %s", espServiceName, loadedServiceName.str());
@@ -1067,6 +1095,7 @@ bool EsdlBindingImpl::loadDefinitions(const char * espServiceName, IEsdlDefiniti
                     DBGLOG("Error saving DESDL state file for ESP service %s", espServiceName);
                 }
             }
+            esdlshare->add(id, esdl.get());
         }
         catch (IException * e)
         {
@@ -1114,17 +1143,22 @@ void EsdlBindingImpl::saveDESDLState()
 
 bool EsdlBindingImpl::reloadDefinitionsFromCentralStore(IPropertyTree * esdlBndCng, StringBuffer & loadedname)
 {
+    if (esdlBndCng == nullptr)
+        esdlBndCng = m_esdlBndCfg.get();
     if ( m_pESDLService )
     {
         Owned<IEsdlDefinition> tempESDLDef = createNewEsdlDefinition();
 
-        if (!loadDefinitions(m_espServiceName.get(), tempESDLDef.get(), esdlBndCng, loadedname, m_esdlStateFilesLocation.str()))
+        if (!loadDefinitions(m_espServiceName.get(), tempESDLDef, esdlBndCng, loadedname, m_esdlStateFilesLocation.str()))
+        {
+            DBGLOG("Failed to reload ESDL definitions");
             return false;
+        }
 
         DBGLOG("Definitions reloaded, will update ESDL definition object");
         CriticalBlock b(configurationLoadCritSec);
 
-        m_esdl.set(tempESDLDef.getClear());
+        m_esdl.setown(tempESDLDef.getClear());
         m_pESDLService->setEsdlTransformer(createEsdlXFormer(m_esdl));
 
         return true;
@@ -1134,58 +1168,65 @@ bool EsdlBindingImpl::reloadDefinitionsFromCentralStore(IPropertyTree * esdlBndC
     return false;
 }
 
-
-bool EsdlBindingImpl::reloadBindingFromCentralStore(const char *binding, const char *process)
+bool EsdlBindingImpl::reloadBindingFromCentralStore(const char* bindingId)
 {
-    if (strcmp(m_bindingName.get(), binding)==0)
+    if(!bindingId || !*bindingId)
+        return false;
+    if(m_bindingId.length() == 0 || strcmp(m_bindingId.str(), bindingId) != 0)
+        m_bindingId.set(bindingId);
+    try
     {
-        try
+        DBGLOG("Reloading binding %s...", bindingId);
+        if ( m_pESDLService)
         {
-            DBGLOG("Reloading binding %s.%s...", m_processName.get(), m_bindingName.get());
-            if ( m_pESDLService)
-            {
-                Owned<IPropertyTree> tempEsdlBndCfg;
-                DBGLOG("Fetching ESDL binding information from dali based on ESP binding (%s.%s)", m_processName.get(), m_bindingName.get());
-                tempEsdlBndCfg.set(m_pCentralStore->fetchBinding(process, binding));
+            Owned<IPropertyTree> tempEsdlBndCfg;
+            DBGLOG("Fetching ESDL binding information from dali based on ESP binding (%s)", bindingId);
+            tempEsdlBndCfg.setown(m_pCentralStore->fetchBinding(bindingId));
 
-                if (!tempEsdlBndCfg.get())
-                {
-                    clearDESDLState();
-                    clearState(m_esdlStateFilesLocation.str());
-                    return false;
-                }
+            if (!tempEsdlBndCfg.get())
+            {
+                clearDESDLState();
+                clearState(m_esdlStateFilesLocation.str());
+                return false;
+            }
 
-                StringBuffer loadedname;
-                if (!reloadDefinitionsFromCentralStore(tempEsdlBndCfg.get(), loadedname))
-                    return false;
+            StringBuffer loadedname;
+            if (!reloadDefinitionsFromCentralStore(tempEsdlBndCfg.get(), loadedname))
+                return false;
 
-                IEsdlDefService *srvdef = m_esdl->queryService(loadedname);
+            IEsdlDefService *srvdef = m_esdl->queryService(loadedname);
 
-                if (srvdef)
-                    initEsdlServiceInfo(*srvdef);
-
-                m_pESDLService->m_espServiceType.set(loadedname);
-                m_pESDLService->configureTargets(tempEsdlBndCfg, loadedname);
-                m_esdlBndCfg.set(tempEsdlBndCfg.getClear());
-            }
-            else
-                DBGLOG("Could not reload binding %s because service implementation object not available.", m_bindingName.get());
+            if (srvdef)
+                initEsdlServiceInfo(*srvdef);
 
+            m_pESDLService->m_espServiceType.set(loadedname);
+            m_pESDLService->configureTargets(tempEsdlBndCfg, loadedname);
+            m_esdlBndCfg.setown(tempEsdlBndCfg.getClear());
         }
-        catch(IException* e)
-        {
-           StringBuffer msg;
-           e->errorMessage(msg);
-           DBGLOG("Exception caught in EsdlBindingImpl::EsdlBindingImpl: %s", msg.str());
-        }
-        catch (...)
-        {
-            DBGLOG("Exception caught in EsdlBindingImpl::EsdlBindingImpl: Could Not load Binding %s information from Dali!", binding);
-        }
+        else
+            DBGLOG("Could not reload binding %s because service implementation object not available.", bindingId);
+
+    }
+    catch(IException* e)
+    {
+       StringBuffer msg;
+       e->errorMessage(msg);
+       DBGLOG("Exception caught in EsdlBindingImpl::EsdlBindingImpl: %s", msg.str());
+       e->Release();
+    }
+    catch (...)
+    {
+        DBGLOG("Exception caught in EsdlBindingImpl::EsdlBindingImpl: Could Not load Binding %s information from Dali!", bindingId);
     }
     return true;
 }
 
+void EsdlBindingImpl::clearBindingState()
+{
+    clearDESDLState();
+    clearState(m_esdlStateFilesLocation.str());
+}
+
 void EsdlBindingImpl::addService(const char * name,
                                  const char * host,
                                  unsigned short port,
@@ -1199,7 +1240,7 @@ void EsdlBindingImpl::addService(const char * name,
         m_pESDLService = dynamic_cast<EsdlServiceImpl*>(&service);
 
     m_espServiceName.set(name);
-    DBGLOG("ESDL Binding: Adding service '%s' on host %s and port %d on %s binding.", name, host, port, m_bindingName.get());
+    DBGLOG("ESDL Binding: Adding service '%s' on %s port %d on %s binding.", name, (host&&*host)?host:"", port, m_bindingName.get());
     if ( m_pESDLService)
     {
         if (m_esdlBndCfg)
@@ -1207,7 +1248,7 @@ void EsdlBindingImpl::addService(const char * name,
             if (m_esdl)
             {
                 StringBuffer loadedservicename;
-                if (!loadDefinitions(name, m_esdl.get(), m_esdlBndCfg, loadedservicename, m_esdlStateFilesLocation.str()))
+                if (!loadDefinitions(name, m_esdl, m_esdlBndCfg, loadedservicename, m_esdlStateFilesLocation.str()))
                 {
                     DBGLOG("ESDL Binding: Error adding ESP service '%s': Could not fetch ESDL definition", name);
                     return;
@@ -2827,27 +2868,6 @@ bool EsdlBindingImpl::makeURL( StringBuffer& url, IPropertyTree& cfg )
     return result;
 }
 
-void EsdlBindingImpl::onNotify(EsdlNotifyData* data)
-{
-    if (!data)
-        return;
-    CriticalBlock b(configurationLoadCritSec);
-    if (data->type == EsdlNotifyType::DefinitionUpdate)
-    {
-        if (usesESDLDefinition(data->id.str()))
-        {
-            DBGLOG("Requesting reload of ESDL definitions for %s.%s binding...", m_processName.get(), m_bindingName.get() );
-            StringBuffer loaded;
-            reloadDefinitionsFromCentralStore(m_esdlBndCfg.get(), loaded);
-        }
-    }
-    else
-    {
-        DBGLOG("Requesting reload of %s.%s binding...", data->espProcess.str(), data->espBinding.str() );
-        reloadBindingFromCentralStore(data->espBinding.str(), data->espProcess.str());
-    }
-}
-
 bool EsdlBindingImpl::usesESDLDefinition(const char * name, int version)
 {
     if (!name || !*name)

+ 25 - 214
esp/services/esdl_svc_engine/esdl_binding.hpp

@@ -29,6 +29,7 @@
 #include "eclrtl.hpp"
 #include "dautils.hpp"
 #include "esdl_store.hpp"
+#include "esdl_monitor.hpp"
 
 static const char* ESDL_METHOD_DESCRIPTION="description";
 static const char* ESDL_METHOD_HELP="help";
@@ -175,143 +176,9 @@ public:
 
 #define DEFAULT_ESDLBINDING_URN_BASE "urn:hpccsystems:ws"
 
-class EsdlBindingImpl : public CHttpSoapBinding, implements IEsdlListener
+class EsdlBindingImpl : public CHttpSoapBinding
 {
 private:
-/*
-
-    //==========================================================================================
-    // the following class implements notification handler for subscription to dali for environment
-    // updates by other clients.
-    //==========================================================================================
-    class CESDLBindingSubscription : public CInterface, implements ISDSSubscription
-    {
-    private :
-        CriticalSection daliSubscriptionCritSec;
-        SubscriptionId sub_id;
-        EsdlBindingImpl * thisBinding;
-
-    public:
-        CESDLBindingSubscription(EsdlBindingImpl * binding)
-        {
-            thisBinding = binding;
-            sub_id = 0;
-            subscribe();
-        }
-
-        virtual ~CESDLBindingSubscription()
-        {
-            unsubscribe();
-        }
-
-        void unsubscribe()
-        {
-            CriticalBlock b(daliSubscriptionCritSec);
-            try
-            {
-                if (sub_id)
-                {
-                    querySDS().unsubscribe(sub_id);
-                    sub_id = 0;
-                }
-            }
-            catch (IException *E)
-            {
-                E->Release();
-            }
-            sub_id = 0;
-        }
-
-        void subscribe()
-        {
-            VStringBuffer fullBindingPath("/ESDL/Bindings/Binding[@id=\'%s.%s\']",thisBinding->m_processName.get(),thisBinding->m_bindingName.get());
-            try
-            {
-                CriticalBlock b(daliSubscriptionCritSec);
-                if (!sub_id)
-                    sub_id = querySDS().subscribe(fullBindingPath.str(), *this, true);
-            }
-            catch (IException *E)
-            {
-                ESPLOG(LogMin, "ESDL Binding %s.%s failed to subscribe to DALI (%s)", thisBinding->m_processName.get(),thisBinding->m_bindingName.get(), fullBindingPath.str());
-                E->Release();
-            }
-        }
-
-        bool isSubscribed()
-        {
-            CriticalBlock b(daliSubscriptionCritSec);
-            return sub_id > 0;
-        }
-
-        IMPLEMENT_IINTERFACE;
-        void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen=0, const void *valueData=NULL);
-    };
-
-    class CESDLDefinitionSubscription : public CInterface, implements ISDSSubscription
-    {
-    private :
-        CriticalSection daliSubscriptionCritSec;
-        SubscriptionId sub_id;
-        EsdlBindingImpl * thisBinding;
-
-    public:
-        CESDLDefinitionSubscription(EsdlBindingImpl * binding)
-        {
-            thisBinding = binding;
-            subscribe();
-        }
-
-        virtual ~CESDLDefinitionSubscription()
-        {
-            unsubscribe();
-        }
-
-        void unsubscribe()
-        {
-            CriticalBlock b(daliSubscriptionCritSec);
-            try
-            {
-                if (sub_id)
-                {
-                    ESPLOG(LogNormal,"ESDL Binding %s is UN subscribing from /ESDL/Bindings/Binding dali changes", thisBinding->m_bindingName.get());
-                    querySDS().unsubscribe(sub_id);
-                    sub_id = 0;
-                }
-            }
-            catch (IException *E)
-            {
-                E->Release();
-            }
-            sub_id = 0;
-        }
-
-        void subscribe()
-        {
-            //for some reason subscriptions based on xpaths with attributes don't seem to work correctly
-            //fullBindingPath.set("/ESDL/Bindings/Binding[@EspBinding=\'WsAccurint\'][@EspProcess=\'myesp\']");
-            CriticalBlock b(daliSubscriptionCritSec);
-            try
-            {
-                sub_id = querySDS().subscribe(ESDL_DEF_PATH, *this, true);
-            }
-            catch (IException *E)
-            {
-                E->Release();
-            }
-        }
-
-        bool isSubscribed()
-        {
-            CriticalBlock b(daliSubscriptionCritSec);
-            return sub_id > 0;
-        }
-
-        IMPLEMENT_IINTERFACE;
-        void notify(SubscriptionId id, const char *xpath, SDSNotifyFlags flags, unsigned valueLen=0, const void *valueData=NULL);
-    };
-
-*/
     Owned<IPropertyTree>                    m_bndCfg;
     Owned<IPropertyTree>                    m_esdlBndCfg;
 
@@ -323,13 +190,13 @@ private:
     StringAttr                              m_processName;
     StringAttr                              m_espServiceName; //previously held the esdl service name, we are now
                                                               //supporting mismatched ESP Service name assigned to a different named ESDL service definition
-    Owned<IEsdlSubscription>                m_pSubscription;
     Owned<IEsdlStore>                       m_pCentralStore;
     CriticalSection                         configurationLoadCritSec;
     CriticalSection                         detachCritSec;
     StringBuffer                            m_esdlStateFilesLocation;
     StringBuffer                            m_staticNamespace;
     bool                                    m_isAttached;
+    StringAttr                              m_bindingId;
 
     virtual void clearDESDLState()
     {
@@ -352,9 +219,6 @@ public:
 
     virtual ~EsdlBindingImpl()
     {
-        //Unsubscribe early to avoid a segfault due to closed dali connection
-        if(m_pSubscription)
-            m_pSubscription->unsubscribe();
     }
 
     virtual int onGet(CHttpRequest* request, CHttpResponse* response);
@@ -407,47 +271,40 @@ public:
     bool usesESDLDefinition(const char * name, int version);
     bool usesESDLDefinition(const char * id);
     virtual bool isDynamicBinding() const override { return true; }
+    virtual bool isBound() const override { return (m_esdlBndCfg.get() != nullptr); }
     virtual unsigned getCacheMethodCount(){return 0;}
-    virtual void onNotify(EsdlNotifyData* data);
+    bool reloadBindingFromCentralStore(const char* bindingId);
+    bool reloadDefinitionsFromCentralStore(IPropertyTree * esdlBndCng, StringBuffer & loadedname);
+    void clearBindingState();
 
     virtual bool subscribeBindingToDali() override
     {
-        ESPLOG(LogNormal, "Binding '%s.%s' is subscribing to Dali for ESDL changes...", m_processName.get(), m_bindingName.get() );
-        if (m_pSubscription)
+        CriticalBlock b(detachCritSec);
+        if(m_isAttached)
+            return true;
+        queryEsdlMonitor()->subscribe();
+        m_isAttached = true;
+        if(m_bindingId.length() != 0)
         {
-            ESPLOG(LogNormal, "ESDL Binding %s is subscribing to all /ESDL/Bindings/Binding dali changes", this->m_bindingName.get());
-            m_pSubscription->subscribe();
+            ESPLOG(LogNormal, "Requesting reload of ESDL binding %s...", m_bindingId.get());
+            reloadBindingFromCentralStore(m_bindingId.get());
         }
-
-        //if (m_pDefinitionSubscription)
-        //{
-        //    ESPLOG(LogNormal, "ESDL Binding %s is subscribing to all /ESDL/Bindings/Definition dali changes", this->m_bindingName.get());
-        //    m_pDefinitionSubscription->subscribe();
-        //}
-
-        ESPLOG(LogNormal, "Requesting reload of ESDL %s.%s binding...", m_processName.get(), m_bindingName.get() );
-        reloadBindingFromCentralStore(m_bindingName.get(), m_processName.get());
-
-        setIsAttached(true);
         return true;
     }
 
     virtual bool unsubscribeBindingFromDali() override
     {
-        if(m_pSubscription)
-            m_pSubscription->unsubscribe();
-        //pSubscription->subscribe/unsubscribe only affects bindings, not definitions
-        // if(m_pDefinitionSubscription)
-        //     m_pDefinitionSubscription->unsubscribe();
-
-         setIsAttached(false);
-         return true;
+        CriticalBlock b(detachCritSec);
+        if(!m_isAttached)
+            return true;
+        m_isAttached = false;
+        queryEsdlMonitor()->unsubscribe();
+        return true;
     }
 
     bool detachBindingFromDali() override
     {
-        unsubscribeBindingFromDali();
-        return false;
+        return unsubscribeBindingFromDali();
     }
 
     virtual bool canDetachFromDali() override
@@ -455,54 +312,10 @@ public:
         return true;
     }
 
-    virtual bool attach()
-    {
-        if (isAttached())
-        {
-            ESPLOG(LogNormal, "Binding %s.%s is already attached to Dali for ESDL changes...", m_processName.get(), m_bindingName.get() );
-            return true;
-        }
-
-        if (m_pSubscription)
-        {
-            ESPLOG(LogNormal, "Binding %s.%s is subscribing to Dali for ESDL changes...", m_processName.get(), m_bindingName.get() );
-            m_pSubscription->subscribe();
-
-            ESPLOG(LogNormal, "Requesting reload of ESDL %s.%s binding...", m_processName.get(), m_bindingName.get() );
-            reloadBindingFromCentralStore(m_bindingName.get(), m_processName.get());
-            setIsAttached(true);
-
-            /* rodrigo
-
-                    if (m_pDefinitionSubscription)
-                    {
-                        ESPLOG(LogNormal, "ESDL Binding %s is subscribing to all /ESDL/Bindings/Definition dali changes", this->m_bindingName.get());
-                        m_pDefinitionSubscription->subscribe();
-                    }
-            */
-            return true;
-        }
-        else
-            ESPLOG(LogNormal, "Could not subscribe binding '%s.%s' to Dali for ESDL changes...", m_processName.get(), m_bindingName.get() );
-
-        return false;
-    };
-
-    virtual bool detach()
-    {
-        if (m_pSubscription)
-            m_pSubscription->unsubscribe();
-        else
-            ESPLOG(LogNormal, "Could not unsubscribe binding '%s.%s' from Dali for ESDL changes...", m_processName.get(), m_bindingName.get() );
-
-        m_isAttached = false;
-        return true;
-    }
-
     void setIsAttached(bool isattached)
     {
-      CriticalBlock b(detachCritSec);
-      m_isAttached = isattached;
+        CriticalBlock b(detachCritSec);
+        m_isAttached = isattached;
     }
 
     bool isAttached()
@@ -516,11 +329,9 @@ private:
     int onRoxieRequest(CHttpRequest* request, CHttpResponse* response, const char *  method);
     void getSoapMessage(StringBuffer& out,StringBuffer& soapresp,const char * starttxt,const char * endtxt);
 
-    bool reloadBindingFromCentralStore(const char *binding, const char *process);
-    bool reloadDefinitionsFromCentralStore(IPropertyTree * esdlBndCng, StringBuffer & loadedname);
     void saveDESDLState();
     IPropertyTree * fetchESDLBinding(const char *process, const char *bindingName, const char * stateFileName);
-    bool loadDefinitions(const char * espServiceName, IEsdlDefinition * esdl, IPropertyTree * config, StringBuffer & loadedServiceName, const char * stateFileName);
+    bool loadDefinitions(const char * espServiceName, Owned<IEsdlDefinition>& esdl, IPropertyTree * config, StringBuffer & loadedServiceName, const char * stateFileName);
 };
 
 #endif //_EsdlBinding_HPP__

+ 575 - 0
esp/services/esdl_svc_engine/esdl_monitor.cpp

@@ -0,0 +1,575 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "esdl_monitor.hpp"
+#include "jmd5.hpp"
+#include "esdl_binding.hpp"
+#include "esdl_svc_engine.hpp"
+#include <memory>
+
+class CEsdlInstance : public CInterface
+{
+public:
+    CEsdlInstance() { }
+    CEsdlInstance(const char* defId, IEsdlDefinition* def)
+    {
+        StringBuffer lcid(defId);
+        lcid.trim().toLowerCase();
+        m_defId.set(lcid.str());
+        m_def.set(def);
+    }
+    virtual ~CEsdlInstance()
+    {
+    }
+    StringBuffer m_defId;
+    Owned<IEsdlDefinition> m_def;
+};
+
+//This class is for storing esdl definition objects to be shared among
+//ESDL services to save memory space and increase efficiency
+class CEsdlShare : implements IEsdlShare, public Thread
+{
+public:
+    IMPLEMENT_IINTERFACE;
+    CEsdlShare() : m_stop(false)
+    {
+    }
+    virtual ~CEsdlShare() {}
+
+    virtual void add(const char* defId, IEsdlDefinition* def) override
+    {
+        if (!defId || !*defId || !def)
+            return;
+        DBGLOG("Adding esdl definition %s to shared cache", defId);
+        Owned<CEsdlInstance> instance = new CEsdlInstance(defId, def);
+        CriticalBlock cb(m_critSect);
+        m_esdlInstanceMap.setValue(defId, instance.getLink());
+    }
+
+    virtual void remove(const char* defId) override
+    {
+        if (!defId || !*defId)
+            return;
+        StringBuffer lcid(defId);
+        lcid.trim().toLowerCase();
+        if (lcid.length() == 0)
+            return;
+        defId = lcid.str();
+        DBGLOG("Removing esdl definition %s from shared cache", defId);
+        {
+            CriticalBlock cb(m_critSect);
+            m_esdlInstanceMap.remove(defId);
+        }
+    }
+
+    virtual Linked<IEsdlDefinition> lookup(const char* defId) override
+    {
+        if (!defId || !*defId)
+            return nullptr;
+        StringBuffer lcid(defId);
+        lcid.trim().toLowerCase();
+        if (lcid.length() == 0)
+            return nullptr;
+        defId = lcid.str();
+        {
+            CriticalBlock cb(m_critSect);
+            Owned<CEsdlInstance>* instancepp = m_esdlInstanceMap.getValue(defId);
+            if (instancepp)
+                return (*instancepp)->m_def.get();
+        }
+        return nullptr;
+    }
+
+    //Thread periodically cleaning definition objects that are no longer being used
+    virtual int run() override
+    {
+        while (!m_stop)
+        {
+            m_waitsem.wait(300000);
+            if(m_stop)
+                break;
+            {
+                CriticalBlock cb(m_critSect);
+                StringArray ids;
+                for (auto& item : m_esdlInstanceMap)
+                {
+                    CEsdlInstance* instance = item.getValue();
+                    if (!instance || !instance->m_def.get())
+                        continue;
+                    if (!instance->m_def->isShared())
+                        ids.append(instance->m_defId.str());
+                }
+                ForEachItemIn (x, ids)
+                {
+                    const char* id = ids.item(x);
+                    DBGLOG("Definition %s is no longer being used, remove it from esdl shared cache", id);
+                    m_esdlInstanceMap.remove(id);
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    virtual void stop()
+    {
+        m_stop = true;
+        m_waitsem.signal();
+        join();
+    }
+private:
+    CriticalSection m_critSect;
+    MapStringTo<Owned<CEsdlInstance>> m_esdlInstanceMap;
+    Semaphore m_waitsem;
+    bool m_stop;
+};
+
+static CriticalSection gEsdlMonitorCritSection;
+
+class CEsdlMonitor : implements IEsdlMonitor, public CInterface, implements IEsdlListener
+{
+private:
+    MapStringTo<EsdlBindingImpl*> m_esdlBindingMap;
+    CriticalSection m_CritSect;
+    StringBuffer mEnvptHeader;
+    Owned<IEsdlStore> m_pCentralStore;
+    Owned<IEsdlSubscription> m_pSubscription;
+    Owned<CEsdlShare> m_esdlShare;
+    bool m_isSubscribed;
+
+public:
+    IMPLEMENT_IINTERFACE;
+
+    CEsdlMonitor() : m_isSubscribed(false)
+    {
+        constructEnvptHeader();
+        m_pCentralStore.setown(createEsdlCentralStore());
+        m_esdlShare.setown(new CEsdlShare());
+        m_esdlShare->start();
+        DBGLOG("EsdlMonitor started.");
+    }
+
+    virtual ~CEsdlMonitor()
+    {
+        if (m_pSubscription && m_isSubscribed)
+            m_pSubscription->unsubscribe();
+    }
+
+    CEsdlShare* queryEsdlShare()
+    {
+        return m_esdlShare.get();
+    }
+
+    void setupSubscription()
+    {
+        m_isSubscribed = true;
+        m_pSubscription.setown(createEsdlSubscription(this));
+    }
+
+    virtual void subscribe() override
+    {
+        CriticalBlock cb(m_CritSect);
+        if(m_isSubscribed)
+            return;
+        m_isSubscribed = true;
+        m_pSubscription->subscribe();
+    }
+
+    virtual void unsubscribe() override
+    {
+        CriticalBlock cb(m_CritSect);
+        if(!m_isSubscribed)
+            return;
+        m_isSubscribed = false;
+        m_pSubscription->unsubscribe();
+    }
+
+    //Reference count increment is done by the function
+    virtual void registerBinding(const char* bindingId, IEspRpcBinding* binding) override
+    {
+        if (!bindingId || !binding)
+            return;
+        EsdlBindingImpl* esdlbinding = dynamic_cast<EsdlBindingImpl*>(binding);
+        if (esdlbinding)
+        {
+            CriticalBlock cb(m_CritSect);
+            m_esdlBindingMap.setValue(bindingId, esdlbinding);
+        }
+    }
+
+    void loadDynamicBindings()
+    {
+        Owned<IPropertyTree> esdlBindings = m_pCentralStore->getBindings();
+        if (!esdlBindings)
+           throw MakeStringException(-1, "Unable to retrieve ESDL bindings information");
+
+        Owned<IPropertyTreeIterator> iter = esdlBindings->getElements("Binding");
+        ForEach (*iter)
+        {
+            std::unique_ptr<EsdlNotifyData> data(new EsdlNotifyData);
+            IPropertyTree & cur = iter->query();
+            cur.getProp("@id", data->id);
+            if(data->id.length() == 0)
+            {
+                DBGLOG("ESDL binding id is missing, skip.");
+                continue;
+            }
+            cur.getProp("@espprocess", data->espProcess);
+            if (!espProcessMatch(data->espProcess.str()))
+            {
+                DBGLOG("ESDL binding %s is not for this esp process, skip.", data->id.str());
+                continue;
+            }
+            cur.getProp("@espbinding", data->name);
+            if (data->name.length() != 0 && existsStaticBinding(data->name.str()))
+            {
+                DBGLOG("ESDL binding %s has esp binding configured, no need to create it dynamically, skip.", data->id.str());
+                continue;
+            }
+            else
+                DBGLOG("ESDL binding %s doesn't have esp binding configured, creating the binding dynamically...", data->id.str());
+
+            data->port = cur.getPropInt("@port");
+            if (data->port == 0)
+            {
+                DBGLOG("ESDL binding %s doesn't have port specified, skip", data->id.str());
+                continue;
+            }
+
+            try
+            {
+                addBinding(data.get());
+            }
+            catch(IException* e)
+            {
+                StringBuffer msg;
+                e->errorMessage(msg);
+                ERRLOG("Exception while loading dynamic binding %s: %d - %s", data->id.str(), e->errorCode(), msg.str());
+                e->Release();
+            }
+        }
+    }
+
+    //IEsdlListener
+    virtual void onNotify(EsdlNotifyData* data) override
+    {
+        if (!m_isSubscribed || !data)
+            return;
+
+        EsdlNotifyType ntype = data->type;
+
+        if (ntype == EsdlNotifyType::DefinitionDelete)
+        {
+            CriticalBlock cb(m_CritSect);
+            m_esdlShare->remove(data->id.str());
+        }
+        else if (ntype == EsdlNotifyType::DefinitionUpdate)
+        {
+            CriticalBlock cb(m_CritSect);
+            m_esdlShare->remove(data->id.str());
+            for (auto& sb:m_esdlBindingMap)
+            {
+                EsdlBindingImpl* binding = sb.getValue();
+                if (binding->usesESDLDefinition(data->id.str()))
+                {
+                    DBGLOG("Requesting reload of ESDL definitions for binding %s...", (const char*)sb.getKey());
+                    StringBuffer loaded;
+                    binding->reloadDefinitionsFromCentralStore(nullptr, loaded);
+                }
+            }
+        }
+        else if (ntype == EsdlNotifyType::BindingDelete)
+        {
+            CriticalBlock cb(m_CritSect);
+            EsdlBindingImpl* theBinding = findBinding(data->id.str());
+            if (theBinding)
+            {
+                DBGLOG("Requesting clearing of binding %s", data->id.str());
+                if (data->name.length() > 0 && existsStaticBinding(data->name.str()))
+                {
+                    DBGLOG("Static esp binding exists for this esdl binding.");
+                    theBinding->reloadBindingFromCentralStore(data->id.str()); //clear the binding by reloading
+                }
+                else
+                {
+                    theBinding->clearBindingState();
+                    if (data->port <= 0)
+                        data->port = theBinding->getPort();
+                    DBGLOG("Removing binding from port %d", data->port);
+                    queryEspServer()->removeBinding(data->port, *theBinding);
+                }
+                removeBindingFromMap(data->id.str());
+            }
+            else
+                DBGLOG("Can't delete binding %s, it's not currently registered", data->id.str());
+        }
+        else if (ntype == EsdlNotifyType::BindingUpdate)
+        {
+            CriticalBlock cb(m_CritSect);
+            EsdlBindingImpl* theBinding = findBinding(data->id.str());
+            if (!theBinding)
+            {
+                DBGLOG("Binding %s not found, can't update", data->id.str());
+                return;
+            }
+            DBGLOG("Reloading ESDL binding %s", data->id.str());
+            theBinding->reloadBindingFromCentralStore(data->id.str());
+        }
+        else if (ntype == EsdlNotifyType::BindingAdd)
+        {
+            if (!espProcessMatch(data->espProcess.str()))
+            {
+                DBGLOG("ESDL binding %s is not for this esp process, ignore.", data->id.str());
+                return;
+            }
+
+            CriticalBlock cb(m_CritSect);
+            EsdlBindingImpl* theBinding = findBinding(data->id.str());
+            if (theBinding)
+            {
+                DBGLOG("Binding %s already exists, reload...", data->id.str());
+                theBinding->reloadBindingFromCentralStore(data->id.str());
+                return;
+            }
+
+            bool existsStatic = false;
+            if (data->name.length() > 0)
+                existsStatic = existsStaticBinding(data->name.str());
+            else
+                data->name.set(data->id);
+            if (!existsStatic)
+            {
+                DBGLOG("ESDL binding %s doesn't have esp binding configured, creating the binding dynamically...", data->id.str());
+                if (data->port == 0)
+                {
+                    DBGLOG("Port is not provided for binding, can't create binding.");
+                    return;
+                }
+                addBinding(data);
+            }
+            else
+            {
+                DBGLOG("ESDL binding %s has esp binding configured, reloading the esp binding...", data->id.str());
+                //Reload static binding
+                IEspServer* server = queryEspServer();
+                IEspRpcBinding* espBinding = server->queryBinding(data->name.str());
+                if (espBinding != nullptr)
+                {
+                    EsdlBindingImpl* esdlBinding = dynamic_cast<EsdlBindingImpl*>(espBinding);
+                    if (esdlBinding != nullptr)
+                    {
+                        esdlBinding->reloadBindingFromCentralStore(data->id.str());
+                        registerBinding(data->id.str(), esdlBinding);
+                    }
+                    else
+                        DBGLOG("The esp binding failed to be cast to esdl binding.");
+                }
+                else
+                    DBGLOG("Esp binding not found.");
+            }
+        }
+        else
+        {
+            WARNLOG("Unexpected notify type received, ignore.");  //DefintionAdd and DefinitionDelete shouldn't happen
+        }
+    }
+
+private:
+    EsdlBindingImpl* findBinding(const char* bindingId)
+    {
+        if (!bindingId)
+            return nullptr;
+        EsdlBindingImpl** ptrptr = m_esdlBindingMap.getValue(bindingId);
+        if (ptrptr)
+            return *ptrptr;
+        else
+            return nullptr;
+    }
+
+    void removeBindingFromMap(const char* bindingId)
+    {
+        if (!bindingId)
+            return;
+        CriticalBlock cb(m_CritSect);
+        m_esdlBindingMap.remove(bindingId);
+    }
+
+    void addBinding(EsdlNotifyData* data)
+    {
+        DBGLOG("Creating new binding %s", data->id.str());
+        CriticalBlock cb(m_CritSect);
+        if (data->name.length() == 0)
+            data->name.set(data->id);
+        StringBuffer protocol, serviceName;
+        Owned<IPropertyTree> envpt = getEnvpt(data, protocol, serviceName);
+        if (protocol.length() == 0)
+            protocol.set("http");
+        StringBuffer envptxml;
+        toXML(envpt, envptxml);
+        DBGLOG("Use the following config tree to create the binding and service:\n%s\n", envptxml.str());
+        IEspServer* server = queryEspServer();
+        IEspProtocol* espProtocol = server->queryProtocol(protocol.str());
+        Owned<EsdlBindingImpl> esdlbinding = new CEsdlSvcEngineSoapBindingEx(envpt,  data->name.str(), data->espProcess.str());
+        Owned<EsdlServiceImpl> esdlservice = new CEsdlSvcEngine();
+        esdlservice->init(envpt, data->espProcess.str(), serviceName.str());
+        esdlbinding->addService(esdlservice->getServiceType(), nullptr, data->port, *esdlservice.get());
+        esdlbinding->addProtocol(protocol.str(), *espProtocol);
+        server->addBinding(data->name.str(), nullptr, data->port, *espProtocol, *esdlbinding.get(), false, envpt);
+        DBGLOG("Successfully instantiated new DESDL binding %s and service", data->id.str());
+    }
+
+    bool existsStaticBinding(const char* espBinding)
+    {
+        if (!espBinding || !*espBinding)
+            return false;
+        DBGLOG("Checking if there is esp binding %s configured...", espBinding);
+        IPropertyTree* procpt = queryEspServer()->queryProcConfig();
+        if (procpt)
+        {
+            VStringBuffer xpath("EspBinding[@name='%s']", espBinding);
+            if (procpt->queryPropTree(xpath.str()) != nullptr)
+                return true;
+        }
+        return false;
+    }
+
+    bool espProcessMatch(const char* espProcess)
+    {
+        if (!espProcess)
+            return false;
+        return (strcmp(espProcess, queryEspServer()->getProcName()) == 0);
+    }
+
+    void constructEnvptHeader()
+    {
+        mEnvptHeader.set("<Environment><Software><EspProcess ");
+        IPropertyTree* procpt = queryEspServer()->queryProcConfig();
+        if (procpt)
+        {
+            Owned<IAttributeIterator> attrs = procpt->getAttributes(false);
+            for (attrs->first(); attrs->isValid(); attrs->next())
+            {
+                StringBuffer name(attrs->queryName());
+                StringBuffer value;
+                encodeXML(attrs->queryValue(), value);
+                if (name.length() > 1)
+                    mEnvptHeader.appendf("%s=\"%s\" ", name.str()+1, value.str());
+            }
+        }
+        mEnvptHeader.append(">");
+    }
+
+    IPropertyTree* getEnvpt(EsdlNotifyData* notifyData, StringBuffer& protocol, StringBuffer& serviceName)
+    {
+        VStringBuffer portStr("%d", notifyData->port);
+        return getEnvpt(notifyData->espProcess.str(), notifyData->name.str(), notifyData->id.str(),
+                portStr.str(), protocol, serviceName);
+    }
+
+    IPropertyTree* getEnvpt(const char* espProcess, const char* bindingName, const char* bindingId, const char* port, StringBuffer& protocol, StringBuffer& serviceName)
+    {
+        if (!bindingName || !*bindingName)
+            bindingName = bindingId;
+        serviceName.set(bindingId);
+        StringBuffer envxmlbuf;
+        IPropertyTree* procpt = queryEspServer()->queryProcConfig();
+        if (procpt)
+        {
+            //If esp's original config has one configured for this binding, use it
+            VStringBuffer xpath("EspBinding[@name='%s']", bindingName);
+            IPropertyTree* bindingtree = procpt->queryPropTree(xpath.str());
+            if (bindingtree)
+            {
+                bindingtree->getProp("@protocol", protocol);
+                return LINK(procpt);
+            }
+            //Otherwise check if there's binding configured on the same port
+            xpath.clear().appendf("EspBinding[@type='EsdlBinding'][@port='%s'][1]", port);
+            bindingtree = procpt->queryPropTree(xpath.str());
+            if (!bindingtree)
+            {
+                //Otherwise check if there's binding configured with port 0
+                xpath.clear().appendf("EspBinding[@type='EsdlBinding'][@port='0']");
+                bindingtree = procpt->queryPropTree(xpath.str());
+            }
+            if (bindingtree)
+            {
+                bindingtree->getProp("@protocol", protocol);
+                const char* service = bindingtree->queryProp("@service");
+                xpath.clear().appendf("EspService[@name='%s']", service);
+                IPropertyTree* servicetree = procpt->queryPropTree(xpath.str());
+                if (servicetree)
+                {
+                    bindingtree = createPTreeFromIPT(bindingtree);
+                    servicetree = createPTreeFromIPT(servicetree);
+                    bindingtree->setProp("@name", bindingName);
+                    bindingtree->setProp("@service", serviceName.str());
+                    bindingtree->setProp("@port", port);
+                    servicetree->setProp("@name", serviceName.str());
+                    servicetree->setProp("@type", "DynamicESDL");
+                    envxmlbuf.appendf("%s</EspProcess></Software></Environment>", mEnvptHeader.str());
+                    Owned<IPropertyTree> envpttree = createPTreeFromXMLString(envxmlbuf.str());
+                    envpttree->addPropTree("Software/EspProcess/EspBinding", bindingtree);
+                    envpttree->addPropTree("Software/EspProcess/EspService", servicetree);
+                    return envpttree.getClear();
+                }
+            }
+        }
+        throw MakeStringException(-1, "There's no template esp binding configured on port %s, or port 0.", port);
+    }
+};
+
+static Owned<CEsdlMonitor> gEsdlMonitor;
+static bool isEsdlMonitorStarted = false;
+
+extern "C" void startEsdlMonitor()
+{
+    CriticalBlock cb(gEsdlMonitorCritSection);
+    if (gEsdlMonitor.get() == nullptr)
+    {
+        CEsdlMonitor* monitor = new CEsdlMonitor();
+        gEsdlMonitor.setown(monitor);
+        isEsdlMonitorStarted = true;
+        monitor->loadDynamicBindings();
+        monitor->setupSubscription();
+    }
+}
+
+extern "C" void stopEsdlMonitor()
+{
+    DBGLOG("stopping esdl monitor...");
+    CriticalBlock cb(gEsdlMonitorCritSection);
+    if (gEsdlMonitor.get() != nullptr)
+    {
+        gEsdlMonitor->queryEsdlShare()->stop();
+        gEsdlMonitor.clear();
+    }
+}
+
+IEsdlMonitor* queryEsdlMonitor()
+{
+    if (!isEsdlMonitorStarted)
+        startEsdlMonitor();
+    return gEsdlMonitor.get();
+}
+
+IEsdlShare* queryEsdlShare()
+{
+    if (!isEsdlMonitorStarted)
+        startEsdlMonitor();
+    return gEsdlMonitor->queryEsdlShare();
+}

+ 44 - 0
esp/services/esdl_svc_engine/esdl_monitor.hpp

@@ -0,0 +1,44 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+#ifndef ESDL_MONITOR_HPP
+
+#include "esdl_def.hpp"
+#include "esdl_transformer.hpp"
+#include "esdl_store.hpp"
+
+interface IEsdlShare : implements IInterface
+{
+    virtual void add(const char* defId, IEsdlDefinition* defobj) = 0;
+    virtual void remove(const char* defId) = 0;
+    virtual Linked<IEsdlDefinition> lookup(const char* defId) = 0;
+};
+
+interface IEsdlMonitor : implements IInterface
+{
+    virtual void registerBinding(const char* bindingId, IEspRpcBinding* binding) = 0;
+    virtual void subscribe() = 0;
+    virtual void unsubscribe() = 0;
+};
+
+extern "C" esdl_engine_decl void startEsdlMonitor();
+extern "C" esdl_engine_decl void stopEsdlMonitor();
+esdl_engine_decl IEsdlMonitor* queryEsdlMonitor();
+esdl_engine_decl IEsdlShare* queryEsdlShare();
+
+#define ESDL_MONITOR_HPP
+
+#endif //ESDL_MONITOR_HPP

文件差异内容过多而无法显示
+ 427 - 260
esp/services/esdl_svc_engine/esdl_store.cpp


+ 15 - 9
esp/services/esdl_svc_engine/esdl_store.hpp

@@ -25,7 +25,7 @@
 #ifdef ESDL_ENGINE_EXPORTS
  #define esdl_engine_decl DECL_EXPORT
 #else
- #define esdl_engine_decl
+ #define esdl_engine_decl DECL_IMPORT
 #endif
 
 interface IEsdlStore : public IInterface
@@ -33,33 +33,39 @@ interface IEsdlStore : public IInterface
     virtual void fetchDefinition(const char* definitionId, StringBuffer& esxdl) = 0;
     virtual void fetchLatestDefinition(const char* definitionName, StringBuffer& esxdl) = 0;
     virtual IPropertyTree* fetchBinding(const char* espProcess, const char* espStaticBinding) = 0;
+    virtual IPropertyTree* fetchBinding(const char* bindingId) = 0;
     virtual bool definitionExists(const char* definitionId) = 0;
     virtual bool isMethodDefined(const char* definitionId, StringBuffer & esdlServiceName, const char* methodName) = 0;
-    virtual bool addDefinition(IPropertyTree* definitionRegistry, const char* definitionName, IPropertyTree* definitionInfo, StringBuffer &newId, unsigned &newSeq, const char* userid, bool deleteprev, StringBuffer & message) = 0;
+    virtual bool addDefinition(const char* definitionName, IPropertyTree* definitionInfo, StringBuffer &newId, unsigned &newSeq, const char* userid, bool deleteprev, StringBuffer & message) = 0;
+    virtual int configureMethod(const char* bindingId, const char* methodName, IPropertyTree* configTree, bool overwrite, StringBuffer& message) = 0;
     virtual int configureMethod(const char* espProcName, const char* espBindingName, const char* definitionId, const char* methodName, IPropertyTree* configTree, bool overwrite, StringBuffer& message) = 0;
     virtual int bindService(const char* bindingName, IPropertyTree* methodsConfig, const char* espProcName, const char* espPort, const char* definitionId,
                        const char* esdlServiceName, StringBuffer& message, bool overwrite, const char* user) = 0;
     virtual bool deleteDefinition(const char* definitionId, StringBuffer& errmsg, StringBuffer* defxml) = 0;
     virtual bool deleteBinding(const char* bindingId, StringBuffer& errmsg, StringBuffer* bindingxml) = 0;
-    virtual IPropertyTree* getDefinitionRegistry(bool readonly) = 0;
     virtual IPropertyTree* getBindingTree(const char* espProcName, const char* espBindingName, StringBuffer& msg) = 0;
+    virtual IPropertyTree* getBindingTree(const char* bindingId, StringBuffer& msg) = 0;
     virtual IPropertyTree* getDefinitions() = 0;
     virtual IPropertyTree* getBindings() = 0;
 };
 
-enum EsdlNotifyType
+enum class EsdlNotifyType
 {
-    BindingUpdate = 1,
-    BindingDelete = 2,
-    DefinitionUpdate = 3,
+    BindingAdd = 1,
+    BindingUpdate = 2,
+    BindingDelete = 3,
+    DefinitionAdd = 4,
+    DefinitionUpdate = 5,
+    DefinitionDelete = 6
 };
 
 struct EsdlNotifyData
 {
     EsdlNotifyType type;
     StringBuffer id;
-    StringBuffer espBinding;
+    StringBuffer name;
     StringBuffer espProcess;
+    unsigned port;
 };
 
 interface IEsdlListener
@@ -74,6 +80,6 @@ interface IEsdlSubscription : public IInterface
 };
 
 esdl_engine_decl IEsdlStore* createEsdlCentralStore();
-esdl_engine_decl IEsdlSubscription* createEsdlSubscription(IEsdlListener* listener, const char* process, const char* binding);
+esdl_engine_decl IEsdlSubscription* createEsdlSubscription(IEsdlListener* listener);
 
 #endif // _ESDL_STORE_HPP__

+ 369 - 233
esp/services/ws_esdlconfig/ws_esdlconfigservice.cpp

@@ -116,6 +116,49 @@ IPropertyTree * fetchConfigInfo(const char * config,
     return methodstree;
 }
 
+IPropertyTree * fetchConfigInfo(const char * config,
+                                const char* bindingId)
+{
+    IPropertyTree * methodstree = NULL;
+
+    if (!config || !*config)
+    {
+        throw MakeStringException(-1,"Empty config detected");
+    }
+    else
+    {
+        Owned<IPropertyTree>  configTree = createPTreeFromXMLString(config, ipt_caseInsensitive);
+        //Now let's figure out the structure of the configuration passed in...
+
+        StringBuffer rootname;
+        configTree->getName(rootname);
+
+        if (stricmp(rootname.str(), "Binding") == 0)
+        {
+            if(stricmp(bindingId, configTree->queryProp("@id")) != 0)
+                throw MakeStringException(-1, "Binding id in the config tree doesn't match binding id provided");
+        }
+
+        IPropertyTree * deftree = NULL;
+        if (stricmp(rootname.str(), "Definition") == 0)
+            deftree = configTree;
+        else
+            deftree = configTree->queryBranch("Definition[1]");
+
+        if (deftree)
+        {
+            methodstree = deftree->getBranch("Methods");
+        }
+
+        if (!methodstree) //if we didn't already find the methods section of the config, let's look at the root
+        {
+            if (stricmp(rootname.str(), "Methods") == 0)
+                methodstree = configTree.getLink();
+        }
+    }
+    return methodstree;
+}
+
 void CWsESDLConfigEx::init(IPropertyTree *cfg, const char *process, const char *service)
 {
     if(cfg == NULL)
@@ -134,41 +177,10 @@ void CWsESDLConfigEx::init(IPropertyTree *cfg, const char *process, const char *
     if(servicecfg == NULL)
         throw MakeStringException(-1, "config not found for service %s/%s",process, service);
 
+    m_isDetachedFromDali = false;
     m_esdlStore.setown(createEsdlCentralStore());
 }
 
-IPropertyTree * CWsESDLConfigEx::getEspProcessRegistry(const char * espprocname, const char * espbindingport, const char * servicename)
-{
-    if (!espprocname || !*espprocname)
-        return NULL;
-
-    if ((!espbindingport || !*espbindingport) && (!servicename || !*servicename))
-           return NULL;
-
-    VStringBuffer xpath("/Environment/Software/EspProcess[@name='%s']", espprocname);
-    Owned<IRemoteConnection> globalLock = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT_DESDL);
-
-    if (!globalLock || !globalLock->queryRoot())
-        throw MakeStringException(-1, "Unable to connect to ESP configuration information in dali %s", xpath.str());
-
-    globalLock->close(false);
-
-    if (espbindingport && *espbindingport)
-        xpath.appendf("/EspBinding[@port='%s']", espbindingport);
-    else
-        xpath.appendf("/EspBinding[@service='%s']", servicename);
-
-    //Only lock the branch for the target we're interested in.
-    Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_READ , SDS_LOCK_TIMEOUT_DESDL);
-    if (conn)
-    {
-        conn->close(false);
-        return conn->getRoot();
-    }
-
-    return NULL;
-}
-
 bool CWsESDLConfigEx::onPublishESDLDefinition(IEspContext &context, IEspPublishESDLDefinitionRequest & req, IEspPublishESDLDefinitionResponse & resp)
 {
     try
@@ -192,7 +204,7 @@ bool CWsESDLConfigEx::onPublishESDLDefinition(IEspContext &context, IEspPublishE
 
         resp.updateStatus().setCode(0);
 
-        StringAttr service(req.getServiceName());
+        StringBuffer service(req.getServiceName());
 
         const char * inxmldef = req.getXMLDefinition();
         if (!inxmldef || !*inxmldef)
@@ -210,19 +222,36 @@ bool CWsESDLConfigEx::onPublishESDLDefinition(IEspContext &context, IEspPublishE
         fprintf(stderr, "incoming ESDL def: %s", xml.str());
 #endif
 
-        if (service.isEmpty())
+        if (service.length() == 0)
         {
-            if(serviceXMLTree->getCount("EsdlService") == 1)
-                service.set(serviceXMLTree->queryProp("esxdl/EsdlService/@name"));
-            else
-                throw MakeStringException(-1, "Could not publish ESDL definition, name of target esdl service is required if ESDL definition contains multiple services.");
-        }
+            Owned<IPropertyTreeIterator> iter = serviceXMLTree->getElements("esxdl/EsdlService");
+            StringArray servicenames;
+            ForEach (*iter)
+            {
+                IPropertyTree &item = iter->query();
+                StringBuffer lcname(item.queryProp("@name"));
+                servicenames.append(lcname.toLowerCase());
+            }
+            if (servicenames.length() == 0)
+                throw MakeStringException(-1, "Could not publish ESDL definition, the definition doesn't contain any service");
 
-        StringBuffer serviceXpath;
-        serviceXpath.appendf("esxdl/EsdlService[@name=\"%s\"]", service.get());
+            servicenames.sortAscii();
+            for (int i = 0; i < servicenames.length(); i++)
+            {
+                if (i > 0)
+                    service.append("-");
+                service.append(servicenames.item(i));
+            }
+            DBGLOG("Constructed esdl definition name %s", service.str());
+        }
+        else
+        {
+            StringBuffer serviceXpath;
+            serviceXpath.appendf("esxdl/EsdlService[@name=\"%s\"]", service.str());
 
-        if (!serviceXMLTree->hasProp(serviceXpath))
-            throw MakeStringException(-1, "Service \"%s\" definition not found in ESDL provided", service.get());
+            if (!serviceXMLTree->hasProp(serviceXpath))
+                throw MakeStringException(-1, "Service \"%s\" definition not found in ESDL provided", service.str());
+        }
 
         bool deletePrevious = req.getDeletePrevious();
         resp.setDeletePrevious(deletePrevious);
@@ -231,30 +260,16 @@ bool CWsESDLConfigEx::onPublishESDLDefinition(IEspContext &context, IEspPublishE
         unsigned newseq = 0;
         StringBuffer msg;
 
-        {   // We don't need the queryregistry around after the addESDLDefinition.
-            Owned<IPropertyTree> queryRegistry = m_esdlStore->getDefinitionRegistry(false);
-
-            if (queryRegistry != NULL)
-            {
-                if (m_esdlStore->addDefinition(queryRegistry, service.get(), serviceXMLTree.get(), newqueryid, newseq, user, deletePrevious, msg))
-                {
-                    if (newseq)
-                        resp.setEsdlVersion(newseq);
-                 }
-                 else
-                 {
-                     resp.updateStatus().setCode(-1);
-                     resp.updateStatus().setDescription(msg.str());
-                     return false;
-                 }
-            }
-            else
-            {
-                msg.set("Could not publish ESDL Definition, unable to fetch ESDL Definition registry.");
-                resp.updateStatus().setCode(-1);
-                resp.updateStatus().setDescription(msg.str());
-                return false;
-            }
+        if (m_esdlStore->addDefinition(service.str(), serviceXMLTree.get(), newqueryid, newseq, user, deletePrevious, msg))
+        {
+            if (newseq)
+                resp.setEsdlVersion(newseq);
+        }
+        else
+        {
+            resp.updateStatus().setCode(-1);
+            resp.updateStatus().setDescription(msg.str());
+            return false;
         }
 
         msg.appendf("Successfully published %s", newqueryid.str());
@@ -339,7 +354,7 @@ bool CWsESDLConfigEx::onPublishESDLDefinition(IEspContext &context, IEspPublishE
                 }
             }
         }
-        resp.setServiceName(service.get());
+        resp.setServiceName(service.str());
         resp.updateStatus().setDescription(msg.str());
     }
     catch(IException* e)
@@ -373,10 +388,9 @@ bool CWsESDLConfigEx::onPublishESDLBinding(IEspContext &context, IEspPublishESDL
         StringBuffer espProcName(req.getEspProcName());
         StringBuffer espBindingName(req.getEspBindingName());
         StringBuffer espPort(req.getEspPort());
-        StringBuffer espServiceName(req.getEspServiceName());
         StringBuffer esdlDefIdSTR(req.getEsdlDefinitionID());
-
         StringBuffer esdlServiceName(req.getEsdlServiceName());
+
         bool overwrite = req.getOverwrite();
 
         StringBuffer config(req.getConfig());
@@ -419,33 +433,14 @@ bool CWsESDLConfigEx::onPublishESDLBinding(IEspContext &context, IEspPublishESDL
         if (espProcName.length() == 0)
             throw MakeStringException(-1, "Must provide ESP Process name");
 
-        Owned<IPropertyTree> espproctree;
-
-        if (espBindingName.length() == 0)
-        {
-            if (espPort.length() <= 0 && espServiceName.length() <= 0)
-                throw MakeStringException(-1, "Must provide either ESP Port, or Service Name");
-
-            espproctree.setown(getEspProcessRegistry(espProcName.str(), espPort.str(), espServiceName.str()));
-
-            if (!espproctree)
-            {
-                StringBuffer msg;
-                msg.appendf("Could not find ESP binding associated with Esp Process '%s' and either port '%s' or Esp Service Name '%s'",
-                        espProcName.str(), espPort.isEmpty() ? "N/A" : espPort.str(), espServiceName.isEmpty() ? "N/A" : espServiceName.str());
-                resp.updateStatus().setCode(-1);
-                resp.updateStatus().setDescription(msg.str());
-                return false;
-            }
-        }
-
-        StringBuffer bindingName(espproctree != NULL ? espproctree->queryProp("@name") : espBindingName.str());
+        if (espBindingName.length() == 0 && espPort.length() == 0)
+            throw MakeStringException(-1, "Must provide either ESP Port, or Binding Name");
 
         if (m_esdlStore->definitionExists(esdlDefIdSTR.str()))
         {
             if(methodstree)
             {
-                IPropertyTreeIterator * iter = methodstree->getElements("Method");
+                Owned<IPropertyTreeIterator> iter = methodstree->getElements("Method");
                 StringBuffer methodxpath;
                 ForEach(*iter)
                 {
@@ -470,7 +465,7 @@ bool CWsESDLConfigEx::onPublishESDLBinding(IEspContext &context, IEspPublishESDL
             }
 
             StringBuffer msg;
-            resp.updateStatus().setCode(m_esdlStore->bindService(bindingName.str(),
+            resp.updateStatus().setCode(m_esdlStore->bindService(espBindingName.str(),
                                                            methodstree.get(),
                                                            espProcName.str(),
                                                            espPort,
@@ -596,7 +591,7 @@ bool CWsESDLConfigEx::onPublishESDLBinding(IEspContext &context, IEspPublishESDL
         else
         {
             StringBuffer msg;
-            msg.appendf("Could not find ESDL Definition for : '%s'", esdlDefIdSTR.str());
+            msg.appendf("Could not find ESDL Definition for ID : '%s'", esdlDefIdSTR.str());
             resp.updateStatus().setCode(-1);
             resp.updateStatus().setDescription(msg.str());
             return false;
@@ -625,18 +620,43 @@ bool CWsESDLConfigEx::onConfigureESDLBindingMethod(IEspContext &context, IEspCon
         context.getUserID(username);
         DBGLOG("CWsESDLConfigEx::onConfigureESDBindingLMethod User=%s",username.str());
 
-        StringBuffer espProcName(req.getEspProcName());
-        StringBuffer espBindingName(req.getEspBindingName());
-        StringBuffer espPort(req.getEspPort());
-        StringBuffer espServiceName(req.getEsdlServiceName());
-        StringBuffer esdlServiceName(req.getEsdlServiceName());
-        StringBuffer esdlDefIdSTR(req.getEsdlDefinitionID());
+        const char* bindingId = req.getEsdlBindingId();
+        const char* methodName = req.getMethodName();
+        StringBuffer espProcName;
+        StringBuffer espBindingName;
+        StringBuffer espPort;
+        StringBuffer esdlServiceName;
+        StringBuffer espServiceName;
+        StringBuffer esdlDefIdSTR;
         StringBuffer config(req.getConfig());
 
+        double ver = context.getClientVersion();
+        if(ver >= 1.4)
+        {
+            StringBuffer msg;
+            Owned<IPropertyTree> bindingtree = m_esdlStore->getBindingTree(bindingId, msg);
+            if(!bindingtree)
+                throw MakeStringException(-1, "Can't find esdl binding for id %s", bindingId);
+            bindingtree->getProp("@espprocess", espProcName);
+            bindingtree->getProp("@espbinding", espBindingName);
+            bindingtree->getProp("@port", espPort);
+            bindingtree->getProp("Definition[1]/@esdlservice", esdlServiceName);
+            bindingtree->getProp("Definition[1]/@id", esdlDefIdSTR);
+        }
+        else
+        {
+            espProcName.set(req.getEspProcName());
+            espBindingName.set(req.getEspBindingName());
+            espPort.set(req.getEspPort());
+            espServiceName.set(req.getEsdlServiceName());
+            esdlServiceName.set(req.getEsdlServiceName());
+            esdlDefIdSTR.set(req.getEsdlDefinitionID());
+        }
+
         Owned<IPropertyTree> methodstree;
 
         if (config.length() > 0)
-            methodstree.setown(fetchConfigInfo(config, espProcName, espBindingName, esdlDefIdSTR, esdlServiceName));
+            methodstree.setown(fetchConfigInfo(config, bindingId));
         else
         {
             double ver = context.getClientVersion();
@@ -686,44 +706,51 @@ bool CWsESDLConfigEx::onConfigureESDLBindingMethod(IEspContext &context, IEspCon
             if (esdlver <= 0)
                 throw MakeStringException(-1, "Invalid ESDL Definition version detected: %d", esdlver);
         }
+        else if (ver >= 1.4)
+            throw MakeStringException(-1, "Can't find esdl definition for binding %s", bindingId);
 
-        if (esdlServiceName.length() == 0)
-        {
-           if (esdlDefinitionName.length() == 0)
-                throw MakeStringException(-1, "Must provide either valid EsdlDefinition ID <esdldefname>.<ver> or EsdlServiceName");
-            else
-                esdlServiceName.set(esdlDefinitionName.str());
-        }
-
-        if (espProcName.length() == 0)
-            throw MakeStringException(-1, "Must provide ESP Process name");
-
-        Owned<IPropertyTree> espproctree;
-
-        if (espBindingName.length() == 0)
+        if (ver < 1.4)
         {
-            if (espPort.length() <= 0 && espServiceName.length() <= 0)
-                throw MakeStringException(-1, "Must provide either ESP Port, or Service Name");
+            if (esdlServiceName.length() == 0)
+            {
+               if (esdlDefinitionName.length() == 0)
+                    throw MakeStringException(-1, "Must provide either valid EsdlDefinition ID <esdldefname>.<ver> or EsdlServiceName");
+                else
+                    esdlServiceName.set(esdlDefinitionName.str());
+            }
 
-            espproctree.setown(getEspProcessRegistry(espProcName.str(), espPort.str(), espServiceName.str()));
+            if (espProcName.length() == 0)
+                throw MakeStringException(-1, "Must provide ESP Process name");
 
-            if (!espproctree)
+            if (espBindingName.length() == 0)
             {
-                StringBuffer msg;
-                msg.appendf(
-                        "Could not find ESP binding associated with Esp Process '%s' and either port '%s' or Esp Service Name '%s'",
-                        espProcName.str(), espPort.isEmpty() ? "N/A" : espPort.str(), espServiceName.isEmpty() ? "N/A" : espServiceName.str());
-                resp.updateStatus().setCode(-1);
-                resp.updateStatus().setDescription(msg.str());
-                return false;
+                if (espPort.length() <= 0 && espServiceName.length() <= 0)
+                    throw MakeStringException(-1, "Must provide either ESP Port, or Service Name");
+
+                VStringBuffer xpath("/Environment/Software/EspProcess[@name='%s']/EspBinding[@port='%s']", espProcName.str(), espPort.str());
+                Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_READ , SDS_LOCK_TIMEOUT_DESDL);
+                if (!conn)
+                {
+                    StringBuffer msg;
+                    msg.appendf(
+                            "Could not find ESP binding associated with Esp Process '%s' and either port '%s' or Esp Service Name '%s'",
+                            espProcName.str(), espPort.isEmpty() ? "N/A" : espPort.str(), espServiceName.isEmpty() ? "N/A" : espServiceName.str());
+                    resp.updateStatus().setCode(-1);
+                    resp.updateStatus().setDescription(msg.str());
+                    return false;
+                }
+                espBindingName.set(conn->queryRoot()->queryProp("@name"));
             }
         }
 
-        StringBuffer bindingName(espproctree != NULL ? espproctree->queryProp("@name") : espBindingName.str());
-
         if (m_esdlStore->definitionExists(esdlDefIdSTR.str()))
         {
-            IPropertyTreeIterator * iter = methodstree->getElements("Method");
+            StringBuffer methodxpath;
+            if (methodName && *methodName)
+                methodxpath.appendf("Method[@name='%s']", methodName);
+            else
+                methodxpath.append("Method");
+            Owned<IPropertyTreeIterator> iter = methodstree->getElements(methodxpath.str());
             ForEach(*iter)
             {
                 IPropertyTree &item = iter->query();
@@ -743,18 +770,28 @@ bool CWsESDLConfigEx::onConfigureESDLBindingMethod(IEspContext &context, IEspCon
                 else
                 {
                     StringBuffer msg;
-                    success = m_esdlStore->configureMethod(espProcName.str(), espBindingName.str(), esdlDefIdSTR.toLowerCase().str(), methodName, &item, override, msg);
+                    if (ver >= 1.4)
+                        success = m_esdlStore->configureMethod(bindingId, methodName, LINK(&item), override, msg);
+                    else
+                        success = m_esdlStore->configureMethod(espProcName.str(), espBindingName.str(), esdlDefIdSTR.toLowerCase().str(), methodName, LINK(&item), override, msg);
                     resp.updateStatus().setDescription(msg.str());
                     if (success == 0)
                     {
                         double ver = context.getClientVersion();
 
-                        ESPLOG(LogMin, "ESDL Binding '%s.%d' configured method '%s' by user='%s' overwrite flag: %s", esdlDefinitionName.str(), esdlver, username.isEmpty() ? "Anonymous" : username.str(), methodName, override ? "TRUE" : "FALSE");
+                        if (ver >= 1.4)
+                            ESPLOG(LogMin, "ESDL Binding '%s' configured method '%s' by user='%s' overwrite flag: %s", bindingId, username.isEmpty() ? "Anonymous" : username.str(), methodName, override ? "TRUE" : "FALSE");
+                        else
+                            ESPLOG(LogMin, "ESDL Binding '%s.%d' configured method '%s' by user='%s' overwrite flag: %s", esdlDefinitionName.str(), esdlver, username.isEmpty() ? "Anonymous" : username.str(), methodName, override ? "TRUE" : "FALSE");
 
                         if (ver >= 1.2)
                         {
                             StringBuffer msg;
-                            Owned<IPropertyTree> esdlbindingtree = m_esdlStore->getBindingTree(espProcName.str(), espBindingName.str(), msg);
+                            Owned<IPropertyTree> esdlbindingtree;
+                            if (ver >= 1.4)
+                                esdlbindingtree.setown(m_esdlStore->getBindingTree(bindingId, msg));
+                            else
+                                esdlbindingtree.setown(m_esdlStore->getBindingTree(espProcName.str(), espBindingName.str(), msg));
                             if (esdlbindingtree)
                             {
                                 IArrayOf<IEspMethodConfig> iesmethods;
@@ -878,18 +915,18 @@ bool CWsESDLConfigEx::onConfigureESDLBindingMethod(IEspContext &context, IEspCon
     return true;
 }
 
-int CWsESDLConfigEx::getBindingXML(const char * espProcName, const char * espBindingName, StringBuffer & bindingXml, StringBuffer & msg)
+int CWsESDLConfigEx::getBindingXML(const char * bindingId, StringBuffer & bindingXml, StringBuffer & msg)
 {
-    Owned<IPropertyTree> esdlBinding = m_esdlStore->getBindingTree(espProcName, espBindingName, msg);
+    Owned<IPropertyTree> esdlBinding = m_esdlStore->getBindingTree(bindingId, msg);
     if (esdlBinding)
     {
         toXML(esdlBinding, bindingXml, 0,0);
-        msg.setf("Successfully fetched binding for ESP proc: %s, and binding: %s", espProcName, espBindingName);
+        msg.setf("Successfully fetched binding %s", bindingId);
         return 0;
     }
     else
     {
-        msg.setf("Could not fetch binding for ESP proc: %s, and binding: %s", espProcName, espBindingName);
+        msg.setf("Could not fetch binding %s", bindingId);
         return -1;
     }
 }
@@ -907,70 +944,52 @@ bool CWsESDLConfigEx::onGetESDLBinding(IEspContext &context, IEspGetESDLBindingR
         double ver = context.getClientVersion();
         StringBuffer username;
         context.getUserID(username);
-        DBGLOG("CWsESDLConfigEx::onGetESDLServiceConfig User=%s",username.str());
+        DBGLOG("CWsESDLConfigEx::onGetESDLBinding User=%s",username.str());
 
         StringBuffer espProcName(req.getEspProcName());
         StringBuffer espBindingName(req.getEspBindingName());
+
         StringBuffer espProcNameFromId;
         StringBuffer espBindingNameFromId;
-
         const char * esdlBindId = req.getEsdlBindingId();
-        if (esdlBindId && *esdlBindId)
-        {
-            while(esdlBindId && *esdlBindId && *esdlBindId != '.') //RODRIGO: we should have a limit on this...
-            {
-                espProcNameFromId.append(*esdlBindId++);
-            }
 
-            if (espProcNameFromId.length() > 0 && (!esdlBindId || !*esdlBindId || *esdlBindId != '.'))
-                throw MakeStringException(-1, "Invalid ESDL Binding ID format detected. <espprocessname>.<espbindingname>");
-            else
+        if(ver >= 1.4)
+        {
+            if (!(esdlBindId && *esdlBindId))
             {
-                espBindingNameFromId.set(++esdlBindId);
+                throw MakeStringException(-1, "Must provide EsdlBindingId");
             }
         }
-
-        if (espProcName.length() == 0)
-        {
-            if (espProcNameFromId.length() > 0)
-                espProcName.set(espProcNameFromId);
-            else
-                throw MakeStringException(-1, "Must provide ESP Process name");
-        }
-        else if (espProcNameFromId.length() > 0)
-        {
-            if (strcmp(espProcName.str(), espProcNameFromId.str())!=0)
-                throw MakeStringException(-1, "EspProcessName passed in doesn't match EspProcName from EsdlId passed in, which one is correct?");
-        }
-
-        if (espBindingName.length() == 0)
-        {
-            if (espBindingNameFromId.length() > 0)
-                espBindingName.set(espBindingNameFromId);
-        }
-        else if (espBindingNameFromId.length() > 0)
+        else
         {
-            if (strcmp(espBindingName.str(), espBindingNameFromId.str())!=0)
-                throw MakeStringException(-1, "EspBindingName passed in doesn't match EspBindingName from EsdlId passed in, which one is correct?");
+            if (!esdlBindId || !*esdlBindId)
+            {
+                StringBuffer espPort = req.getEspPort();
+                StringBuffer msg;
+                StringBuffer serviceName;
+                if (espProcName.length() == 0 || (espBindingName.length() == 0 && espPort.length() == 0))
+                    throw MakeStringException(-1, "Must provide EsdlBindingId, or EspProcName plus EspBinding or EspPort");
+                if (espBindingName.length() == 0)
+                {
+                    VStringBuffer xpath("/Environment/Software/EspProcess[@name='%s']/EspBinding[@port='%s']", espProcName.str(), espPort.str());
+                    Owned<IRemoteConnection> conn = querySDS().connect(xpath.str(), myProcessSession(), RTM_LOCK_READ , SDS_LOCK_TIMEOUT_DESDL);
+                    if(conn)
+                         espBindingName.set(conn->queryRoot()->queryProp("@name"));
+                    else
+                        throw MakeStringException(-1, "Can't find any esp binding for port %s", espPort.str());
+                }
+            }
         }
 
-        resp.setEspProcName(espProcName);
-        resp.setBindingName(espBindingName);
-
-        StringBuffer espPort = req.getEspPort();
         StringBuffer msg;
-        StringBuffer serviceName;
-
-        if (espBindingName.length() == 0)
-        {
-            IPropertyTree * espproctree = getEspProcessRegistry(espProcName.str(), espPort.str(), serviceName.str());
-            if (espproctree)
-                espBindingName.set(espproctree->queryProp("@name"));
-        }
+        Owned<IPropertyTree> esdlbindingtree;
+        if (esdlBindId && *esdlBindId)
+            esdlbindingtree.setown(m_esdlStore->getBindingTree(esdlBindId, msg));
+        else
+            esdlbindingtree.setown(m_esdlStore->getBindingTree(espProcName.str(), espBindingName.str(), msg));
 
         if (ver >= 1.1)
         {
-            Owned<IPropertyTree> esdlbindingtree = m_esdlStore->getBindingTree(espProcName.str(), espBindingName.str(), msg);
             if (esdlbindingtree)
             {
                 IPropertyTree * def = esdlbindingtree->queryPropTree("Definition[1]");
@@ -1080,7 +1099,7 @@ bool CWsESDLConfigEx::onGetESDLBinding(IEspContext &context, IEspGetESDLBindingR
                 }
                 else
                 {
-                    msg.setf("\nCould not find Definition section in ESDL Binding %s.%s", espProcName.str(), espBindingName.str());
+                    msg.setf("\nCould not find Definition section in ESDL Binding %s", esdlBindId);
                     resp.updateStatus().setCode(-1);
                 }
             }
@@ -1089,12 +1108,31 @@ bool CWsESDLConfigEx::onGetESDLBinding(IEspContext &context, IEspGetESDLBindingR
         }
 
         StringBuffer bindingxml;
-        int bindingxmlcode = getBindingXML(espProcName.str(), espBindingName.str(), bindingxml, msg);
-        if (ver < 1.1)
-            resp.updateStatus().setCode(bindingxmlcode);
+        int retcode;
+        if (esdlbindingtree)
+        {
+            toXML(esdlbindingtree, bindingxml, 0,0);
+            msg.setf("Successfully fetched binding %s", esdlBindId);
+            retcode = 0;
+        }
+        else
+        {
+            msg.setf("Could not fetch binding %s", esdlBindId);
+            retcode = -1;
+        }
 
-        resp.setConfigXML(bindingxml.str());
+        if (ver < 1.1)
+            resp.updateStatus().setCode(retcode);
         resp.updateStatus().setDescription(msg.str());
+        if (bindingxml.length() > 0)
+            resp.setConfigXML(bindingxml.str());
+        if (esdlbindingtree)
+        {
+            resp.setBindingName(esdlbindingtree->queryProp("@espbinding"));
+            resp.setEspProcName(esdlbindingtree->queryProp("@espprocess"));
+            resp.setEspPort(esdlbindingtree->queryProp("@port"));
+            resp.setServiceName(esdlbindingtree->queryProp("Definition/@esdlservice"));
+        }
     }
     catch(IException* e)
     {
@@ -1143,7 +1181,8 @@ bool CWsESDLConfigEx::onDeleteESDLDefinition(IEspContext &context, IEspDeleteESD
         ESPLOG(LogMin, "ESDL Definition '%s' Deleted by user='%s'", esdlDefinitionId.str(), username.isEmpty() ? "Anonymous" : username.str());
         resp.setDeletedTree(thexml.str());
         resp.updateStatus().setCode(0);
-        resp.updateStatus().setDescription("Deleted ESDL Definition");
+        VStringBuffer desc("Deleted ESDL Definition %s", esdlDefinitionId.str());
+        resp.updateStatus().setDescription(desc.str());
     }
     else
     {
@@ -1163,28 +1202,86 @@ bool CWsESDLConfigEx::onDeleteESDLBinding(IEspContext &context, IEspDeleteESDLBi
     if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Full, false))
         throw MakeStringException(ECLWATCH_ROXIE_QUERY_ACCESS_DENIED, "Failed to DELETE ESDL entry. Permission denied.");
 
-    StringBuffer espBindingId(req.getId());
-    if (espBindingId.length()<=0)
+    double ver = context.getClientVersion();
+    StringBuffer esdlBindingId(req.getId());
+    if (esdlBindingId.length()<=0)
     {
-        const char * espprocname = req.getEspProcess();
-        const char * espbindingname = req.getEspBinding();
-        if( !espprocname || !*espprocname ||  !espbindingname || !*espbindingname)
+        if (ver >= 1.4)
         {
-            resp.updateStatus().setDescription("Must provide the target ESDL Binding Id or espprocessname and espbindingname");
+            resp.updateStatus().setDescription("Must provide the target ESDL Binding Id");
             return false;
         }
-        espBindingId.setf("%s.%s", espprocname, espbindingname);
+        else
+        {
+            const char * espprocname = req.getEspProcess();
+            const char * espbindingname = req.getEspBinding();
+            if( !espprocname || !*espprocname ||  !espbindingname || !*espbindingname)
+            {
+                resp.updateStatus().setDescription("Must provide the target ESDL Binding ID, or espprocessname and espbindingname");
+                return false;
+            }
+            Owned<IPropertyTree> esdlBinding = m_esdlStore->fetchBinding(espprocname, espbindingname);
+            if (esdlBinding)
+                esdlBinding->getProp("@id", esdlBindingId);
+            else
+            {
+                resp.updateStatus().setDescription("No esdl binding found for the esp process and binding provided");
+                return false;
+            }
+        }
+    }
+    else
+    {
+        if(ver < 1.4)
+        {
+            Owned<IPropertyTree> esdlBinding = m_esdlStore->fetchBinding(esdlBindingId.str());
+            if (!esdlBinding)
+            {
+                bool isOldFormat = false;
+                int i = 0, j = 0;
+                for (i = 0; i < esdlBindingId.length(); i++)
+                {
+                    if (esdlBindingId.charAt(i) == '.')
+                        break;
+                }
+                if (i < esdlBindingId.length())
+                {
+                    for (j = i+1; j < esdlBindingId.length(); j++)
+                    {
+                        if (esdlBindingId.charAt(j) == '.')
+                            break;
+                    }
+                    if (j == esdlBindingId.length())
+                        isOldFormat = true;
+                }
+                if (isOldFormat)
+                {
+                    StringBuffer proc, binding;
+                    proc.append(i, esdlBindingId.str());
+                    binding.append(j-i-1, esdlBindingId.str()+i+1);
+                    Owned<IPropertyTree> esdlBinding = m_esdlStore->fetchBinding(proc.str(), binding.str());
+                    if (esdlBinding)
+                        esdlBinding->getProp("@id", esdlBindingId.clear());
+                    else
+                    {
+                        resp.updateStatus().setDescription("No esdl binding found for the esp process and binding provided");
+                        return false;
+                    }
+                }
+            }
+        }
     }
 
     StringBuffer errmsg, thexml;
-    bool deleted = m_esdlStore->deleteBinding(espBindingId.str(), errmsg, &thexml);
+    bool deleted = m_esdlStore->deleteBinding(esdlBindingId.str(), errmsg, &thexml);
     if (deleted)
     {
         StringBuffer username;
         context.getUserID(username);
-        ESPLOG(LogMin, "ESDL Definition '%s' Deleted by user='%s'", espBindingId.str(), username.isEmpty() ? "Anonymous" : username.str());
+        ESPLOG(LogMin, "ESDL binding '%s' Deleted by user='%s'", esdlBindingId.str(), username.isEmpty() ? "Anonymous" : username.str());
 
         resp.setDeletedTree(thexml.str());
+        resp.updateStatus().setDescription("Service successfully unbound");
         resp.updateStatus().setCode(0);
     }
     else
@@ -1205,6 +1302,7 @@ bool CWsESDLConfigEx::onGetESDLDefinition(IEspContext &context, IEspGetESDLDefin
 
     StringBuffer id = req.getId();
     StringBuffer definition;
+    const char* serviceName = req.getServiceName();
 
     double ver = context.getClientVersion();
 
@@ -1267,7 +1365,12 @@ bool CWsESDLConfigEx::onGetESDLDefinition(IEspContext &context, IEspGetESDLDefin
                 {
                     try
                     {
-                        Owned<IPropertyTreeIterator> iter = definitionTree->getElements("EsdlService/EsdlMethod");
+                        StringBuffer xpath;
+                        if (serviceName && *serviceName)
+                            xpath.appendf("EsdlService[@name='%s']/EsdlMethod", serviceName);
+                        else
+                            xpath.set("EsdlService/EsdlMethod");
+                        Owned<IPropertyTreeIterator> iter = definitionTree->getElements(xpath.str());
                         IArrayOf<IEspMethodConfig> list;
                         ForEach(*iter)
                         {
@@ -1292,7 +1395,12 @@ bool CWsESDLConfigEx::onGetESDLDefinition(IEspContext &context, IEspGetESDLDefin
                 try
                 {
                     StringArray esdlServices;
-                    Owned<IPropertyTreeIterator> serviceiter = definitionTree->getElements("EsdlService");
+                    StringBuffer xpath;
+                    if (serviceName && *serviceName)
+                        xpath.appendf("EsdlService[@name='%s']", serviceName);
+                    else
+                        xpath.set("EsdlService");
+                    Owned<IPropertyTreeIterator> serviceiter = definitionTree->getElements(xpath.str());
                     ForEach(*serviceiter)
                     {
                         IPropertyTree &item = serviceiter->query();
@@ -1320,23 +1428,12 @@ bool CWsESDLConfigEx::onGetESDLDefinition(IEspContext &context, IEspGetESDLDefin
 
 bool CWsESDLConfigEx::onListESDLDefinitions(IEspContext &context, IEspListESDLDefinitionsRequest&req, IEspListESDLDefinitionsResponse &resp)
 {
-    Owned<IPropertyTree> esdlDefinitions = m_esdlStore->getDefinitions();
-    if(esdlDefinitions.get() == nullptr)
-        return false;
-/*RODRIGO
     if (m_isDetachedFromDali)
         throw MakeStringException(-1, "Cannot list ESDL Definitions. ESP is currently detached from DALI.");
 
-    Owned<IRemoteConnection> conn = querySDS().connect(ESDL_DEFS_ROOT_PATH, myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT_DESDL);
-    if (!conn)
-       throw MakeStringException(-1, "Unable to connect to ESDL Service definition information in dali '%s'", ESDL_DEFS_ROOT_PATH);
-
-    conn->close(false); //release lock right away
-
-    IPropertyTree * esdlDefinitions = conn->queryRoot();
-    if (!esdlDefinitions)
-       throw MakeStringException(-1, "Unable to open ESDL Service definition information in dali '%s'", ESDL_DEFS_ROOT_PATH);
-*/
+    Owned<IPropertyTree> esdlDefinitions = m_esdlStore->getDefinitions();
+    if(esdlDefinitions.get() == nullptr)
+        return false;
     Owned<IPropertyTreeIterator> iter = esdlDefinitions->getElements("Definition");
     IArrayOf<IEspESDLDefinition> list;
     ForEach(*iter)
@@ -1491,40 +1588,79 @@ bool CWsESDLConfigEx::onListDESDLEspBindings(IEspContext &context, IEspListDESDL
     return true;
 }
 
-bool CWsESDLConfigEx::onListESDLBindings(IEspContext &context, IEspListESDLBindingsRequest&req, IEspListESDLBindingsResponse &resp)
+static int bindingCompareFunc(IInterface * const *_itm1, IInterface * const* _itm2)
 {
+    IConstESDLBinding* itm1 = static_cast<IConstESDLBinding*>(*_itm1);
+    IConstESDLBinding* itm2 = static_cast<IConstESDLBinding*>(*_itm2);
+    int cmp1 = strcmp(itm1->getEspProcess(), itm2->getEspProcess());
+    if (cmp1 != 0)
+        return cmp1;
+    if (itm1->getPort() < itm2->getPort())
+        return -1;
+    else if (itm1->getPort() > itm2->getPort())
+        return 1;
+    else
+        return 0;
+}
 
-    Owned<IPropertyTree> esdlBindings = m_esdlStore->getBindings();
-    if(esdlBindings.get() == nullptr)
-        return false;
-/*Rodrigo
+bool CWsESDLConfigEx::onListESDLBindings(IEspContext &context, IEspListESDLBindingsRequest&req, IEspListESDLBindingsResponse &resp)
+{
     if (m_isDetachedFromDali)
         throw MakeStringException(-1, "Cannot list ESDL Bindings. ESP is currently detached from DALI.");
 
-    Owned<IRemoteConnection> conn = querySDS().connect(ESDL_BINDINGS_ROOT_PATH, myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT_DESDL);
-    if (!conn)
-       throw MakeStringException(-1, "Unable to connect to ESDL Service definition information in dali '%s'", ESDL_DEFS_ROOT_PATH);
-
-    conn->close(false); //release lock right away
-
-    IPropertyTree * esdlBindings = conn->queryRoot();
-    if (!esdlBindings)
-       throw MakeStringException(-1, "Unable to open ESDL Service definition information in dali '%s'", ESDL_DEFS_ROOT_PATH);
-
-rodrigo*/
+    Owned<IPropertyTree> esdlBindings = m_esdlStore->getBindings();
+    if (esdlBindings.get() == nullptr)
+        return false;
     Owned<IPropertyTreeIterator> iter = esdlBindings->getElements("Binding");
-
+    double ver = context.getClientVersion();
     IArrayOf<IEspESDLBinding> list;
     ForEach(*iter)
     {
         IPropertyTree &item = iter->query();
         Owned<IEspESDLBinding> esdlbinding = createESDLBinding("","");
         esdlbinding->setId(item.queryProp("@id"));
-        esdlbinding->setEspBinding(item.queryProp("@espbinding"));
         esdlbinding->setEspProcess(item.queryProp("@espprocess"));
+        const char* portstr = item.queryProp("@port");
+        if (portstr && *portstr)
+            esdlbinding->setPort(atoi(portstr));
+        else
+            esdlbinding->setPort(0);
+        esdlbinding->setEspBinding(item.queryProp("@espbinding"));
         list.append(*esdlbinding.getClear());
     }
+    list.sort(bindingCompareFunc);
+    if (ver >= 1.4)
+    {
+        IArrayOf<IConstEspProcessStruct>& processes = resp.getEspProcesses();
+        IConstESDLBinding* lastBinding = nullptr;
+        Owned<IEspEspProcessStruct> currentProcess = nullptr;
+        Owned<IEspEspPortStruct> currentPort = nullptr;
+        for (int i = 0; i < list.length(); i++)
+        {
+            IConstESDLBinding* binding = &list.item(i);
+            bool processCreated = false;
+            if (!lastBinding || (strcmp(lastBinding->getEspProcess(), binding->getEspProcess()) != 0))
+            {
+                currentProcess.setown(createEspProcessStruct());
+                currentProcess->setName(binding->getEspProcess());
+                processes.append(*currentProcess.getLink());
+                processCreated = true;
+            }
+
+            if (processCreated || lastBinding->getPort() != binding->getPort())
+            {
+                IArrayOf<IConstEspPortStruct>& ports = currentProcess->getPorts();
+                currentPort.setown(createEspPortStruct());
+                currentPort->setValue(binding->getPort());
+                ports.append(*currentPort.getLink());
+            }
 
-    resp.setBindings(list);
+            IArrayOf<IConstESDLBinding>& bindings = currentPort->getBindings();
+            bindings.append(*LINK(binding));
+            lastBinding = binding;
+        }
+    }
+    else
+        resp.setBindings(list);
     return true;
 }

+ 1 - 2
esp/services/ws_esdlconfig/ws_esdlconfigservice.hpp

@@ -38,7 +38,7 @@ class CWsESDLConfigEx : public CWsESDLConfig
 private:
     Owned<IEsdlStore> m_esdlStore;
     IPropertyTree * getEspProcessRegistry(const char * espprocname, const char * espbingingport, const char * servicename);
-    int getBindingXML(const char * espProcName, const char * espBindingName, StringBuffer & bindingXml, StringBuffer & msg);
+    int getBindingXML(const char * bindingId, StringBuffer & bindingXml, StringBuffer & msg);
 public:
     IMPLEMENT_IINTERFACE;
     virtual ~CWsESDLConfigEx(){};
@@ -67,7 +67,6 @@ public:
         return true;
     }
 private:
-    //Service will be attached to Dali until told otherwise
     bool m_isDetachedFromDali = false;
 };
 

+ 7 - 0
esp/xslt/nav.xsl

@@ -140,7 +140,14 @@
                         <tr>
                         <td colspan="2">
                             <xsl:text disable-output-escaping="yes">&amp;nbsp;&amp;nbsp;</xsl:text>
+                            <xsl:choose>
+                            <xsl:when test="@isBound=1">
+                            <font size="-2" color="gray">Empty DESDL Service</font>
+                            </xsl:when>
+                            <xsl:otherwise>
                             <font size="-2" color="gray">Unbound DESDL Service</font>
+                            </xsl:otherwise>
+                            </xsl:choose>
                         </td>
                         </tr>
                     </table>

文件差异内容过多而无法显示
+ 2 - 2
initfiles/examples/EsdlExample/ReadMeFirst.txt


+ 85 - 122
tools/esdlcmd/esdl-publish.cpp

@@ -128,8 +128,8 @@ public:
             fprintf(stderr,"\nESDL Definition for service %s could not be loaded from: %s\n", optESDLService.get(), optSource.get());
             return -1;
         }
-
-        request->setServiceName(optESDLService.get());
+        if (optESDLService.length() != 0)
+            request->setServiceName(optESDLService.get());
 
         if (optVerbose)
             fprintf(stdout,"\nESDL Definition: \n%s\n", esxml.str());
@@ -146,7 +146,10 @@ public:
             return 1;
         }
 
-        fprintf(stdout, "\nESDL Service: %s: %s", optESDLService.get(), resp->getStatus().getDescription());
+        if (optESDLService.length() > 0)
+            fprintf(stdout, "\nESDL Service: %s: %s\n", optESDLService.get(), resp->getStatus().getDescription());
+        else
+            fprintf(stdout, "\n%s\n", resp->getStatus().getDescription());
 
         return 0;
     }
@@ -156,7 +159,7 @@ public:
         printf("\nUsage:\n\n"
                 "esdl publish <filename.(ecm|esdl|xml)> <servicename> [command options]\n\n"
                 "   <filename.(ecm|esdl|xml)>   The ESDL file containing service definition in esdl format (.ecm |.esdl) or in esxdl format (.xml) \n"
-                "   <servicename>               The ESDL defined ESP service to publish, optional if ESDL definition contains a single service definition\n"
+                "   <servicename>               The ESDL defined ESP service to publish. Optional.\n"
                 "Options (use option flag followed by appropriate value):\n"
                 "   --overwrite                 Overwrite the latest version of this ESDL Definition\n"
                 ESDLOPT_INCLUDE_PATH_USAGE
@@ -256,6 +259,7 @@ private:
 class EsdlBindServiceCmd : public EsdlPublishCmdCommon
 {
 protected:
+    StringAttr optBindingName;
     StringAttr optPortOrName;
     StringAttr optInput;
 
@@ -265,11 +269,12 @@ public:
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientPublishESDLBindingRequest> request = esdlConfigClient->createPublishESDLBindingRequest();
 
-        fprintf(stdout,"\nAttempting to publish ESDL binding: '%s.%s' \n", optTargetESPProcName.get(), optService.get() ? optService.get() : optTargetPort.get() );
-
+        fprintf(stdout,"\nAttempting to publish ESDL binding on process %s %s %s\n", optTargetESPProcName.get(), optBindingName.length() > 0?"binding":"port", optPortOrName.get());
         request->setEspProcName(optTargetESPProcName);
-        request->setEspPort(optTargetPort);
-        request->setEspServiceName(optService);
+        if (optBindingName.length() > 0)
+            request->setEspBindingName(optBindingName.str());
+        if (optTargetPort.length() > 0)
+            request->setEspPort(optTargetPort);
         request->setEsdlServiceName(optESDLService);
         request->setEsdlDefinitionID(optESDLDefID);
         request->setConfig(optInput);
@@ -294,9 +299,9 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl bind-service <TargetESPProcessName> <TargetESPBindingPort | TargetESPServiceName> <ESDLDefinitionId> (<ESDLServiceName>) [command options]\n\n"
+                "esdl bind-service <TargetESPProcessName> <TargetESPBindingPort | TargetESPBindingName> <ESDLDefinitionId> (<ESDLServiceName>) [command options]\n\n"
                 "   TargetESPProcessName                             The target ESP Process name\n"
-                "   TargetESPBindingPort | TargetESPServiceName      Either target ESP binding port or target ESP service name\n"
+                "   TargetESPBindingPort | TargetESPBindingName      Either target ESP binding port or target ESP binding name\n"
                 "   ESDLDefinitionId                                 The Name and version of the ESDL definition to bind to this service (must already be defined in dali.)\n"
                 "   ESDLServiceName                                  The Name of the ESDL Service (as defined in the ESDL Definition)"
                 "                                                    *Required if ESDL definition contains multiple services\n"
@@ -429,7 +434,7 @@ public:
         else
         {
             const char * portorname =  optPortOrName.get();
-            isdigit(*portorname) ? optTargetPort.set(portorname) : optService.set(portorname);
+            isdigit(*portorname) ? optTargetPort.set(portorname) : optBindingName.set(portorname);
         }
 
         return EsdlPublishCmdCommon::finalizeOptions(globals);
@@ -440,6 +445,7 @@ class EsdlUnBindServiceCmd : public EsdlPublishCmdCommon
 {
 protected:
     StringAttr optEspBinding;
+    StringAttr optBindingId;
 
 public:
     int processCMD()
@@ -447,11 +453,9 @@ public:
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientDeleteESDLBindingRequest> request = esdlConfigClient->createDeleteESDLBindingRequest();
 
-        fprintf(stdout,"\nAttempting to un-bind ESDL Service: '%s.%s'\n", optTargetESPProcName.get(), optEspBinding.get());
+        fprintf(stdout,"\nAttempting to un-bind ESDL Service: '%s'\n", optBindingId.get());
 
-        StringBuffer id;
-        id.setf("%s.%s", optTargetESPProcName.get(), optEspBinding.get());
-        request->setId(id);
+        request->setId(optBindingId);
 
         Owned<IClientDeleteESDLRegistryEntryResponse> resp = esdlConfigClient->DeleteESDLBinding(request);
 
@@ -469,22 +473,20 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl unbind-service <ESPProcessName> <ESPBindingName> [command options]\n\n"
-                "   ESPProcessName      Name of the ESP Process\n"
-                "   ESPBindingName      Name of the ESP binding\n"
+                "esdl unbind-service <EsdlBindingId> [command options]\n\n"
+                "   EsdlBindingId      Id of the esdl binding\n"
                 "\n\nOptions:\n"
               );
 
         EsdlPublishCmdCommon::usage();
 
         printf( "\n   Use this command to unbind ESDL service based bindings.\n"
-                "   To unbind a given ESDL binding, provide the ESP process name and the ESP binding"
-                "   which make up this ESDL binding.\n"
+                "   To unbind a given ESDL binding, provide the esdl binding id\n"
                 "   Available ESDL bindings to unbind can be found via the '>esdl list-bindings' command."
                 );
 
         printf("\nExample:"
-                ">esdl unbind-service myesp myservice_binding \n"
+                ">esdl unbind-service myesp.8003.EsdlExample \n"
                 );
     }
 
@@ -496,7 +498,7 @@ public:
             return false;
         }
 
-        for (int cur = 0; cur < 2 && !iter.done(); cur++)
+        for (int cur = 0; cur < 1 && !iter.done(); cur++)
         {
            const char *arg = iter.query();
            if (*arg != '-')
@@ -504,10 +506,7 @@ public:
                switch (cur)
                {
                 case 0:
-                    optTargetESPProcName.set(arg);
-                    break;
-                case 1:
-                    optEspBinding.set(arg);
+                    optBindingId.set(arg);
                     break;
                }
            }
@@ -544,11 +543,8 @@ public:
     bool finalizeOptions(IProperties *globals)
     {
 
-        if (optTargetESPProcName.isEmpty())
-            throw MakeStringException( 0, "Name of Target ESP process must be provided!" );
-
-        if (optEspBinding.isEmpty())
-            throw MakeStringException( 0, "Target ESP Binding must be provided!" );
+        if (optBindingId.isEmpty())
+            throw MakeStringException( 0, "Esdl binding id must be provided!" );
 
         return EsdlPublishCmdCommon::finalizeOptions(globals);
     }
@@ -742,17 +738,30 @@ public:
             return 1;
         }
 
-        IArrayOf<IConstESDLBinding> & binds = resp->getBindings();
-
-        if (binds.length() > 0)
-            fprintf(stdout, "\nESDL Bindings found:\n");
-
-        ForEachItemIn(bindindex, binds)
+        bool found = false;
+        IArrayOf<IConstEspProcessStruct> & processes = resp->getEspProcesses();
+        ForEachItemIn(procInd, processes)
         {
-            IConstESDLBinding & bind = binds.item(bindindex);
-            fprintf(stdout, "\t%s \n", bind.getId());
+            IConstEspProcessStruct& process = processes.item(procInd);
+            IArrayOf<IConstEspPortStruct>& ports = process.getPorts();
+            ForEachItemIn(portInd, ports)
+            {
+                IConstEspPortStruct& port = ports.item(portInd);
+                IArrayOf<IConstESDLBinding>& bindings = port.getBindings();
+                ForEachItemIn(bindInd, bindings)
+                {
+                    IConstESDLBinding& binding = bindings.item(bindInd);
+                    if (!found)
+                    {
+                        found = true;
+                        fprintf(stdout, "\nESDL bindings found:\n");
+                    }
+                    fprintf(stdout, "\t%s\n", binding.getId());
+                }
+            }
         }
-
+        if (!found)
+            fprintf(stdout, "\nNo ESDL binding found.\n");
         return 0;
     }
 
@@ -797,7 +806,7 @@ class EsdlBindMethodCmd : public EsdlBindServiceCmd
 {
 protected:
     StringAttr optMethod;
-    StringAttr optBindingName;
+    StringAttr optBindingId;
 
 public:
     int processCMD()
@@ -805,11 +814,9 @@ public:
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientConfigureESDLBindingMethodRequest> request = esdlConfigClient->createConfigureESDLBindingMethodRequest();
 
-        fprintf(stdout,"\nAttempting to configure Method : '%s'.'%s'\n", optService.get(), optMethod.get());
-        request->setEspProcName(optTargetESPProcName);
-        request->setEspBindingName(optBindingName);
-        request->setEsdlServiceName(optService.get());
-        request->setEsdlDefinitionID(optESDLDefID.get());
+        fprintf(stdout,"\nAttempting to configure Method : '%s' for binding '%s'\n", optMethod.get(), optBindingId.get());
+        request->setEsdlBindingId(optBindingId.get());
+        request->setMethodName(optMethod.get());
         request->setConfig(optInput);
         request->setOverwrite(optOverWrite);
 
@@ -832,11 +839,8 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl bind-method <TargetESPProcessName> <TargetESPBindingName> <TargetServiceName> <TargetESDLDefinitionID> <TargetMethodName> [command options]\n\n"
-                "   TargetESPProcessName                             The target ESP Process name\n"
-                "   TargetESPBindingName                             The target ESP binding name associated with this service\n"
-                "   TargetServiceName                                The name of the Service to bind (must already be defined in dali.)\n"
-                "   TargetESDLDefinitionID                           The id of the target ESDL definition (must exist in dali)\n"
+                "esdl bind-method <TargetESDLBindingID> <TargetMethodName> [command options]\n\n"
+                "   TargetESDLBindingID                              The id of the target ESDL binding (must exist in dali)\n"
                 "   TargetMethodName                                 The name of the target method (must exist in the service ESDL definition)\n"
 
                 "\nOptions (use option flag followed by appropriate value):\n"
@@ -846,10 +850,7 @@ public:
                 EsdlPublishCmdCommon::usage();
 
         printf( "\n Use this command to publish ESDL Service based bindings.\n"
-                "   To bind a ESDL Service, provide the target ESP process name\n"
-                "   (esp which will host the service.) \n"
-                "   It is also necessary to provide the target ESP binding name,\n"
-                "   and the name of the service you are binding.\n"
+                "   To bind a ESDL Service, provide the id of the esdl binding and the method name you're going to configure.\n"
                 "   Optionally provide configuration information either directly, or via a\n"
                 "   configuration file in the following syntax:\n"
                 "     <Methods>\n"
@@ -859,7 +860,7 @@ public:
                 );
 
         printf("\nExample:"
-                ">esdl bind-method myesp mybinding WsMyService WsMyService.1 myMethod --config /myService/methods.xml\n"
+                ">esdl bind-method myesp.8003.EsdlExample myMethod --config /myService/methods.xml\n"
                 );
     }
 
@@ -872,7 +873,7 @@ public:
         }
 
         //First 5 parameter order is fixed.
-        for (int cur = 0; cur < 5 && !iter.done(); cur++)
+        for (int cur = 0; cur < 2 && !iter.done(); cur++)
         {
            const char *arg = iter.query();
            if (*arg != '-')
@@ -880,18 +881,9 @@ public:
                switch (cur)
                {
                 case 0:
-                    optTargetESPProcName.set(arg);
+                    optBindingId.set(arg);
                     break;
                 case 1:
-                    optBindingName.set(arg);
-                    break;
-                case 2:
-                    optService.set(arg);
-                    break;
-                case 3:
-                    optESDLDefID.set(arg);
-                    break;
-                case 4:
                     optMethod.set(arg);
                     break;
                }
@@ -932,21 +924,12 @@ public:
             }
         }
 
-        if(optTargetESPProcName.isEmpty())
-            throw MakeStringException( 0, "Name of Target ESP process must be provided" );
-
-        if (optService.isEmpty())
-            throw MakeStringException( 0, "Name of ESDL based service must be provided" );
-
-        if (optESDLDefID.isEmpty())
-            throw MakeStringException( 0, "ESDLDefinitionID must be provided!" );
+        if (optBindingId.isEmpty())
+            throw MakeStringException( 0, "ESDLBindingID must be provided!" );
 
         if (optMethod.isEmpty())
             throw MakeStringException( 0, "Name of ESDL based method must be provided" );
 
-        if (optBindingName.isEmpty())
-            throw MakeStringException( 0, "Name of ESP binding must be provided" );
-
         return EsdlPublishCmdCommon::finalizeOptions(globals);
     }
 };
@@ -959,11 +942,9 @@ public:
         int success = -1;
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientGetESDLBindingRequest> getrequest = esdlConfigClient->createGetESDLBindingRequest();
-        VStringBuffer bindingid("%s.%s", optTargetESPProcName.get(), optBindingName.get());
-
         if (optVerbose)
-            fprintf(stdout,"\nFetching current ESDL binging configuration for (%s)\n", bindingid.str());
-        getrequest->setEsdlBindingId(bindingid.str());
+            fprintf(stdout,"\nFetching current ESDL binging configuration for (%s)\n", optBindingId.get());
+        getrequest->setEsdlBindingId(optBindingId.get());
 
         Owned<IClientGetESDLBindingResponse> getresp = esdlConfigClient->GetESDLBinding(getrequest);
 
@@ -975,7 +956,7 @@ public:
 
         if (getresp->getStatus().getCode()!=0)
         {
-            fprintf(stdout, "\n Failed to retrieve '%s' ESDL Binding configuration: %s.\n", optMethod.get(), getresp->getStatus().getDescription());
+            fprintf(stdout, "\n Failed to retrieve ESDL Binding configuration for %s: %s.\n", optBindingId.get(), getresp->getStatus().getDescription());
             return success;
         }
 
@@ -997,8 +978,12 @@ public:
                         Owned<IClientPublishESDLBindingRequest> request = esdlConfigClient->createPublishESDLBindingRequest();
 
                         if (optVerbose)
-                            fprintf(stdout,"\nAttempting to publish ESDL Binding %s sans Method '%s'\n", bindingid.str(), optMethod.get());
+                            fprintf(stdout,"\nAttempting to remove method '%s' from esdl binding '%s'\n", optMethod.get(), optBindingId.get());
 
+                        request->setEsdlDefinitionID(getresp->getESDLBinding().getDefinition().getId());
+                        request->setEsdlServiceName(getresp->getServiceName());
+                        request->setEspProcName(getresp->getEspProcName());
+                        request->setEspPort(getresp->getEspPort());
                         request->setConfig(newconfig.str());
                         request->setOverwrite(true);
 
@@ -1012,23 +997,23 @@ public:
 
                         if (resp->getStatus().getCode() == 0)
                         {
-                            fprintf(stdout, "\nSuccessfully unbound method %s from ESDL Binding %s.", optMethod.get(), bindingid.str());
+                            fprintf(stdout, "\nSuccessfully unbound method %s from ESDL Binding %s.\n", optMethod.get(), optBindingId.get());
                             success = 0;
                         }
                         else
-                            fprintf(stdout, "\nCould not unbound method %s from ESDL Binding %s: %s", optMethod.get(), bindingid.str(), resp->getStatus().getDescription());
+                            fprintf(stdout, "\nCould not unbound method %s from ESDL Binding %s: %s\n", optMethod.get(), optBindingId.get(), resp->getStatus().getDescription());
                     }
                     else
-                        fprintf(stdout, "\n Could not remove Method %s from ESDL Binding %s.configuration.\n", optMethod.get(), bindingid.str());
+                        fprintf(stdout, "\n Could not remove Method %s from ESDL Binding %s configuration.\n", optMethod.get(), optBindingId.get());
                 }
                 else
-                    fprintf(stdout, "\n Method %s doesn't seem to be associated with ESDL Binding %s.\n", optMethod.get(), bindingid.str());
+                    fprintf(stdout, "\n Method %s doesn't seem to be associated with ESDL Binding %s.\n", optMethod.get(), optBindingId.get());
             }
             else
-                fprintf(stdout, "\n Could not interpret configuration for ESDL Binding %s :  %s.\n", bindingid.str(), currentconfig );
+                fprintf(stdout, "\n Could not interpret configuration for ESDL Binding %s :  %s.\n", optBindingId.get(), currentconfig );
         }
         else
-            fprintf(stdout, "\n Received empty configuration for ESDL Binding %s.\n", bindingid.str());
+            fprintf(stdout, "\n Received empty configuration for ESDL Binding %s.\n", optBindingId.get());
 
         return success;
     }
@@ -1036,22 +1021,17 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl unbind-method <ESPProcessName> <ESPBindingName> <ESDLServiceName> <MethodName> [\n\n"
-                "   ESPProcessName                             The target ESP Process name\n"
-                "   ESPBindingName                             The target ESP binding name associated with this service\n"
-                "   ESDLServiceName                            The name of the ESDLService name associated with the target method\n"
+                "esdl unbind-method <ESDLBindingID> <MethodName> [\n\n"
+                "   ESDLBindingID                              The id of the esdl binding associated with the target method\n"
                 "   MethodName                                 The name of the target method (must exist in the service ESDL definition)\n");
 
                 EsdlPublishCmdCommon::usage();
 
         printf( "\n   Use this command to unbind a method configuration currently associated with a given ESDL binding.\n"
-                "   To unbind a method, provide the target ESP process name (ESP which hosts the service.) \n"
-                "   It is also necessary to provide the ESP binding on which this service is configured to run,\n"
-                "   The name of the ESDL service and the name of the method you are unbinding.\n");
-
+                "   To unbind a method, provide the target esdl binding id and the name of the method to unbind\n");
 
         printf("\nExample:"
-                ">esdl unbind-method myesp myespbinding WsMyService mymethod\n"
+                ">esdl unbind-method myesp.8003.WsMyService mymethod\n"
                 );
     }
     bool parseCommandLineOptions(ArgvIterator &iter)
@@ -1063,7 +1043,7 @@ public:
         }
 
         //First 4 parameter order is fixed.
-        for (int cur = 0; cur < 4 && !iter.done(); cur++)
+        for (int cur = 0; cur < 2 && !iter.done(); cur++)
         {
            const char *arg = iter.query();
            if (*arg != '-')
@@ -1071,15 +1051,9 @@ public:
                switch (cur)
                {
                 case 0:
-                    optTargetESPProcName.set(arg);
+                    optBindingId.set(arg);
                     break;
                 case 1:
-                    optBindingName.set(arg);
-                    break;
-                case 2:
-                    optService.set(arg);
-                    break;
-                case 3:
                     optMethod.set(arg);
                     break;
                }
@@ -1108,18 +1082,12 @@ public:
 
     bool finalizeOptions(IProperties *globals)
     {
-        if(optTargetESPProcName.isEmpty())
-            throw MakeStringException( 0, "Name of Target ESP process must be provided" );
-
-        if (optService.isEmpty())
-            throw MakeStringException( 0, "Name of ESDL based service must be provided" );
+        if(optBindingId.isEmpty())
+            throw MakeStringException( 0, "Name of Target ESDL Binding must be provided" );
 
         if (optMethod.isEmpty())
             throw MakeStringException( 0, "Name of ESDL based method must be provided" );
 
-        if (optBindingName.isEmpty())
-            throw MakeStringException( 0, "Name of ESP binding must be provided" );
-
         return EsdlPublishCmdCommon::finalizeOptions(globals);
     }
 };
@@ -1267,16 +1235,11 @@ public:
         printf( "\nUsage:\n\n"
                 "esdl get-binding <ESDLBindingId> [command options]\n\n"
                 "Options (use option flag followed by appropriate value):\n"
-                "   ESDLBindingId                             The target ESDL binding id <espprocessname>.<espbindingname>\n"
+                "   ESDLBindingId            The target ESDL binding id\n"
                );
 
                 EsdlPublishCmdCommon::usage();
 
-        printf( "\n\n Use this command to get DESDL Service based bindings.\n"
-                " To specify the target DESDL based service configuration, provide the target ESP process \n"
-                " (esp process name or machine IP Address) which hosts the service.\n"
-                " It is also necessary to provide the Port on which this service is configured to run,\n"
-                " and the name of the service.\n"
-                );
+        printf( "\n\n Use this command to get DESDL Service based bindings.\n");
     }
 };

+ 5 - 2
tools/esdlcmd/esdlcmd_common.hpp

@@ -192,7 +192,10 @@ public:
 
             if( deps )
             {
-                xmlOut.appendf( "<esxdl name=\"%s\">", serviceName);
+                if (serviceName)
+                    xmlOut.appendf("<esxdl name=\"%s\">", serviceName);
+                else
+                    xmlOut.appendf("<esxdl>");
                 defHelper->toXML( *deps, xmlOut, version, opts, flags );
                 xmlOut.append("</esxdl>");
             }
@@ -231,7 +234,7 @@ public:
         if(server == NULL)
             throw MakeStringException(-1, "Server url not specified");
 
-        VStringBuffer url("http://%s:%s/WsESDLConfig", server, port);
+        VStringBuffer url("http://%s:%s/WsESDLConfig/?ver_=%s", server, port, VERSION_FOR_ESDLCMD);
 
         IClientWsESDLConfig * esdlConfigClient = createWsESDLConfigClient();
         esdlConfigClient->addServiceUrl(url.str());