Browse Source

Fixed gh-2057. Configmgr reload if environment file changes

Monitor the file system to detect any changes to the
environment file.  Trigger a reload upon change.

Signed-off-by: Gleb Aronsky <gleb.aronsky@lexisnexis.com>
Gleb Aronsky 13 years ago
parent
commit
96c2cdb6a4

+ 14 - 4
esp/files/scripts/configmgr/navtree.js

@@ -317,14 +317,18 @@ function keepAlive() {
         resetHiddenVars();
         document.forms['treeForm'].mode.value = prevmode;
       }
-      else if (form.saveInProgress.value !== "true" && (RefreshClient1[0] === 'true' || (LastSaved1[0].charAt(0) != '<' && form.lastSaved.value.length && (form.lastSaved.value != LastSaved1[0])))) {
+      else if ( document.getElementById('ReadWrite').checked == false &&
+                form.saveInProgress.value !== "true" &&
+                (RefreshClient1[0] === 'true' || (LastSaved1[0].charAt(0) != '<' && form.lastSaved.value.length && (form.lastSaved.value != LastSaved1[0]))))
+      {
         if (document.forms['treeForm'].mode.value === '2')
           msg = "Environment has been updated by another user. Press Ok to reload the Environment.";
         form.lastSaved.value = LastSaved1[0];
       }
-
-      if (msg.length > 0)
+      if (msg.length > 0  && form.isChanged.value === "false")
+      {
         refresh(msg);
+      }
     },
     failure: function(o) {
     },
@@ -1597,9 +1601,13 @@ function unlockEnvironment(navtable, saveEnv) {
             var form = document.forms['treeForm'];
             var LastSaved = o.responseText.split(/<LastSaved>/g);
             var LastSaved1 = LastSaved[1].split(/<\/LastSaved>/g);
+            var Refresh = "false";
 
             if (LastSaved1[0].charAt(0) != '<' && form.lastSaved.value !== LastSaved1[0])
+            {
+              Refresh = "true";
               form.lastSaved.value = LastSaved1[0];
+            }
 
             Dom.removeClass(navtable.getTrEl(0), 'envlocked');
             form.isLocked.value = "false";
@@ -1607,8 +1615,10 @@ function unlockEnvironment(navtable, saveEnv) {
             form.isChanged.value = "false";
             updateEnvCtrls(false);
 
-            if (saveEnv || changed === "true")
+            if (saveEnv || changed === "true" || Refresh === "true")
+            {
               refresh();
+            }
           }
         }
         else if (o.responseText.indexOf("<html") === 0) {

+ 44 - 3
esp/services/WsDeploy/WsDeployService.cpp

@@ -274,7 +274,7 @@ IPropertyTree* CWsDeployFileInfo::getEnvTree(IEspContext &context, IConstWsDeplo
   
   context.getPeer(sbUserIp);
 
-  if (m_userWithLock.length() && !strcmp(sbName.str(), m_userWithLock.str()) && !strcmp(sbUserIp.str(), m_userIp.str()))
+  if (m_userWithLock.length() && !strcmp(sbName.str(), m_userWithLock.str()) && !strcmp(sbUserIp.str(), m_userIp.str()) &&  m_Environment != NULL)
     return &m_Environment->getPTree();
   else
     return &m_constEnvRdOnly->getPTree();
@@ -2824,6 +2824,12 @@ bool CWsDeployFileInfo::clientAlive(IEspContext &context, IEspClientAliveRequest
   StringBuffer sb(sbName);
   sb.append(sbUserIp);
 
+  if (getConfigChanged() == true)
+  {
+    updateConfigFromFile();
+    setConfigChanged(false);
+  }
+
   if (!strcmp(sbName.str(), m_userWithLock.str()) && !strcmp(sbUserIp.str(), m_userIp.str()))
   {
     CClientAliveThread* pClientAliveThread = m_keepAliveHTable.getValue(sb.str());
@@ -5244,6 +5250,31 @@ const char* CWsDeployFileInfo::GetDisplayProcessName(const char* processName, ch
   }
 }
 
+void CWsDeployFileInfo::updateConfigFromFile()
+{
+  StringBuffer sbxml;
+
+  if (m_pFileIO.get() != NULL)
+  {
+    m_pFileIO.clear();
+  }
+  if (m_lastSaved.isNull())
+  {
+    m_lastSaved.setNow();
+  }
+
+  m_pFileIO.setown(m_pFile->open(IFOread));
+  Owned <IPropertyTree> pTree = createPTree(*m_pFileIO);
+  toXML(pTree, sbxml.clear());
+
+  Owned<IEnvironmentFactory> factory = getEnvironmentFactory();
+
+  m_constEnvRdOnly.clear();
+  m_constEnvRdOnly.setown(factory->loadLocalEnvironment(sbxml.str()));
+  m_lastSaved.clear();
+  m_lastSaved.setNow();
+}
+
 bool CWsDeployFileInfo::deploy(IEspContext &context, IEspDeployRequest& req, IEspDeployResponse& resp)
 {
   synchronized block(m_mutex);
@@ -5465,6 +5496,7 @@ void CWsDeployFileInfo::saveEnvironment(IEspContext* pContext, IConstWsDeployReq
           else
           {
             Owned<IFile> pFile(createIFile(sb.str()));
+            m_configFileMonitorThread.clear();
             copyFile(pFile, m_pFile, 0x100000);
             break;
           }
@@ -5557,6 +5589,12 @@ void CWsDeployFileInfo::saveEnvironment(IEspContext* pContext, IConstWsDeployReq
       throw MakeStringException(0, "%s", sMsg.str());
     }
   }
+
+  if (m_configFileMonitorThread.get() == NULL)
+  {
+    m_configFileMonitorThread.setown(new CWsDeployFileInfo::CConfigFileMonitorThread(this, CONFIG_MONITOR_CHECK_INTERVAL, CONFIG_MONITOR_TIMEOUT_PERIOD));
+    m_configFileMonitorThread->init();
+  }
 }
 
 void CWsDeployFileInfo::unlockEnvironment(IEspContext* context, IConstWsDeployReqInfo *reqInfo, const char* xmlArg, StringBuffer& sbErrMsg, bool saveEnv)
@@ -6046,9 +6084,9 @@ void CWsDeployFileInfo::initFileInfo(bool createOrOverwrite)
 
   if (!fileExists)
     toXML(pEnvRoot, sbxml.clear());
-  
+
   m_Environment.clear();
-  
+
   if (m_constEnvRdOnly.get() == NULL)
   {
     if (fileExists)
@@ -6547,6 +6585,9 @@ CWsDeployFileInfo* CWsDeployExCE::getFileInfo(const char* fileName, bool addIfNo
       try
       {
         fi->initFileInfo(createFile);
+        fi->m_configFileMonitorThread.clear();
+        fi->m_configFileMonitorThread.setown(new CWsDeployFileInfo::CConfigFileMonitorThread(fi, CONFIG_MONITOR_CHECK_INTERVAL, CONFIG_MONITOR_TIMEOUT_PERIOD));
+        fi->m_configFileMonitorThread->init();
       }
       catch (IException* e)
       {

+ 86 - 0
esp/services/WsDeploy/WsDeployService.hpp

@@ -29,6 +29,8 @@
 #include "XMLTags.h"
 #include "httpclient.hpp"
 
+class CDirectoryDifferenceIterator;
+
 typedef enum EnvAction_
 {
     CLOUD_NONE,
@@ -41,6 +43,8 @@ typedef enum EnvAction_
 } EnvAction;
 
 #define CLOUD_SOAPCALL_TIMEOUT 10000
+#define CONFIG_MONITOR_CHECK_INTERVAL  1000
+#define CONFIG_MONITOR_TIMEOUT_PERIOD  6000
 
 class CCloudTask;
 class CCloudActionHandler;
@@ -131,6 +135,75 @@ private:
         Linked<IConstEnvironment> m_constEnv;
     };
 
+  public:
+    class CConfigFileMonitorThread
+      : public CInterface, implements IThreaded, implements IInterface
+    {
+    public:
+      CConfigFileMonitorThread(CWsDeployFileInfo* pFileInfo, unsigned int uCheckInterval, unsigned int uTimeout)
+        : m_pWorkerThread(NULL), m_pFileInfo(pFileInfo), m_quitThread(false), m_uCheckInterval(uCheckInterval), m_uTimeout(uTimeout)
+      {
+      };
+
+      virtual ~CConfigFileMonitorThread()
+      {
+        m_quitThread = true;
+        m_pWorkerThread->join();
+        delete m_pWorkerThread;
+      };
+
+      IMPLEMENT_IINTERFACE;
+
+      virtual void main()
+      {
+        StringBuffer strDrive, strPath, strTail, strExt, strFileName;
+
+        while(m_quitThread == false)
+        {
+          if (m_pFileInfo != NULL && m_pFileInfo->m_pFile != NULL)
+          {
+            splitFilename( m_pFileInfo->m_pFile->queryFilename(), &strDrive, &strPath, &strTail, &strExt);
+            strFileName.clear().appendf("%s%s",strTail.toCharArray(),strExt.toCharArray());
+
+            Owned<IFile> configFiles = createIFile(strPath);
+
+            while ( m_quitThread == false )
+            {
+              IDirectoryDifferenceIterator* diffIter = configFiles->monitorDirectory(NULL, strFileName, false, true, m_uCheckInterval, m_uTimeout);
+
+              if (diffIter != NULL && m_pFileInfo != NULL)
+              {
+                m_pFileInfo->setConfigChanged(true);
+              }
+            }
+          }
+         Sleep(0);
+        }
+      };
+
+      void init()
+      {
+        if ( m_pWorkerThread == NULL)
+        {
+          m_pWorkerThread = new CThreaded("CConfigFileMonitorThread");
+          IThreaded* pIThreaded = this;
+          m_pWorkerThread->init(pIThreaded);
+        }
+      };
+
+    protected:
+      CThreaded* m_pWorkerThread;
+      CWsDeployFileInfo* m_pFileInfo;
+
+      bool m_quitThread;
+      unsigned int m_uTimeout;
+      unsigned int m_uCheckInterval;
+
+    private:
+      CConfigFileMonitorThread() {};
+      CConfigFileMonitorThread(const CConfigFileMonitorThread& configFileThread) {};
+    };
+
     class CClientAliveThread : public CInterface, implements IThreaded, implements IInterface
     {
     public:
@@ -254,6 +327,15 @@ public:
     }
     ~CWsDeployFileInfo();
      void initFileInfo(bool createFile);
+    virtual void setConfigChanged(bool b)
+    {
+      m_configChanged = b;
+    };
+    virtual bool getConfigChanged() const
+    {
+      return m_configChanged;
+    };
+    virtual void updateConfigFromFile();
     virtual bool deploy(IEspContext &context, IEspDeployRequest &req, IEspDeployResponse &resp);
     virtual bool graph(IEspContext &context, IEspEmptyRequest& req, IEspGraphResponse& resp);
     virtual bool navMenuEvent(IEspContext &context, IEspNavMenuEventRequest &req, 
@@ -347,8 +429,12 @@ private:
     StringBuffer              m_cloudEnvId;
     short                     m_daliServerPort;
     Owned<CGenerateJSFactoryThread> m_pGenJSFactoryThread;
+public:
+    Owned<CConfigFileMonitorThread> m_configFileMonitorThread;
+private:
     bool                      m_skipEnvUpdateFromNotification;
     bool                      m_activeUserNotResp;
+    bool                      m_configChanged;
     bool                      m_bCloud;
     Owned<IFile>              m_pFile;
     Owned<IFileIO>            m_pFileIO;