소스 검색

Merge branch 'candidate-6.4.2'

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 7 년 전
부모
커밋
2eb6e34dab

+ 16 - 6
clienttools/IDEPlugins/ESDL/esdl.bat.in

@@ -60,8 +60,8 @@ for /f "tokens=1,2,3 delims=/:" %%a in ("%8") do set http=%%a&set server=%%b&set
 echo.server: %server% >> %TMP%\log.txt
 echo.port  : %port% >> %TMP%\log.txt
 
-echo "%clienttoolsbindir%\esdl.exe publish %newinput% %2 --server %server%  --port %port% --version 1.0 --username %6 --password %9 -v" >>%TMP%\log.txt
-"%clienttoolsbindir%"\esdl.exe publish %newinput% %2 --server %server%  --port %port% --version 1.0 --username %6 --password %9 -v 2>%5 >>%TMP%\log.txt
+echo "%clienttoolsbindir%\esdl.exe publish %newinput% %2 --server %server% --port %port% --username %6 --password %9 -v" >>%TMP%\log.txt
+"%clienttoolsbindir%"\esdl.exe publish %newinput% %2 --server %server% --port %port% --username %6 --password %9 -v 2>%5 >>%TMP%\log.txt
 goto end
 
 :genecl
@@ -71,19 +71,29 @@ goto end
 
 :end
 
+find /i "syntax error" "%TMP%\log.txt" >>%5
+if %errorlevel%==0 goto nomod
+
 rem =====================================
 rem  MAKE FILE INTO MOD FILE FORMAT
 rem =====================================
-set "newoutputUnique=%2Gen"
-echo //IMPORT:%1.%newoutputUnique% >> %TMP%\modfile.tmp
+echo //IMPORT:%1.%2 >> %TMP%\modfile.tmp
 type %newoutput% >> %TMP%\modfile.tmp
 del %newoutput%
 copy /Y %TMP%\modfile.tmp %newoutput%
 del %TMP%\modfile.tmp
 
 copy /Y %3 %TMP%\in.txt
-copy /Y %newoutput% %TMP%\%newoutputUnique%.ecl
-copy /Y %TMP%\%newoutputUnique%.ecl %4
+copy /Y %newoutput% %TMP%\%2.ecl
+copy /Y %TMP%\%2.ecl %4
+copy /Y %4 %TMP%\out.txt
+del %newoutput%
+copy /Y %5 %TMP%\err.txt
+goto eof
+
+:nomod
+
+copy /Y %3 %TMP%\in.txt
 copy /Y %4 %TMP%\out.txt
 del %newoutput%
 copy /Y %5 %TMP%\err.txt

+ 1 - 1
cmake_modules/FindEXAMPLE_PLUGIN_DEP.cmake

@@ -46,7 +46,7 @@ IF (NOT EXAMPLE_PLUGIN_DEP_FOUND)
   #"#define EXAMPLE_PLUGIN_DEP_PATCH 2"
   #The minimum version to requirement is made visible to this cmake file from
   #HPCC/plugins/exampleplugin/CMakeLists.txt:ADD_PLUGIN(EXAMPLEPLUGIN PACKAGES EXAMPLE_PLUGIN_DEP MINVERSION 4.6.2)
-  IF  (EXAMPLE_PLUGIN_DEP_INCLUDE_DIR)
+  IF  (EXISTS "${EXAMPLE_PLUGIN_DEP_INCLUDE_DIR}/hpcc-example-plugin-deps.h")
     #MAJOR
     FILE (STRINGS "${EXAMPLE_PLUGIN_DEP_INCLUDE_DIR}/hpcc-example-plugin-deps.h" major REGEX "#define EXAMPLE_PLUGIN_DEP_MAJOR")
     STRING (REGEX REPLACE "#define EXAMPLE_PLUGIN_DEP_MAJOR " "" major "${major}")

+ 1 - 1
cmake_modules/FindHIREDIS.cmake

@@ -31,7 +31,7 @@ IF (NOT HIREDIS_FOUND)
   FIND_PATH(HIREDIS_INCLUDE_DIR hiredis/hiredis.h PATHS /usr/include /usr/share/include /usr/local/include PATH_SUFFIXES hiredis)
   FIND_LIBRARY(HIREDIS_LIBRARY NAMES ${libhiredis} PATHS /usr/lib /usr/share /usr/lib64 /usr/local/lib /usr/local/lib64)
 
-  IF(HIREDIS_INCLUDE_DIR)
+  IF(EXISTS "${HIREDIS_INCLUDE_DIR}/hiredis/hiredis.h")
     #MAJOR
     FILE (STRINGS "${HIREDIS_INCLUDE_DIR}/hiredis/hiredis.h" major REGEX "#define HIREDIS_MAJOR")
     STRING(REGEX REPLACE "#define HIREDIS_MAJOR " "" major "${major}")

+ 12 - 11
cmake_modules/FindLIBMEMCACHED.cmake

@@ -41,17 +41,18 @@ find_library(LIBMEMCACHEDUTIL_LIBRARY NAMES ${libmemcachedUtil_lib} PATHS /usr/l
 
 set(LIBMEMCACHED_LIBRARIES ${LIBMEMCACHEDCORE_LIBRARY} ${LIBMEMCACHEDUTIL_LIBRARY})
 
-if(LIBMEMCACHED_INCLUDE_DIR)
-    file(STRINGS "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached-1.0/configure.h" version REGEX "#define LIBMEMCACHED_VERSION_STRING")
-    string(REGEX REPLACE "#define LIBMEMCACHED_VERSION_STRING " "" version "${version}")
-    string(REGEX REPLACE "\"" "" version "${version}")
-    set(LIBMEMCACHED_VERSION_STRING ${version})
-    if("${LIBMEMCACHED_VERSION_STRING}" VERSION_EQUAL "${LIBMEMCACHED_FIND_VERSION}" OR "${LIBMEMCACHED_VERSION_STRING}" VERSION_GREATER "${LIBMEMCACHED_FIND_VERSION}")
-        set(LIBMEMCACHED_VERSION_OK 1)
-        set(MSG "${DEFAULT_MSG}")
-    else()
-        set(LIBMEMCACHED_VERSION_OK 0)
-        set(MSG "libmemcached version '${LIBMEMCACHED_VERSION_STRING}' incompatible with min version>=${LIBMEMCACHED_FIND_VERSION}")
+    if(EXISTS "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached-1.0/configure.h")
+        file(STRINGS "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached-1.0/configure.h" version REGEX "#define LIBMEMCACHED_VERSION_STRING")
+        string(REGEX REPLACE "#define LIBMEMCACHED_VERSION_STRING " "" version "${version}")
+        string(REGEX REPLACE "\"" "" version "${version}")
+        set(LIBMEMCACHED_VERSION_STRING ${version})
+        if("${LIBMEMCACHED_VERSION_STRING}" VERSION_EQUAL "${LIBMEMCACHED_FIND_VERSION}" OR "${LIBMEMCACHED_VERSION_STRING}" VERSION_GREATER "${LIBMEMCACHED_FIND_VERSION}")
+            set(LIBMEMCACHED_VERSION_OK 1)
+            set(MSG "${DEFAULT_MSG}")
+        else()
+            set(LIBMEMCACHED_VERSION_OK 0)
+            set(MSG "libmemcached version '${LIBMEMCACHED_VERSION_STRING}' incompatible with min version>=${LIBMEMCACHED_FIND_VERSION}")
+        endif()
     endif()
 endif()
 

+ 15 - 13
cmake_modules/FindR.cmake

@@ -44,19 +44,21 @@ IF (NOT R_FOUND)
     SET (RCPP_LIBRARY "")    # Newer versions of Rcpp are header-only, with no associated library.
   ENDIF()
 
-  #Rcpp/config.h
-  #define RCPP_VERSION Rcpp_Version(0,12,3)
-  FILE(STRINGS "${RCPP_INCLUDE_DIR}/Rcpp/config.h" version_string REGEX "#define RCPP_VERSION Rcpp_Version\\(")
-  #major
-  STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\(" "" major "${version_string}")
-  STRING(REGEX REPLACE ",[0-9]+,[0-9]+\\)" "" major "${major}")
-  #minor
-  STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\([0-9]+," "" minor "${version_string}")
-  STRING(REGEX REPLACE ",[0-9]+\\)" "" minor "${minor}")
-  #patch
-  STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\([0-9]+,[0-9]+," "" patch "${version_string}")
-  STRING(REGEX REPLACE "\\)" "" patch "${patch}")
-  SET(RCPP_VERSION_STRING "${major}.${minor}.${patch}")
+  IF(EXISTS "${RCPP_INCLUDE_DIR}/Rcpp/config.h")
+    #Rcpp/config.h
+    #define RCPP_VERSION Rcpp_Version(0,12,3)
+    FILE(STRINGS "${RCPP_INCLUDE_DIR}/Rcpp/config.h" version_string REGEX "#define RCPP_VERSION Rcpp_Version\\(")
+    #major
+    STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\(" "" major "${version_string}")
+    STRING(REGEX REPLACE ",[0-9]+,[0-9]+\\)" "" major "${major}")
+    #minor
+    STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\([0-9]+," "" minor "${version_string}")
+    STRING(REGEX REPLACE ",[0-9]+\\)" "" minor "${minor}")
+    #patch
+    STRING(REGEX REPLACE "#define RCPP_VERSION Rcpp_Version\\([0-9]+,[0-9]+," "" patch "${version_string}")
+    STRING(REGEX REPLACE "\\)" "" patch "${patch}")
+    SET(RCPP_VERSION_STRING "${major}.${minor}.${patch}")
+  ENDIF()
 
   SET (R_INCLUDE_DIRS ${R_INCLUDE_DIR} ${RINSIDE_INCLUDE_DIR} ${RCPP_INCLUDE_DIR})
   SET (R_LIBRARIES ${R_LIBRARY} ${RINSIDE_LIBRARY} ${RCPP_LIBRARY})

+ 15 - 6
common/workunit/referencedfilelist.cpp

@@ -179,6 +179,11 @@ public:
         return numParts;
     }
     virtual const StringArray &getSubFileNames() const { return subFileNames; };
+    virtual void appendSubFileNames(const StringArray &names)
+    {
+        ForEachItemIn(i, names)
+            subFileNames.append(names.item(i));
+    };
 public:
     StringArray subFileNames;
     StringAttr logicalName;
@@ -215,7 +220,7 @@ public:
             user.set(userDesc);
     }
 
-    void ensureFile(const char *ln, unsigned flags, const char *pkgid, bool noDfsResolution, const char *daliip=NULL, const char *srcCluster=NULL, const char *remotePrefix=NULL);
+    void ensureFile(const char *ln, unsigned flags, const char *pkgid, bool noDfsResolution, const StringArray *subfileNames, const char *daliip=NULL, const char *srcCluster=NULL, const char *remotePrefix=NULL);
 
     virtual void addFile(const char *ln, const char *daliip=NULL, const char *srcCluster=NULL, const char *remotePrefix=NULL);
     virtual void addFiles(StringArray &files);
@@ -543,7 +548,7 @@ public:
     Owned<HashIterator> iter;
 };
 
-void ReferencedFileList::ensureFile(const char *ln, unsigned flags, const char *pkgid, bool noDfsResolution, const char *daliip, const char *srcCluster, const char *prefix)
+void ReferencedFileList::ensureFile(const char *ln, unsigned flags, const char *pkgid, bool noDfsResolution, const StringArray *subfileNames, const char *daliip, const char *srcCluster, const char *prefix)
 {
     if (!allowForeign && checkForeign(ln))
         throw MakeStringException(-1, "Foreign file not allowed%s: %s", (flags & RefFileInPackage) ? " (declared in package)" : "", ln);
@@ -551,6 +556,8 @@ void ReferencedFileList::ensureFile(const char *ln, unsigned flags, const char *
     Owned<ReferencedFile> file = new ReferencedFile(ln, daliip, srcCluster, prefix, false, flags, pkgid, noDfsResolution, allowSizeCalc);
     if (!file->logicalName.length())
         return;
+    if (subfileNames)
+        file->appendSubFileNames(*subfileNames);
     ReferencedFile *existing = map.getValue(file->getLogicalName());
     if (existing)
         existing->flags |= flags;
@@ -564,7 +571,7 @@ void ReferencedFileList::ensureFile(const char *ln, unsigned flags, const char *
 
 void ReferencedFileList::addFile(const char *ln, const char *daliip, const char *srcCluster, const char *prefix)
 {
-    ensureFile(ln, 0, NULL, false, daliip, srcCluster, prefix);
+    ensureFile(ln, 0, NULL, false, nullptr, daliip, srcCluster, prefix);
 }
 
 void ReferencedFileList::addFiles(StringArray &files)
@@ -649,6 +656,7 @@ bool ReferencedFileList::addFilesFromQuery(IConstWorkUnit *cw, const IHpccPackag
             if (node.getPropBool("att[@name='_isSpill']/@value") ||
                 node.getPropBool("att[@name='_isTransformSpill']/@value"))
                 continue;
+            StringArray subfileNames;
             unsigned flags = isOpt ? RefFileOptional : RefFileNotOptional;
             if (pkg)
             {
@@ -664,14 +672,15 @@ bool ReferencedFileList::addFilesFromQuery(IConstWorkUnit *cw, const IHpccPackag
                         {
                             StringBuffer subfile;
                             ssfe->getSubFileName(count, subfile);
-                            ensureFile(subfile, RefSubFile | RefFileInPackage, pkgid, false);
+                            ensureFile(subfile, RefSubFile | RefFileInPackage, pkgid, false, nullptr);
+                            subfileNames.append(subfile);
                         }
                     }
                 }
-                ensureFile(logicalName, flags, pkgid, pkg->isCompulsory());
+                ensureFile(logicalName, flags, pkgid, pkg->isCompulsory(), &subfileNames);
             }
             else
-                ensureFile(logicalName, flags, NULL, false);
+                ensureFile(logicalName, flags, NULL, false, &subfileNames);
         }
     }
     return pkg ? pkg->isCompulsory() : false;

+ 13 - 12
dali/sasha/saxref.cpp

@@ -41,7 +41,7 @@
 #define LOGPFX "XREF: "
 #define LOGPFX2 "FILEEXPIRY: "
 
-#define RECENTCUTOFF 1  // day
+#define DEFAULT_RECENT_CUTOFF_DAYS 1
 
 inline bool nextCsvToken(const char *&s,StringBuffer &tok) 
 {
@@ -1178,7 +1178,7 @@ public:
     }   
 
 
-    void listOrphans(cFileDesc *f,const char *basedir,bool &abort)
+    void listOrphans(cFileDesc *f,const char *basedir,bool &abort,unsigned int recentCutoffDays)
     {
         if (abort)
             return;
@@ -1328,7 +1328,7 @@ public:
                 if (drv) 
                     setReplicateFilename(tmp,1);
                 CDateTime co(mostrecent[drv]);
-                co.adjustTime(RECENTCUTOFF*60*24);
+                co.adjustTime(recentCutoffDays*60*24);
                 if (co.compare(now)>=0) {
                     warn(tmp.str(),"Recent orphans ignored");
                     branch[drv].clear();
@@ -1416,7 +1416,7 @@ public:
         }
     }
 
-    void listOrphans(cDirDesc *d,StringBuffer &basedir,bool &abort)
+    void listOrphans(cDirDesc *d,StringBuffer &basedir,bool &abort,unsigned int recentCutoffDays)
     {
         if (abort)
             return;
@@ -1439,7 +1439,7 @@ public:
         unsigned i =0;
         cFileDesc *file = d->files.first(i);
         while (file) {
-            listOrphans(file,basedir,abort);
+            listOrphans(file,basedir,abort,recentCutoffDays);
             if (abort)
                 return;
             file = d->files.next(i);
@@ -1447,7 +1447,7 @@ public:
         i = 0;
         cDirDesc *dir = d->dirs.first(i);
         while (dir) {
-            listOrphans(dir,basedir,abort);
+            listOrphans(dir,basedir,abort,recentCutoffDays);
             if (abort)
                 return;
             dir = d->dirs.next(i);
@@ -1468,12 +1468,12 @@ public:
         return stricmp(pt2->queryProp("Name"),pt1->queryProp("Name")); // rev
     }
 
-    void listOrphans(bool &abort)
+    void listOrphans(bool &abort,unsigned int recentCutoffDays)
     {   
         // also does directories
         log("Scanning for orphans");
         StringBuffer basedir;
-        listOrphans(NULL,basedir,abort);
+        listOrphans(NULL,basedir,abort,recentCutoffDays);
         if (abort)
             return;
         log("Orphan scan complete");
@@ -1484,7 +1484,7 @@ public:
     }
 
 
-    void listLost(bool &abort,bool ignorelazylost)
+    void listLost(bool &abort,bool ignorelazylost,unsigned int recentCutoffDays)
     {
         log("Scanning for lost files");
         StringBuffer tmp;
@@ -1527,7 +1527,7 @@ public:
                 CDateTime now;
                 now.setNow();
                 CDateTime co(dt);
-                co.adjustTime(RECENTCUTOFF*60*24);
+                co.adjustTime(recentCutoffDays*60*24);
                 if (co.compare(now)>=0) {
                     warn(lfn.get(),"Recent file ignored");
                     continue;
@@ -2105,13 +2105,14 @@ public:
             if (stopped)
                 break;
             unsigned numThreads = serverConfig->getPropInt("DfuXRef/@numThreads", DEFAULT_MAXDIRTHREADS);
+            unsigned int recentCutoffDays = serverConfig->getPropInt("DfuXRef/@cutoff", DEFAULT_RECENT_CUTOFF_DAYS);
             if (manager.scanDirectories(stopped,numThreads)) {
                 manager.updateStatus(true);
                 manager.scanLogicalFiles(stopped);
                 manager.updateStatus(true);
-                manager.listLost(stopped,ignorelazylost);
+                manager.listLost(stopped,ignorelazylost,recentCutoffDays);
                 manager.updateStatus(true);
-                manager.listOrphans(stopped);
+                manager.listOrphans(stopped,recentCutoffDays);
                 manager.updateStatus(true);
                 manager.saveToEclWatch(stopped,byscheduler);
                 manager.updateStatus(true);

+ 38 - 49
docs/HPCCClientTools/CT_Mods/CT_ESDL_CLI.xml

@@ -846,8 +846,8 @@
 
         <para><emphasis role="bold">esdl bind-service
         &lt;TargetESPProcessName&gt; &lt;TargetESPBindingPort |
-        TargetESPServic eName&gt; &lt;ESDLDefinitionId&gt;
-        &lt;ESDLServiceName&gt; [command options]</emphasis></para>
+        TargetESPServiceName&gt; &lt;ESDLDefinitionId&gt;
+        (&lt;ESDLServiceName&gt;) [command options]</emphasis></para>
 
         <informaltable colsep="1" frame="all" rowsep="1">
           <tgroup cols="2">
@@ -880,8 +880,8 @@
                 <entry>ESDLServiceName</entry>
 
                 <entry>The Name of the ESDL Service (as defined in the ESDL
-                Definition). Optional if the ESDL definition contains only one
-                service.</entry>
+                Definition) Required if ESDL definition contains multiple
+                services</entry>
               </row>
 
               <row>
@@ -953,8 +953,8 @@
         (ESP Process which will host the ESP Service as defined in the ESDL
         Definition.)</para>
 
-        <para>You must also provide the Port on which this service is
-        configured to run (ESP Binding), and the name of the service you are
+        <para>You must also provide either the port on which this service is
+        configured to run (ESP Binding) or the name of the service you are
         binding.</para>
 
         <para>Optionally provide configuration information either directly
@@ -1128,9 +1128,8 @@
       <sect2 id="CT_ESDL_CLI_esdl_unbind-service" role="brk">
         <title>esdl unbind-service</title>
 
-        <para><emphasis role="bold">esdl unbind-service
-        &lt;TargetESPProcessName&gt; &lt;TargetESPBindingPort | TargetESPServ
-        iceName&gt; [options]</emphasis></para>
+        <para><emphasis role="bold">esdl unbind-service &lt;ESPProcessName&gt;
+        &lt;ESPBindingName&gt; [options]</emphasis></para>
 
         <informaltable colsep="1" frame="all" rowsep="1">
           <tgroup cols="2">
@@ -1140,16 +1139,15 @@
 
             <tbody>
               <row>
-                <entry>TargetESPProcessName</entry>
+                <entry>ESPProcessName</entry>
 
-                <entry>The target ESP Process name</entry>
+                <entry>The ESP Process name</entry>
               </row>
 
               <row>
-                <entry>TargetESPBindingPort | TargetESPServiceName</entry>
+                <entry>ESPBindingName</entry>
 
-                <entry>Either target ESP binding port or the target ESP
-                service name</entry>
+                <entry>The ESP Binding name</entry>
               </row>
 
               <row>
@@ -1198,20 +1196,17 @@
           </tgroup>
         </informaltable>
 
-        <para><emphasis role="bold"></emphasis></para>
+        <para>Use this command to unbind ESDL service based bindings. </para>
 
-        <para>Use this command to unpublish ESDL Service based
-        bindings.</para>
+        <para>To unbind a given ESDL binding, provide the ESP process name and
+        the ESP binding which make up this ESDL binding. </para>
 
-        <para>To unbind an ESDL Service, provide the target ESP process name
-        (ESP Process which will host the ESP Service as defined in the ESDL
-        Definition.) You must also provide the Port on which this service is
-        configured to run (the ESP Binding), and the name of the service you
-        are unbinding.</para>
+        <para>Available ESDL bindings to unbind can be found using the "esdl
+        list-bindings" command </para>
 
         <para><emphasis role="bold">Example:</emphasis></para>
 
-        <programlisting>esdl unbind-service myesp 8003 </programlisting>
+        <programlisting>esdl unbind-service myesp myServiceBinding </programlisting>
       </sect2>
 
       <sect2 id="CT_ESDL_CLI_esd_bind-method" role="brk">
@@ -1328,7 +1323,7 @@
         (ESP Process which will host the ESP Service as defined in the ESDL
         Definition.)</para>
 
-        <para>You must also provide the Port on which this service is
+        <para>You must also provide the port on which this service is
         configured to run (ESP Binding), and the name of the service you are
         binding.</para>
 
@@ -1349,10 +1344,9 @@
       <sect2 id="CT_ESDL_CLI_esdl_unbind-method" role="brk">
         <title>esdl unbind-method</title>
 
-        <para><emphasis role="bold">esdl unbind-method
-        &lt;TargetESPProcessName&gt; &lt;TargetESPBindingName&gt;
-        &lt;TargetServiceName&gt; &lt;TargetServiceDefVersion&gt;
-        &lt;TargetMethodName&gt; [options]</emphasis></para>
+        <para><emphasis role="bold">esdl unbind-method &lt;ESPProcessName&gt;
+        &lt;ESPBindingName&gt; &lt;ESDLServiceName&gt; &lt;MethodName&gt;
+        [options]</emphasis></para>
 
         <informaltable colsep="1" frame="all" rowsep="1">
           <tgroup cols="2">
@@ -1362,35 +1356,30 @@
 
             <tbody>
               <row>
-                <entry>TargetESPProcessName</entry>
+                <entry>ESPProcessName</entry>
 
                 <entry>The target ESP Process name</entry>
               </row>
 
               <row>
-                <entry>TargetESPBindingName</entry>
+                <entry>ESPBindingName</entry>
 
                 <entry>The target ESP binding name associated with this
                 service</entry>
               </row>
 
               <row>
-                <entry>TargetServiceName</entry>
-
-                <entry>The name of the Service as defined in ESDL</entry>
-              </row>
-
-              <row>
-                <entry>TargetServiceDefVersion</entry>
+                <entry>ESDLServiceName</entry>
 
-                <entry>The version of the target service ESDL
-                definition</entry>
+                <entry>The name of the ESDLService associated with the target
+                method. </entry>
               </row>
 
               <row>
-                <entry>TargetMethodName</entry>
+                <entry>MethodName</entry>
 
-                <entry>The name of the target method</entry>
+                <entry>The name of the target method (must exist in the
+                service ESDL definition)</entry>
               </row>
 
               <row>
@@ -1439,19 +1428,19 @@
           </tgroup>
         </informaltable>
 
-        <para>Use this command to unbind a method configuration currently
-        associated with a given ESDL binding.</para>
+        <para>Use this command to unbind a method configuration associated
+        with a given ESDL binding0.</para>
 
-        <para>To unbind a method, provide the target ESP process name (esp
-        which hosts the service.). It is also necessary to provide the Port on
-        which this service is configured to run (ESP Binding), and the name of
-        the method you are unbinding.</para>
+        <para>To unbind a method, provide the target ESP process name (the ESP
+        which hosts the service.)</para>
 
-        <para></para>
+        <para>You must also provide the ESP binding on which this service is
+        configured to run, the name of the ESDL service, and the name of the
+        method you are unbinding.</para>
 
         <para><emphasis role="bold">Example:</emphasis></para>
 
-        <programlisting>esdl unbind-method myesp mybinding WsMyService mymethod </programlisting>
+        <programlisting>esdl unbind-method myesp myespbinding WsMyService mymethod </programlisting>
       </sect2>
 
       <sect2 id="CT_ESDL_CLI_esdl_get-binding" role="brk">

+ 1 - 1
ecl/hql/hqlutil.cpp

@@ -9265,7 +9265,7 @@ IHqlExpression * expandMacroDefinition(IHqlExpression * expr, HqlLookupContext &
 static IHqlExpression * transformAttributeToQuery(IHqlExpression * expr, HqlLookupContext & ctx, bool syntaxCheck)
 {
     if (expr->isMacro())
-        return expandMacroDefinition(expr, ctx, true);
+        return expandMacroDefinition(expr, ctx, !syntaxCheck);
 
     if (expr->isFunction())
     {

+ 32 - 0
ecl/regress/issue18000.eclxml

@@ -0,0 +1,32 @@
+<Archive build="community_6.4.0-rc6Debug"
+         eclVersion="6.4.0"
+         legacyImport="0"
+         legacyWhen="0">
+ <Query attributePath="_local_directory_.issue18000"/>
+ <Option name="syntaxCheck" value="1"/>
+ <Module key="_local_directory_" name="_local_directory_">
+  <Attribute key="issue18000" name="issue18000" sourcePath="issue18000.ecl">
+   /*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+    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 &quot;AS IS&quot; 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.
+############################################################################## */
+
+
+export issue18000(AttrName,FirstArg,SecondArg) := MACRO
+    AttrName := FirstArg + SecondArg;
+ENDMACRO;
+  </Attribute>
+ </Module>
+</Archive>

+ 14 - 7
esp/esdllib/esdl_def.cpp

@@ -269,16 +269,23 @@ public:
         // must provide a parameter on the URL '?internal' to see those elements
         // in the WSDL or web form.
 
-        if( opts && defOptional )
+        if (opts && defOptional)
         {
-            if( opts->hasProp(defOptional) )
+            if (*defOptional == '!')
             {
-                return true;
-            } else {
-                return false;
+                if (!opts->hasProp(defOptional+1))
+                    return true;
+                else
+                    return false;
+            }
+            else
+            {
+                if (opts->hasProp(defOptional))
+                    return true;
+                else
+                    return false;
             }
         }
-
         return true;
     }
 };
@@ -1662,7 +1669,7 @@ void EsdlDefinition::walkDefinitionDepthFirst( AddedObjs& foundByName, EsdlDefOb
     // ancestors- they've already been added.
     // Checking up front here will also allow us to detect cycles in the strcuture
     // graph -such as we have with BpsReportRelative- and avoid an infinite loop
-    if( found || esdlObj->checkOptional(opts) == false || esdlObj->checkVersion(requestedVer) == false )
+    if (found || esdlObj->checkOptional(opts) == false || (requestedVer != 0.0 && esdlObj->checkVersion(requestedVer) == false))
     {
         //DBGLOG("%s</%s><Skipped/>", indent.str(), esdlObj->queryName());
         return;

+ 13 - 4
esp/esdllib/esdl_transformer2.cpp

@@ -230,13 +230,22 @@ void Esdl2Base::serialize_attributes(StringBuffer &out)
     }
 }
 
-// return true if it passed version check
+// return true if it passed optional check and version check
 bool Esdl2Base::checkVersion(Esdl2TransformerContext &ctx)
 {
     if (!param_group.isEmpty())
-        if (!ctx.param_groups || !ctx.param_groups->hasProp(param_group.get()))
-            return false;
-
+    {
+        if (param_group.get()[0] == '!')
+        {
+           if (ctx.param_groups && ctx.param_groups->hasProp(param_group.get()+1))
+               return false;
+        }
+        else
+        {
+            if (!ctx.param_groups || !ctx.param_groups->hasProp(param_group.get()))
+                return false;
+        }
+    }
     return m_def->checkVersion(ctx.client_ver);
 }
 

+ 7 - 1
esp/platform/espcontext.cpp

@@ -125,7 +125,13 @@ public:
     virtual bool checkMinVer(double minVer) {  return m_clientVer<0 || m_clientVer >= minVer; }
     virtual bool checkMaxVer(double maxVer) {  return m_clientVer<0 || m_clientVer <= maxVer; }
     virtual bool checkMinMaxVer(double minVer, double maxVer) {  return m_clientVer<0 || m_clientVer>= minVer || m_clientVer <= maxVer; }
-    virtual bool checkOptional(const char* option) { return m_queryparams.get() && m_queryparams->hasProp(option); }
+    virtual bool checkOptional(const char* option)
+    {
+        if (option && *option == '!')
+            return !m_queryparams.get() || !m_queryparams->hasProp(option+1);
+        else
+            return m_queryparams.get() && m_queryparams->hasProp(option);
+    }
     virtual bool isMethodAllowed(double version, const char* optional, const char* security, double maxver, double minver);
 
     virtual IMapInfo& queryMapInfo() 

+ 1 - 1
esp/src/eclwatch/XrefFoundFilesWidget.js

@@ -121,7 +121,7 @@ define([
             var selections = this.grid.getSelected();
             var list = this.arrayToList(selections, "Name");
             if (confirm(this.i18n.AddTheseFilesToDali + "\n" + list)) {
-                WsDFUXref.DFUXRefArrayAction(selections, this.i18n.Attach, context.params.Name, "Attach").then(function (response) {
+                WsDFUXref.DFUXRefArrayAction(selections, "Attach", context.params.Name, "Found").then(function (response) {
                     context.refreshGrid();
                 });
             }

+ 4 - 1
esp/xslt/esxdl2xsd.xslt

@@ -165,7 +165,7 @@
                 </xsl:attribute>
             </xsl:if>
             <xsl:if test="boolean($all_annot_Param)">
-                <xsl:if test="@html_head or @form_ui or @collapsed or @cols or @rows">
+                <xsl:if test="@html_head or @form_ui or @collapsed or @cols or @rows or @optional">
                     <xsd:annotation>
                         <xsd:appinfo>
                             <form>
@@ -189,6 +189,9 @@
                                 <xsl:if test="@rows">
                                     <xsl:attribute name="formRows"><xsl:value-of select="@rows"/></xsl:attribute>
                                 </xsl:if>
+                                <xsl:if test="@optional">
+                                    <xsl:attribute name="optional"><xsl:value-of select="@optional"/></xsl:attribute>
+                                </xsl:if>
                             </form>
                         </xsd:appinfo>
                     </xsd:annotation>

+ 17 - 0
esp/xslt/gen_form.xsl

@@ -772,6 +772,7 @@
             <xsl:with-param name="inputCtrlHtml" select="$inputCtrlHtml"/>
             <xsl:with-param name="isAttr" select="name($node)='xsd:attribute'"/>
             <xsl:with-param name="isBool" select="$node/@type='xsd:boolean'"/>
+            <xsl:with-param name="optional" select="$node/xsd:annotation/xsd:appinfo/form/@optional | $node/xsd:annotation/xsd:appinfo/xsd:form/@optional"/>
         </xsl:call-template>
     </xsl:template >
     
@@ -785,6 +786,7 @@
         <xsl:param name="inputCtrlHtml" select="''"/>
         <xsl:param name="isAttr" select="false()"/>
         <xsl:param name="isBool" select="false()"/>
+        <xsl:param name="optional" select="''"/>
 
         <!--    <xsl:if test="$verbose"><xsl:value-of select="concat('GenOneInputCtrlHtmlRaw(parentId=', $parentId, ', fieldId=', $fieldId, ', ui=', $ui, ', inputCtrlHtml=', $inputCtrlHtml, ')&lt;br/&gt;') "/> </xsl:if> -->     
 
@@ -828,6 +830,9 @@
                                 <xsl:text disable-output-escaping="yes"><![CDATA['> <b>]]></xsl:text>
                 <xsl:value-of select="$fieldName"/>
                 <xsl:text disable-output-escaping="yes"><![CDATA[</b>]]></xsl:text>
+                <xsl:call-template name="showOptionalSupscript">
+                    <xsl:with-param name="optional" select="$optional"/>
+                </xsl:call-template>
                 <xsl:value-of select="$ctrlId"/>
                 <xsl:choose>
                     <xsl:when test="$isBool">
@@ -848,6 +853,9 @@
                 <xsl:value-of select="$fieldName"/>
                 <xsl:if test="$isAttr"><![CDATA[</i>]]></xsl:if>
                 <xsl:text disable-output-escaping="yes"><![CDATA[</b></span>]]></xsl:text>
+                <xsl:call-template name="showOptionalSupscript">
+                    <xsl:with-param name="optional" select="$optional"/>
+                </xsl:call-template>
                 <xsl:value-of select="$ctrlId"/>
                 <xsl:choose>
                     <xsl:when test="$isBool">
@@ -1468,6 +1476,15 @@
             </xsl:otherwise>
         </xsl:choose>
     </xsl:template>
+    <xsl:template name="showOptionalSupscript">
+      <xsl:param name="optional" select="''"/>
+      <!-- optional starts with _ is deeemed as implementation specific and don't show it -->
+      <xsl:if test="$optional and substring($optional,1,1)!='_' and substring($optional,1,2)!='!_'">
+        <xsl:text><![CDATA[<sup style='color:red'>]]></xsl:text>
+        <xsl:value-of select="$optional"/>
+        <xsl:text><![CDATA[</sup>]]></xsl:text>
+      </xsl:if>
+    </xsl:template>
 </xsl:stylesheet>
 
 

+ 2 - 2
initfiles/examples/EsdlExample/ReadMeFirst.txt

@@ -24,7 +24,7 @@ Make a copy of the /opt/HPCCSystems/examples/EsdlExample folder.
 From EsdlExample copy folder:
 
 1. Generate java base classes (and dummy implementation file): 
-esdl java esdl_example.esdl EsdlExample --version=9
+esdl java esdl_example.esdl EsdlExample
 
 2. Compile java base classes and example service (must have sudo access to place the classes in the default HPCC class location):
 sudo javac -g EsdlExampleServiceBase.java -cp /opt/HPCCSystems/classes -d /opt/HPCCSystems/classes/
@@ -37,7 +37,7 @@ esdl ecl esdl_example.esdl .
 ecl publish roxie RoxieEchoPersonInfo.ecl
 
 5. Publish the esdl defined service to dynamicESDL:
- esdl publish esdl_example.esdl EsdlExample --version 9 --overwrite
+ esdl publish esdl_example.esdl EsdlExample --overwrite
 
 5. Bind both java and roxie implementations to DynamicESDL
 esdl bind-service myesp 8088 esdlexample.1 EsdlExample --config esdl_binding.xml --overwrite

+ 234 - 0
initfiles/examples/embed/couchbase-simple.ecl

@@ -0,0 +1,234 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2017 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.
+############################################################################## */
+
+IMPORT couchbase;
+
+/******************************************************************************************
+   This set of example queries are based on the couchbase sample bucket 'travel-sample'
+   The sample data is easily set-up, please refer to the couchbase documentation for set-up
+*******************************************************************************************/
+
+server := '127.0.0.1';            //change this to point to your couchbase
+thebucket := 'travel-sample';
+
+namerec := RECORD
+  string name;
+END;
+
+typerec := RECORD
+  string type;
+END;
+
+travelrec := RECORD
+  string callsign;
+  string country;
+  string iata;
+  string icao;
+  integer id;
+  string name;
+  string type;
+END;
+
+georec := RECORD
+  integer alt;
+  real lat;
+  real lon;
+END;
+
+airportrec := RECORD
+  string airportname;
+  string city;
+  string country;
+  string faa;
+  string  tz;
+  string type;
+  integer id;
+  string icao;
+  georec geo;
+END;
+
+/*
+ --Sample Airport record--
+ "airportname": "Calais Dunkerque",
+    "city": "Calais",
+    "country": "France",
+    "faa": "CQF",
+    "geo": {
+      "alt": 12,
+      "lat": 50.962097,
+      "lon": 1.954764
+    },
+    "icao": "LFAC",
+    "id": 1254,
+    "type": "airport",
+    "tz": "Europe/Paris"
+*/
+/*
+  --sample airline record--
+  "callsign": null,
+  "country": "United States",
+  "iata": "WQ",
+  "icao": "PQW",
+  "id": 13633,
+  "name": "PanAm World Airways",
+  "type": "airline"
+*/
+schedrec := RECORD
+  unsigned day;
+  string flight;
+  string utc;
+END;
+
+routerec := RECORD
+  string airline;
+  string airlineid;
+  string3 destinationairport;
+  real distance;
+  string equipment;
+  integer id;
+  dataset(schedrec) schedule {xpath('schedule')};
+  string3 sourceairport;
+  unsigned stops;
+  string type;
+END;
+/*
+  "travel-sample": {
+  "airline": "AH",
+  "airlineid": "airline_794",
+  "destinationairport": "CDG",
+  "distance": 1420.6731433915318,
+  "equipment": "738",
+  "id": 10041,
+  "schedule": [
+      {
+       "day": 0,
+       "flight": "AH547",
+       "utc": "07:58:00"
+      },
+      {
+       "day": 0,
+       "flight": "AH428",
+       "utc": "12:08:00"
+      },
+      {
+       "day": 1,
+       "flight": "AH444",
+       "utc": "14:16:00"
+      },
+      {
+       "day": 3,
+       "flight": "AH741",
+       "utc": "04:56:00"
+      },
+      {
+       "day": 4,
+       "flight": "AH027",
+       "utc": "03:16:00"
+      },
+      {
+       "day": 4,
+       "flight": "AH113",
+       "utc": "08:11:00"
+      },
+      {
+       "day": 6,
+       "flight": "AH260",
+       "utc": "18:02:00"
+      },
+      {
+       "day": 6,
+       "flight": "AH873",
+       "utc": "03:58:00"
+      }
+     ],
+     "sourceairport": "AAE",
+     "stops": 0,
+     "type": "route"
+    }
+    */
+
+/* Due to inconsistencies found in couchbase travel-sample, some queries explicitly omit records of type landmark and hotel */
+
+integer countAllRecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT count(*) from `travel-sample` as mybucketalias where mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+integer countTypes() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT COUNT(DISTINCT mybucketalias.type) from `travel-sample` as mybucketalias where mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+dataset(typerec) allTypes() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT DISTINCT mybucketalias.type from `travel-sample` as mybucketalias where mybucketalias.type IS NOT NULL and mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+dataset(travelrec) fulltravelrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where callsign = 'MILE-AIR' limit 10;
+ENDEMBED;
+
+dataset(namerec) airlinenames() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.name from `travel-sample` as mybucketalias where mybucketalias.type = 'airline' limit 10;
+ENDEMBED;
+
+dataset(airportrec) airportrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' limit 10;
+ENDEMBED;
+
+dataset(airportrec) usairportrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and country = 'United States' limit 10;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbycountry(string m) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and country = $m limit 10;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbyid(integer id) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and id = $id limit 10;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbyaltitude(integer alt) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and geo.alt >= $alt limit 10;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbycoordinates(row(georec) values) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and geo.lat = $lat and geo.lon = $lon limit 10;
+ENDEMBED;
+
+dataset(routerec) fullroute()  := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT mybucketalias.* FROM `travel-sample` as mybucketalias WHERE type = 'route' and sourceairport IS NOT NULL LIMIT 10
+ENDEMBED;
+
+dataset(routerec) routeschedule(string sair, string dair)  := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT mybucketalias.schedule  FROM `travel-sample` as mybucketalias WHERE type = 'route' and sourceairport = $sair and destinationairport = $dair  LIMIT 1
+ENDEMBED;
+
+sequential
+(
+  OUTPUT(countAllRecords(), NAMED('CountOfAllRecs'));
+  OUTPUT(countTypes(), NAMED('CountOfAllRecTypes'));
+  OUTPUT(allTypes(), NAMED('AllRecordTypes'));
+  OUTPUT(airlinenames(), NAMED('AirlineNames'));
+  OUTPUT(usairportrecords(), NAMED('USAirports'));
+  OUTPUT(airportrecordsbycountry('"France"'), NAMED('AirportsByCountry'));
+  OUTPUT(fulltravelrecords(), NAMED('FullTravelRec'));
+  OUTPUT(airportrecordsbyid(3411), NAMED('AirportByID'));
+  OUTPUT(airportrecordsbyaltitude(4000), NAMED('AirportsAtAltitude'));
+  OUTPUT(airportrecordsbycoordinates(ROW({0,31.3426028, -109.5064544},georec)), NAMED('AirportAtCoordinate'));
+  OUTPUT(fullroute(), NAMED('FullRouteRec'));
+  OUTPUT(routeschedule('"AAE"', '"CDG"'),  NAMED('RouteAAEtoCDG'));
+  OUTPUT('Done', NAMED('Status'));
+);
+

+ 140 - 0
initfiles/examples/embed/couchbase-simple2.ecl

@@ -0,0 +1,140 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2017 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.
+############################################################################## */
+
+//class=embedded
+//class=3rdparty
+
+IMPORT couchbase;
+IMPORT STD;
+
+/***********************************************************************************************
+   This set of example queries are based on a device oriented document structure described below
+   These samples queries rely on a bucket named 'iot'. In order to run these queries, please
+      create the iot bucket on the target couchbase server
+************************************************************************************************/
+
+server := '127.0.0.1';
+thebucket := 'iot';
+
+string adocid := '"mydocid' ;
+string adoc1  := '{"deviceID": "9cf9r-3c0f-446b-ad6a-4136deb88519" ,"deviceType": "handheld","message":{"locationData":{"x": 52.227,"y": 77.699,"z": 99.999, "zoneId": "W"}, "rawdata":{"ambientTemp": 68.21, "barometer": 14.81, "batteryLevelPercentage": 95.32, "bodyTemp": 30.08, "coLevel": 1.46, "forceSensitiveResistance": 136, "heartRate": 94}, "deviceTimestamp": "2017-06-05 15:04:35.924657-0400"}, "receivedTimestamp": "' + STD.System.Debug.msTick ( ) + '"}';
+string adoc2 := '{"deviceID":  "1135c-3c0f-776b-ag6a-7136deb83464" ,"deviceType": "wearable","message":{"locationData":{"x": 2.247,"y": 33.629,"z": 1.323,   "zoneId": "A"}, "rawdata":{"ambientTemp": 8.65,  "barometer": 34.56, "batteryLevelPercentage": 32.09, "bodyTemp": 29.68, "coLevel": 1.34, "forceSensitiveResistance": 6,   "heartRate": 56}, "deviceTimestamp": "2017-06-05 15:05:27.325365-0400"}, "receivedTimestamp": "' + STD.System.Debug.msTick ( ) + '"}';
+
+/*
+Document structure:
+{
+    "deviceID": "9cf9r-3c0f-446b-ad6a-4136deb88519",
+    "deviceType": "handheld",
+    "message":
+    {
+        "locationData": {
+            "x": 52.227,
+            "y": 77.699,
+            "z": 99.999,
+            "zoneId": "W"
+        },
+        "rawdata": {
+            "ambientTemp": 38.21,
+            "barometer": 14.81,
+            "batteryLevelPercentage": 95.32,
+            "bodyTemp": 30.08,
+            "coLevel": 1.46,
+            "forceSensitiveResistance": 166,
+            "heartRate": 94
+        },
+        "deviceTimestamp": "2017-06-05 15:04:35.924657-0400"
+    },
+    "receivedTimestamp": "1496275475926453"
+}
+*/
+
+deviceidrec := RECORD
+  string deviceID;
+END;
+
+rawdatarec := RECORD
+  real4 ambientTemp;
+  real4 barometer;
+  real4 batteryLevelPercentage;
+  real4 bodyTemp;
+  real4 coLevel;
+  real4 forceSensitiveResistance;
+  INTEGER heartRate;
+END;
+
+locationDatarec := RECORD
+  real x {xpath('x')};
+  real y {xpath('y')};
+  real z {xpath('z')};
+  string zoneId {xpath('zoneId')};
+END;
+
+messagerec := RECORD
+  string deviceTimestamp;
+  locationDatarec locationData;
+  rawdatarec rawdata;
+END;
+
+iotrec := RECORD
+  string deviceID;
+  string deviceType;
+  string receivedTimestamp;
+  messagerec message;
+END;
+
+BOOLEAN insertiotdoc(string docid, string doc) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1))
+  INSERT INTO iot (KEY, VALUE) VALUES ($docid, $doc) RETURNING TRUE AS c;
+ENDEMBED;
+
+BOOLEAN upsertiotdoc(string docid, string doc) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1))
+  INSERT INTO iot (KEY, VALUE) VALUES ($docid, $doc) RETURNING TRUE AS c;
+ENDEMBED;
+
+STRING getlatesttimestamp() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1))
+  SELECT max(iot.receivedTimestamp) FROM iot;
+ENDEMBED;
+
+dataset(iotrec) getlatestdoc(string devid) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1))
+  SELECT iot.* FROM iot where iot.deviceID = $devid;
+ENDEMBED;
+
+integer devicecount() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1))
+  SELECT count(DISTINCT iot.deviceID) FROM iot ;
+ENDEMBED;
+
+dataset(iotrec) devicebylocation(row(locationDatarec) values) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select iot.* from iot where iot.message.locationData.x = $x and iot.message.locationData.y = $y limit 1;
+ENDEMBED;
+
+dataset(deviceidrec) deviceidsbyzone(string zone) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select DISTINCT iot.deviceID from iot where iot.message.locationData.zoneId = $zone;
+ENDEMBED;
+
+sequential
+(
+  OUTPUT(insertiotdoc(adocid + random() + '"', adoc1));
+  Std.System.Debug.Sleep(200);
+  OUTPUT(insertiotdoc(adocid + random() + '"', adoc2));
+  OUTPUT(upsertiotdoc(adocid + random() + '"', adoc1));
+  Std.System.Debug.Sleep(200);
+  OUTPUT(getlatesttimestamp());
+  OUTPUT(getlatestdoc('"11135e49c-3c0f-446b-ad6a-4136deb88519"'));
+  OUTPUT(devicecount());
+  OUTPUT(devicebylocation(ROW({2.247,33.629,1.323,'"A"'},locationDatarec)));
+  OUTPUT(deviceidsbyzone('"A"'));
+  OUTPUT('Done');
+);

+ 59 - 37
plugins/couchbase/couchbaseembed.cpp

@@ -901,14 +901,15 @@ namespace couchbaseembed
     {
         isAll = false; // ALL not supported
 
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath)
+        if (!xpath.isEmpty())
         {
             PathTracker     newPathNode(xpath, CPNTSet);
             StringBuffer    newXPath;
 
-            constructNewXPath(newXPath, xpath);
+            constructNewXPath(newXPath, xpath.str());
 
             newPathNode.childCount = m_oResultRow->getCount(newXPath);
             m_pathStack.push_back(newPathNode);
@@ -926,14 +927,15 @@ namespace couchbaseembed
 
     void CouchbaseRowBuilder::processBeginDataset(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath)
+        if (!xpath.isEmpty())
         {
             PathTracker     newPathNode(xpath, CPNTDataset);
             StringBuffer    newXPath;
 
-            constructNewXPath(newXPath, xpath);
+            constructNewXPath(newXPath, xpath.str());
 
             newPathNode.childCount = m_oResultRow->getCount(newXPath);
             m_pathStack.push_back(newPathNode);
@@ -946,11 +948,12 @@ namespace couchbaseembed
 
     void CouchbaseRowBuilder::processBeginRow(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath)
+        if (!xpath.isEmpty())
         {
-            if (strncmp(xpath, "<nested row>", 12) == 0)
+            if (strncmp(xpath.str(), "<nested row>", 12) == 0)
             {
                 // Row within child dataset
                 if (m_pathStack.back().nodeType == CPNTDataset)
@@ -980,9 +983,10 @@ namespace couchbaseembed
 
     void CouchbaseRowBuilder::processEndSet(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath && !m_pathStack.empty() && strcmp(xpath, m_pathStack.back().nodeName.str()) == 0)
+        if (!xpath.isEmpty() && !m_pathStack.empty() && strcmp(xpath.str(), m_pathStack.back().nodeName.str()) == 0)
         {
             m_pathStack.pop_back();
         }
@@ -990,11 +994,12 @@ namespace couchbaseembed
 
     void CouchbaseRowBuilder::processEndDataset(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath)
+        if (!xpath.isEmpty())
         {
-            if (!m_pathStack.empty() && strcmp(xpath, m_pathStack.back().nodeName.str()) == 0)
+            if (!m_pathStack.empty() && strcmp(xpath.str(), m_pathStack.back().nodeName.str()) == 0)
             {
                 m_pathStack.pop_back();
             }
@@ -1007,9 +1012,10 @@ namespace couchbaseembed
 
     void CouchbaseRowBuilder::processEndRow(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (xpath && *xpath)
+        if (!xpath.isEmpty())
         {
             if (!m_pathStack.empty())
             {
@@ -1017,7 +1023,7 @@ namespace couchbaseembed
                 {
                     m_pathStack.back().childrenProcessed++;
                 }
-                else if (strcmp(xpath, m_pathStack.back().nodeName.str()) == 0)
+                else if (strcmp(xpath.str(), m_pathStack.back().nodeName.str()) == 0)
                 {
                     m_pathStack.pop_back();
                 }
@@ -1031,15 +1037,16 @@ namespace couchbaseembed
 
     const char * CouchbaseRowBuilder::nextField(const RtlFieldInfo * field)
     {
-        const char * xpath = xpathOrName(field);
+        StringBuffer    xpath;
+        xpathOrName(xpath, field);
 
-        if (!xpath || !*xpath)
+        if (xpath.isEmpty())
         {
             failx("nextField: Field name or xpath missing");
         }
         StringBuffer fullXPath;
 
-        if (!m_pathStack.empty() && m_pathStack.back().nodeType == CPNTSet && strncmp(xpath, "<set element>", 13) == 0)
+        if (!m_pathStack.empty() && m_pathStack.back().nodeType == CPNTSet && strncmp(xpath.str(), "<set element>", 13) == 0)
         {
             m_pathStack.back().currentChildIndex++;
             constructNewXPath(fullXPath, NULL);
@@ -1047,49 +1054,64 @@ namespace couchbaseembed
         }
         else
         {
-            constructNewXPath(fullXPath, xpath);
+            constructNewXPath(fullXPath, xpath.str());
         }
 
         return m_oResultRow->queryProp(fullXPath.str());
     }
 
-    const char * CouchbaseRowBuilder::xpathOrName(const RtlFieldInfo * field) const
+    void CouchbaseRowBuilder::xpathOrName(StringBuffer & outXPath, const RtlFieldInfo * field) const
     {
-        const char * xpath = NULL;
+        outXPath.clear();
 
         if (field->xpath)
         {
             if (field->xpath[0] == xpathCompoundSeparatorChar)
             {
-                xpath = field->xpath + 1;
+                outXPath.append(field->xpath + 1);
             }
             else
             {
-                xpath = field->xpath;
+                const char * sep = strchr(field->xpath, xpathCompoundSeparatorChar);
+
+                if (!sep)
+                {
+                    outXPath.append(field->xpath);
+                }
+                else
+                {
+                    outXPath.append(field->xpath, 0, static_cast<size32_t>(sep - field->xpath));
+                }
             }
         }
         else
         {
-            xpath = field->name;
+            outXPath.append(field->name);
         }
-
-        return xpath;
     }
 
     void CouchbaseRowBuilder::constructNewXPath(StringBuffer& outXPath, const char * nextNode) const
     {
-        for (std::vector<PathTracker>::const_iterator iter = m_pathStack.begin(); iter != m_pathStack.end(); iter++)
+        bool nextNodeIsFromRoot = (nextNode && *nextNode == '/');
+
+        outXPath.clear();
+
+        if (!nextNodeIsFromRoot)
         {
-            if (strncmp(iter->nodeName, "<row>", 5) != 0)
+            // Build up full parent xpath using our previous components
+            for (std::vector<PathTracker>::const_iterator iter = m_pathStack.begin(); iter != m_pathStack.end(); iter++)
             {
-                if (!outXPath.isEmpty())
-                {
-                    outXPath.append("/");
-                }
-                outXPath.append(iter->nodeName);
-                if (iter->nodeType == CPNTDataset || iter->nodeType == CPNTSet)
+                if (strncmp(iter->nodeName, "<row>", 5) != 0)
                 {
-                    outXPath.appendf("[%d]", iter->currentChildIndex);
+                    if (!outXPath.isEmpty())
+                    {
+                        outXPath.append("/");
+                    }
+                    outXPath.append(iter->nodeName);
+                    if (iter->nodeType == CPNTDataset || iter->nodeType == CPNTSet)
+                    {
+                        outXPath.appendf("[%d]", iter->currentChildIndex);
+                    }
                 }
             }
         }

+ 2 - 2
plugins/couchbase/couchbaseembed.hpp

@@ -190,7 +190,7 @@ namespace couchbaseembed
         inline CouchbaseConnection(bool useSSL, const char * host, unsigned port, const char * bucketname, const char * user, const char * password, const char * connOptions)
         {
             m_connectionString.setf("couchbase%s://%s:%d/%s%s", useSSL ? "s" : "", host, port, bucketname, connOptions);
-            m_pCouchbaseClient = new Couchbase::Client(m_connectionString.str());//USER/PASS still needed
+            m_pCouchbaseClient = new Couchbase::Client(m_connectionString.str(), password);
             m_pQuery = nullptr;
         }
 
@@ -271,7 +271,7 @@ namespace couchbaseembed
 
     protected:
         const char * nextField(const RtlFieldInfo * field);
-        const char * xpathOrName(const RtlFieldInfo * field) const;
+        void xpathOrName(StringBuffer & outXPath, const RtlFieldInfo * field) const;
         void constructNewXPath(StringBuffer& outXPath, const char * nextNode) const;
     private:
         TokenDeserializer m_tokenDeserializer;

+ 9 - 1
system/jlib/jdebug.cpp

@@ -2291,6 +2291,7 @@ public:
     {
         inErrorsCol = -1;
         prevErrors = 0;
+        firstCall = true;
     }
     bool reportSnmpInfo()
     {
@@ -2327,7 +2328,13 @@ public:
                     {
                         ok = true;
                         unsigned errors = strtoul(cols.item(inErrorsCol), NULL, 10);
-                        if (errors > prevErrors)
+                        if (firstCall)
+                        {
+                            firstCall = false;
+                            if (errors)
+                                LOG(MCoperatorWarning, unknownJob, "UDP Initial InError total: %u", errors);
+                        }
+                        else if (errors > prevErrors)
                             LOG(MCoperatorError, unknownJob, "UDP InErrors: %u (total %u)", errors-prevErrors, errors);
                         prevErrors = errors;
                     }
@@ -2343,6 +2350,7 @@ private:
     StringArray columnNames;
     int inErrorsCol;
     unsigned prevErrors;
+    bool firstCall;
 };
 
 static class CMemoryUsageReporter: public Thread

+ 1 - 1
system/jlib/jptree-attrvalues.hpp

@@ -5,7 +5,7 @@
     "*",
     "\\,",
     "0 secs",
-    "-1"
+    "-1",
     "1:1",
     "1:M",
     "Access to cluster topology",

+ 2 - 2
system/jlib/jsocket.cpp

@@ -3071,7 +3071,7 @@ static bool lookupHostAddress(const char *name,unsigned *netaddr)
     // if IP4only or using MS V6 can only resolve IPv4 using 
     static bool recursioncheck = false; // needed to stop error message recursing
     unsigned retry=10;
-#if defined(__linux__) || defined(getaddrinfo)
+#if defined(__linux__) || defined (__APPLE__) ||defined(getaddrinfo)
     if (IP4only) {
 #else
     {
@@ -3116,7 +3116,7 @@ static bool lookupHostAddress(const char *name,unsigned *netaddr)
         }
         return false;
     }
-#if defined(__linux__) || defined(getaddrinfo)
+#if defined(__linux__) || defined (__APPLE__) || defined(getaddrinfo)
     struct addrinfo hints;
     memset(&hints,0,sizeof(hints));
     struct addrinfo  *addrInfo = NULL;

+ 237 - 0
testing/regress/ecl/couchbase-simple.ecl

@@ -0,0 +1,237 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2017 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.
+############################################################################## */
+
+//class=embedded
+//class=3rdparty
+
+IMPORT couchbase;
+
+/******************************************************************************************
+   This set of example queries are based on the couchbase sample bucket 'travel-sample'
+   The sample data is easily set-up, please refer to the couchbase documentation for set-up
+*******************************************************************************************/
+
+server := '127.0.0.1';            //change this to point to your couchbase
+thebucket := 'travel-sample';
+
+namerec := RECORD
+  string name;
+END;
+
+typerec := RECORD
+  string type;
+END;
+
+travelrec := RECORD
+  string callsign;
+  string country;
+  string iata;
+  string icao;
+  integer id;
+  string name;
+  string type;
+END;
+
+georec := RECORD
+  integer alt;
+  real lat;
+  real lon;
+END;
+
+airportrec := RECORD
+  string airportname;
+  string city;
+  string country;
+  string faa;
+  string  tz;
+  string type;
+  integer id;
+  string icao;
+  georec geo;
+END;
+
+/*
+ --Sample Airport record--
+ "airportname": "Calais Dunkerque",
+    "city": "Calais",
+    "country": "France",
+    "faa": "CQF",
+    "geo": {
+      "alt": 12,
+      "lat": 50.962097,
+      "lon": 1.954764
+    },
+    "icao": "LFAC",
+    "id": 1254,
+    "type": "airport",
+    "tz": "Europe/Paris"
+*/
+/*
+  --sample airline record--
+  "callsign": null,
+  "country": "United States",
+  "iata": "WQ",
+  "icao": "PQW",
+  "id": 13633,
+  "name": "PanAm World Airways",
+  "type": "airline"
+*/
+schedrec := RECORD
+  unsigned day;
+  string flight;
+  string utc;
+END;
+
+routerec := RECORD
+  string airline;
+  string airlineid;
+  string3 destinationairport;
+  real distance;
+  string equipment;
+  integer id;
+  dataset(schedrec) schedule {xpath('schedule')};
+  string3 sourceairport;
+  unsigned stops;
+  string type;
+END;
+/*
+  "travel-sample": {
+  "airline": "AH",
+  "airlineid": "airline_794",
+  "destinationairport": "CDG",
+  "distance": 1420.6731433915318,
+  "equipment": "738",
+  "id": 10041,
+  "schedule": [
+      {
+       "day": 0,
+       "flight": "AH547",
+       "utc": "07:58:00"
+      },
+      {
+       "day": 0,
+       "flight": "AH428",
+       "utc": "12:08:00"
+      },
+      {
+       "day": 1,
+       "flight": "AH444",
+       "utc": "14:16:00"
+      },
+      {
+       "day": 3,
+       "flight": "AH741",
+       "utc": "04:56:00"
+      },
+      {
+       "day": 4,
+       "flight": "AH027",
+       "utc": "03:16:00"
+      },
+      {
+       "day": 4,
+       "flight": "AH113",
+       "utc": "08:11:00"
+      },
+      {
+       "day": 6,
+       "flight": "AH260",
+       "utc": "18:02:00"
+      },
+      {
+       "day": 6,
+       "flight": "AH873",
+       "utc": "03:58:00"
+      }
+     ],
+     "sourceairport": "AAE",
+     "stops": 0,
+     "type": "route"
+    }
+    */
+
+/* Due to inconsistencies found in couchbase travel-sample, some queries explicitly omit records of type landmark and hotel */
+
+integer countAllRecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT count(*) from `travel-sample` as mybucketalias where mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+integer countTypes() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT COUNT(DISTINCT mybucketalias.type) from `travel-sample` as mybucketalias where mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+dataset(typerec) allTypes() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT DISTINCT mybucketalias.type from `travel-sample` as mybucketalias where mybucketalias.type IS NOT NULL and mybucketalias.type != 'landmark' and mybucketalias.type != 'hotel';
+ENDEMBED;
+
+dataset(travelrec) fulltravelrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where callsign = 'MILE-AIR' limit 1;
+ENDEMBED;
+
+dataset(namerec) airlinenames() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.name from `travel-sample` as mybucketalias where mybucketalias.type = 'airline' limit 1;
+ENDEMBED;
+
+dataset(airportrec) airportrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' limit 1;
+ENDEMBED;
+
+dataset(airportrec) usairportrecords() := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and country = 'United States' limit 1;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbycountry(string m) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and country = $m limit 1;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbyid(integer id) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and id = $id limit 1;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbyaltitude(integer alt) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and geo.alt >= $alt limit 1;
+ENDEMBED;
+
+dataset(airportrec) airportrecordsbycoordinates(row(georec) values) := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  select mybucketalias.* from `travel-sample` as mybucketalias where mybucketalias.type = 'airport' and geo.lat = $lat and geo.lon = $lon limit 10;
+ENDEMBED;
+
+dataset(routerec) fullroute()  := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT mybucketalias.* FROM `travel-sample` as mybucketalias WHERE type = 'route' and sourceairport IS NOT NULL LIMIT 1
+ENDEMBED;
+
+dataset(routerec) routeschedule(string sair, string dair)  := EMBED(couchbase : server(server), bucket(thebucket), detailed_errcodes(1), operation_timeout(5.5), config_total_timeout(15))
+  SELECT mybucketalias.schedule  FROM `travel-sample` as mybucketalias WHERE type = 'route' and sourceairport = $sair and destinationairport = $dair  LIMIT 1
+ENDEMBED;
+
+sequential
+(
+  OUTPUT(countAllRecords(), NAMED('CountOfAllRecs'));
+  OUTPUT(countTypes(), NAMED('CountOfAllRecTypes'));
+  OUTPUT(allTypes(), NAMED('AllRecordTypes'));
+  OUTPUT(airlinenames(), NAMED('AirlineNames'));
+  OUTPUT(usairportrecords(), NAMED('USAirports'));
+  OUTPUT(airportrecordsbycountry('"France"'), NAMED('AirportsByCountry'));
+  OUTPUT(fulltravelrecords(), NAMED('FullTravelRec'));
+  OUTPUT(airportrecordsbyid(3411), NAMED('AirportByID'));
+  OUTPUT(airportrecordsbyaltitude(4000), NAMED('AirportsAtAltitude'));
+  OUTPUT(airportrecordsbycoordinates(ROW({0,31.3426028, -109.5064544},georec)), NAMED('AirportAtCoordinate'));
+  //OUTPUT(fullroute(), NAMED('FullRouteRec'));
+  //OUTPUT(routeschedule('"AAE"', '"CDG"'),  NAMED('RouteAAEtoCDG'));
+  OUTPUT('Done', NAMED('Status'));
+);
+

+ 35 - 0
testing/regress/ecl/key/couchbase-simple.xml

@@ -0,0 +1,35 @@
+<Dataset name='CountOfAllRecs'>
+ <Row><CountOfAllRecs>26179</CountOfAllRecs></Row>
+</Dataset>
+<Dataset name='CountOfAllRecTypes'>
+ <Row><CountOfAllRecTypes>3</CountOfAllRecTypes></Row>
+</Dataset>
+<Dataset name='AllRecordTypes'>
+ <Row><type>airline</type></Row>
+ <Row><type>airport</type></Row>
+ <Row><type>route</type></Row>
+</Dataset>
+<Dataset name='AirlineNames'>
+ <Row><name>40-Mile Air</name></Row>
+</Dataset>
+<Dataset name='USAirports'>
+ <Row><airportname>Barter Island Lrrs</airportname><city>Barter Island</city><country>United States</country><faa>BTI</faa><tz>America/Anchorage</tz><type>airport</type><id>3411</id><icao>PABA</icao><geo><alt>2</alt><lat>70.133989</lat><lon>-143.581867</lon></geo></Row>
+</Dataset>
+<Dataset name='AirportsByCountry'>
+ <Row><airportname>Calais Dunkerque</airportname><city>Calais</city><country>France</country><faa>CQF</faa><tz>Europe/Paris</tz><type>airport</type><id>1254</id><icao>LFAC</icao><geo><alt>12</alt><lat>50.962097</lat><lon>1.954764</lon></geo></Row>
+</Dataset>
+<Dataset name='FullTravelRec'>
+ <Row><callsign>MILE-AIR</callsign><country>United States</country><iata>Q5</iata><icao>MLA</icao><id>10</id><name>40-Mile Air</name><type>airline</type></Row>
+</Dataset>
+<Dataset name='AirportByID'>
+ <Row><airportname>Barter Island Lrrs</airportname><city>Barter Island</city><country>United States</country><faa>BTI</faa><tz>America/Anchorage</tz><type>airport</type><id>3411</id><icao>PABA</icao><geo><alt>2</alt><lat>70.133989</lat><lon>-143.581867</lon></geo></Row>
+</Dataset>
+<Dataset name='AirportsAtAltitude'>
+ <Row><airportname>Grants Milan Muni</airportname><city>Grants</city><country>United States</country><faa>GNT</faa><tz>America/Denver</tz><type>airport</type><id>3439</id><icao>KGNT</icao><geo><alt>6537</alt><lat>35.167286</lat><lon>-107.901989</lon></geo></Row>
+</Dataset>
+<Dataset name='AirportAtCoordinate'>
+ <Row><airportname>Douglas Municipal Airport</airportname><city>Douglas</city><country>United States</country><faa>DGL</faa><tz>America/Phoenix</tz><type>airport</type><id>7588</id><icao>KDGL</icao><geo><alt>4173</alt><lat>31.3426028</lat><lon>-109.5064544</lon></geo></Row>
+</Dataset>
+<Dataset name='Status'>
+ <Row><Status>Done</Status></Row>
+</Dataset>

+ 43 - 89
tools/esdlcmd/esdl-publish.cpp

@@ -30,8 +30,6 @@ protected:
     StringAttr optService;
     StringAttr optWSProcAddress;
     StringAttr optWSProcPort;
-    StringAttr optVersionStr;
-    double     optVersion;
     StringAttr optUser;
     StringAttr optPass;
     StringAttr optESDLDefID;
@@ -79,7 +77,6 @@ public:
                 "   --port <port>                WsESDLConfig service port\n"
                 "   -u, --username <name>        Username for accessing WsESDLConfig service\n"
                 "   -pw, --password <pw>         Password for accessing WsESDLConfig service\n"
-                "   --version <ver>              ESDL service version\n"
                 );
         EsdlCmdCommon::usage();
     }
@@ -94,8 +91,6 @@ public:
             return true;
         if (iter.matchFlag(optWSProcPort, ESDL_OPTION_SERVICE_PORT) || iter.matchFlag(optWSProcPort, ESDL_OPT_SERVICE_PORT))
             return true;
-        if (iter.matchFlag(optVersionStr, ESDLOPT_VERSION))
-            return true;
         if (iter.matchFlag(optUser, ESDL_OPT_SERVICE_USER) || iter.matchFlag(optUser, ESDL_OPTION_SERVICE_USER))
             return true;
         if (iter.matchFlag(optPass, ESDL_OPT_SERVICE_PASS) || iter.matchFlag(optPass, ESDL_OPTION_SERVICE_PASS))
@@ -127,7 +122,7 @@ public:
         Owned<IClientPublishESDLDefinitionRequest> request = esdlConfigClient->createPublishESDLDefinitionRequest();
 
         StringBuffer esxml;
-        esdlHelper->getServiceESXDL(optSource.get(), optESDLService.get(), esxml, optVersion);
+        esdlHelper->getServiceESXDL(optSource.get(), optESDLService.get(), esxml, 0);
 
         if (esxml.length()==0)
         {
@@ -152,7 +147,7 @@ public:
             return 1;
         }
 
-        fprintf(stdout, "\nESDL Service: %s(%f): %s", optESDLService.get() ,optVersion, resp->getStatus().getDescription());
+        fprintf(stdout, "\nESDL Service: %s: %s", optESDLService.get(), resp->getStatus().getDescription());
 
         return 0;
     }
@@ -229,19 +224,6 @@ public:
 
     bool finalizeOptions(IProperties *globals)
     {
-        if (!optVersionStr.isEmpty())
-        {
-            optVersion = atof( optVersionStr.get() );
-            if( optVersion <= 0 )
-            {
-                throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
-            }
-        }
-        else
-        {
-            fprintf(stderr, "\nWARNING: ESDL Version not specified.\n");
-        }
-
         if (optSource.isEmpty())
             throw MakeStringException( 0, "Source ESDL definition file (ecm|esdl|xml) must be provided" );
 
@@ -290,12 +272,12 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                //"esdl bind-service <TargetESPProcessName> <TargetESPBindingPort | TargetESPServiceName> <ESDLDefinitionId> <ESDLServiceName> [command options]\n\n"
-                "esdl bind-service <TargetESPProcessName> <TargetESPBindingPort | TargetESPServiceName> <ESDLDefinitionId> <ESDLServiceName> [command options]\n\n"
+                "esdl bind-service <TargetESPProcessName> <TargetESPBindingPort | TargetESPServiceName> <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"
                 "   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"
+                "   ESDLServiceName                                  The Name of the ESDL Service (as defined in the ESDL Definition)"
+                "                                                    *Required if ESDL definition contains multiple services\n"
 
                 "\nOptions (use option flag followed by appropriate value):\n"
                 "   --config <file|\"xml\">                          Configuration XML for all methods associated with the target Service\n"
@@ -306,8 +288,8 @@ public:
         printf( "\n Use this command to publish ESDL Service based bindings.\n"
                 "   To bind an ESDL Service, provide the target ESP process name\n"
                 "   (ESP Process which will host the ESP Service as defined in the ESDL Definition.) \n"
-                "   It is also necessary to provide the Port on which this service is configured to run (ESP Binding),\n"
-                "   and the name of the service you are binding.\n"
+                "   It is also necessary to provide either the Port on which this service is configured to run (ESP Binding),\n"
+                "   or the name of the service you are binding.\n"
                 "   Optionally provide configuration information either directly, or via a\n"
                 "   configuration file in the following syntax:\n"
                 "     <Methods>\n"
@@ -465,22 +447,22 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl unbind-service <TargetESPProcessName> <TargetESPServiceName> [command options]\n\n"
-                "   TargetESPProcessName      The target ESP Process name\n"
-                "   TargetESPServiceName      The target ESP Service name\n"
+                "esdl unbind-service <ESPProcessName> <ESPBindingName> [command options]\n\n"
+                "   ESPProcessName      Name of the ESP Process\n"
+                "   ESPBindingName      Name of the ESP binding\n"
                 "\n\nOptions:\n"
               );
 
         EsdlPublishCmdCommon::usage();
 
-        printf( "\n   Use this command to un-bind ESDL Service based bindings.\n"
-                "   To un-bind an ESDL Service, provide the target ESP process name\n"
-                "   (ESP Process which will host the ESP Service as defined in the ESDL Definition.) \n"
-                "   It is also necessary to provide the name of the service.\n"
+        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"
+                "   Available ESDL bindings to unbind can be found via the '>esdl list-bindings' command."
                 );
 
         printf("\nExample:"
-                ">esdl unbind-service myesp wsmyservice \n"
+                ">esdl unbind-service myesp myservice_binding \n"
                 );
     }
 
@@ -558,12 +540,9 @@ public:
         Owned<IClientWsESDLConfig> esdlConfigClient = EsdlCmdHelper::getWsESDLConfigSoapService(optWSProcAddress, optWSProcPort, optUser, optPass);
         Owned<IClientDeleteESDLDefinitionRequest> request = esdlConfigClient->createDeleteESDLDefinitionRequest();
 
-        fprintf(stdout,"\nAttempting to delete ESDL definition: '%s.%d'\n", optESDLService.get(), (int)optVersion);
+        fprintf(stdout,"\nAttempting to delete ESDL definition: '%s'\n", optESDLDefID.get());
 
-        StringBuffer id;
-        id.setf("%s.%d", optESDLService.get(), (int)optVersion);
-
-        request->setId(id);
+        request->setId(optESDLDefID.get());
 
         Owned<IClientDeleteESDLRegistryEntryResponse> resp = esdlConfigClient->DeleteESDLDefinition(request);
 
@@ -581,18 +560,17 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl delete <ESDLServiceDefinitionName> <ESDLServiceDefinitionVersion> [command options]\n\n"
-                "   ESDLServiceDefinitionName         The name of the ESDL service definition to delete\n"
-                "   ESDLServiceDefinitionVersion      The version of the ESDL service definition to delete\n");
+                "esdl delete <ESDLDefinitionID> [command options]\n\n"
+                "   ESDLDefinitionID      The ESDL definition id <esdldefname>.<esdldefver>\n");
 
         EsdlPublishCmdCommon::usage();
 
         printf( "\n   Use this command to delete an ESDL Service definition.\n"
-                "   To delete an ESDL Service definition, provide the definition name and version\n"
+                "   To delete an ESDL Service definition, provide the ESDL definition id\n"
                 );
 
         printf("\nExample:"
-                ">esdl delete myesdldef 5\n"
+                ">esdl delete myesdldef.5\n"
                 );
     }
 
@@ -604,7 +582,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 != '-')
@@ -612,10 +590,7 @@ public:
                switch (cur)
                {
                 case 0:
-                    optESDLService.set(arg);
-                    break;
-                case 1:
-                    optVersionStr.set(arg);
+                    optESDLDefID.set(arg);
                     break;
                }
            }
@@ -652,19 +627,8 @@ public:
     bool finalizeOptions(IProperties *globals)
     {
 
-        if (optESDLService.isEmpty())
-            throw MakeStringException( 0, "Name of ESDL service definition must be provided!" );
-
-        if (!optVersionStr.isEmpty())
-        {
-            optVersion = atof( optVersionStr.get() );
-            if( optVersion <= 0 )
-            {
-                throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
-            }
-        }
-        else
-            throw MakeStringException( 0, "ESDL service definition version must be provided!" );
+        if (optESDLDefID.isEmpty())
+            throw MakeStringException( 0, "ESDLDefinitionID must be provided!" );
 
         return EsdlPublishCmdCommon::finalizeOptions(globals);
     }
@@ -823,8 +787,7 @@ public:
         request->setEspProcName(optTargetESPProcName);
         request->setEspBindingName(optBindingName);
         request->setEsdlServiceName(optService.get());
-        VStringBuffer id("%s.%d", optService.get(), (int)optVersion);
-        request->setEsdlDefinitionID(id.str());
+        request->setEsdlDefinitionID(optESDLDefID.get());
         request->setConfig(optInput);
         request->setOverwrite(optOverWrite);
 
@@ -847,11 +810,11 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl bind-method <TargetESPProcessName> <TargetESPBindingName> <TargetServiceName> <TargetServiceDefVersion> <TargetMethodName> [command options]\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"
-                "   TargetServiceDefVersion                          The version of the target service ESDL definition (must exist in dali)\n"
+                "   TargetESDLDefinitionID                           The id of the target ESDL definition (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"
@@ -863,7 +826,7 @@ public:
         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 Port on which this service is configured to run (ESP Binding),\n"
+                "   It is also necessary to provide the target ESP binding name,\n"
                 "   and the name of the service you are binding.\n"
                 "   Optionally provide configuration information either directly, or via a\n"
                 "   configuration file in the following syntax:\n"
@@ -874,7 +837,7 @@ public:
                 );
 
         printf("\nExample:"
-                ">esdl bind-service myesp 8088 WsMyService --config /myService/methods.xml\n"
+                ">esdl bind-method myesp mybinding WsMyService WsMyService.1 myMethod --config /myService/methods.xml\n"
                 );
     }
 
@@ -904,7 +867,7 @@ public:
                     optService.set(arg);
                     break;
                 case 3:
-                    optVersionStr.set(arg);
+                    optESDLDefID.set(arg);
                     break;
                 case 4:
                     optMethod.set(arg);
@@ -947,23 +910,15 @@ public:
             }
         }
 
-        if (!optVersionStr.isEmpty())
-        {
-            optVersion = atof( optVersionStr.get() );
-            if( optVersion <= 0 )
-            {
-                throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
-            }
-        }
-        else
-            throw MakeStringException( 0, "ESDL service definition version must be provided!" );
-
         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 (optMethod.isEmpty())
             throw MakeStringException( 0, "Name of ESDL based method must be provided" );
 
@@ -1059,23 +1014,22 @@ public:
     void usage()
     {
         printf( "\nUsage:\n\n"
-                "esdl unbind-method <TargetESPProcessName> <TargetESPBindingName> <TargetServiceName> <TargetMethodName> [\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 ESDLService name associated with the target method\n"
-                "   TargetMethodName                                 The name of the target method (must exist in the service ESDL definition)\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"
+                "   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 un-bind a method, provide the target ESP process name\n"
-                "   (esp which hosts the service.) \n"
-                "   It is also necessary to provide the Port on which this service is configured to run (ESP Binding),\n"
-                "   and the name of the method you are unbinding.\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");
 
 
         printf("\nExample:"
-                ">esdl unbind-method myesp mybinding WsMyService mymethod\n"
+                ">esdl unbind-method myesp myespbinding WsMyService mymethod\n"
                 );
     }
     bool parseCommandLineOptions(ArgvIterator &iter)

+ 2 - 0
tools/esdlcmd/esdlcmd_common.hpp

@@ -62,6 +62,8 @@ typedef IEsdlCommand *(*EsdlCommandFactory)(const char *cmdname);
 #define ESDLOPT_XSLT_PATH               "--xslt"
 
 #define ESDLOPT_VERSION                 "--version"
+#define ESDLOPT_INTERFACE_VERSION       "--interface-version"
+#define ESDLOPT_INTERFACE_VERSION_S     "-iv"
 #define ESDLOPT_SERVICE                 "--service"
 #define ESDLOPT_METHOD                  "--method"
 #define ESDLOPT_PREPROCESS_OUT          "--preprocess-output"

+ 21 - 33
tools/esdlcmd/esdlcmd_core.cpp

@@ -30,7 +30,7 @@
 class Esdl2XSDCmd : public EsdlHelperConvertCmd
 {
 public:
-    Esdl2XSDCmd() : optVersion(0), optAllAnnot(false), optNoAnnot(false),
+    Esdl2XSDCmd() : optInterfaceVersion(0), optAllAnnot(false), optNoAnnot(false),
                     optEnforceOptional(true), optRawOutput(false), optXformTimes(1), optFlags(DEPFLAG_COLLAPSE|DEPFLAG_ARRAYOF),
                     outfileext(".xsd")
     {}
@@ -85,7 +85,7 @@ public:
 
     virtual bool parseCommandLineOption(ArgvIterator &iter)
     {
-        if (iter.matchOption(optVersionStr, ESDLOPT_VERSION))
+        if (iter.matchOption(optInterfaceVersionStr, ESDLOPT_INTERFACE_VERSION) || iter.matchOption(optInterfaceVersionStr, ESDLOPT_INTERFACE_VERSION_S))
             return true;
         if (iter.matchOption(optService, ESDLOPT_SERVICE))
             return true;
@@ -135,10 +135,10 @@ public:
             throw( MakeStringException(0, "A service name must be provided") );
         }
 
-        if (!optVersionStr.isEmpty())
+        if (!optInterfaceVersionStr.isEmpty())
         {
-            optVersion = atof( optVersionStr.get() );
-            if( optVersion <= 0 )
+            optInterfaceVersion = atof( optInterfaceVersionStr.get() );
+            if ( optInterfaceVersion <= 0 )
             {
                 throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
             }
@@ -197,7 +197,7 @@ public:
     virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
     {
         TimeSection ts("transforming via XSLT");
-        cmdHelper.defHelper->toXSD( objs, target, EsdlXslToXsd, optVersion, opts, NULL, optFlags );
+        cmdHelper.defHelper->toXSD( objs, target, EsdlXslToXsd, optInterfaceVersion, opts, NULL, optFlags );
     }
 
     virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
@@ -216,7 +216,7 @@ public:
         loadServiceDef();
         createOptionals();
 
-        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optInterfaceVersion, opts.get(), optFlags );
 
         if( optRawOutput )
         {
@@ -231,7 +231,7 @@ public:
 
             for( unsigned i=0; i < optXformTimes; i++ )
             {
-                doTransform( *structs, outputBuffer, optVersion, opts.get(), NULL, optFlags );
+                doTransform( *structs, outputBuffer, optInterfaceVersion, opts.get(), NULL, optFlags );
             }
 
             outputToFile();
@@ -249,7 +249,7 @@ public:
     void printOptions()
     {
         puts("Options:");
-        puts("  --version <version number> : Constrain to interface version");
+        puts("  -iv,--interface-version <version number> : Constrain to interface version");
         puts("  --method <method name>[;<method name>]* : Constrain to list of specific method(s)" );
         puts("  --xslt <xslt file path> : Path to '/xslt/esxdl2xsd.xslt' file to transform EsdlDef to XSD" );
         puts("  --preprocess-output <raw output directory> : Output pre-processed xml file to specified directory before applying XSLT transform" );
@@ -293,7 +293,7 @@ public:
             StringBuffer empty;
 
             xmlOut.appendf( "<esxdl name=\"%s\">", optService.get());
-            cmdHelper.defHelper->toXML( obj, xmlOut, optVersion, opts.get(), optFlags );
+            cmdHelper.defHelper->toXML( obj, xmlOut, optInterfaceVersion, opts.get(), optFlags );
             xmlOut.append("</esxdl>");
 
             saveAsFile( optPreprocessOutputDir.get(), empty, xmlOut.str(), NULL );
@@ -414,8 +414,8 @@ public:
            ns.append('(').append(ns_optionals.str()).append(')');
         */
 
-       if (optVersion > 0)
-        ns.append("@ver=").appendf("%g", optVersion);
+       if (optInterfaceVersion > 0)
+        ns.append("@ver=").appendf("%g", optInterfaceVersion);
        return ns.toLowerCase();
     }
 
@@ -472,8 +472,8 @@ public:
     StringAttr optTargetNamespace;
     StringAttr optPreprocessOutputDir;
     bool optRawOutput;
-    StringAttr optVersionStr;
-    double optVersion;
+    StringAttr optInterfaceVersionStr;
+    double optInterfaceVersion;
     unsigned int optXformTimes;
     unsigned optFlags;
     bool optNoCollapse;
@@ -523,7 +523,7 @@ public:
     virtual void doTransform(IEsdlDefObjectIterator& objs, StringBuffer &target, double version=0, IProperties *opts=NULL, const char *ns=NULL, unsigned flags=0 )
     {
         TimeSection ts("transforming via XSLT");
-        cmdHelper.defHelper->toWSDL(objs, target, EsdlXslToWsdl, optVersion, opts, NULL, optFlags);
+        cmdHelper.defHelper->toWSDL(objs, target, EsdlXslToWsdl, optInterfaceVersion, opts, NULL, optFlags);
     }
 
     virtual void loadTransform( StringBuffer &xsltpath, IProperties *params)
@@ -542,7 +542,7 @@ public:
         loadServiceDef();
         createOptionals();
 
-        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optVersion, opts.get(), optFlags );
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService.get(), optMethod.get(), ESDLOPTLIST_DELIMITER, optInterfaceVersion, opts.get(), optFlags );
 
         if( optRawOutput )
         {
@@ -556,7 +556,7 @@ public:
 
             for( unsigned i=0; i < optXformTimes; i++ )
             {
-                doTransform( *structs, outputBuffer, optVersion, opts.get(), NULL, optFlags );
+                doTransform( *structs, outputBuffer, optInterfaceVersion, opts.get(), NULL, optFlags );
             }
 
             outputToFile();
@@ -616,7 +616,7 @@ public:
 class Esdl2JavaCmd : public EsdlHelperConvertCmd
 {
 public:
-    Esdl2JavaCmd() : optVersion(0), optFlags(0)
+    Esdl2JavaCmd() : optFlags(0)
     {}
 
     virtual bool parseCommandLineOptions(ArgvIterator &iter)
@@ -668,8 +668,6 @@ public:
 
     virtual bool parseCommandLineOption(ArgvIterator &iter)
     {
-        if (iter.matchOption(optVersionStr, ESDLOPT_VERSION))
-            return true;
         if (iter.matchOption(optService, ESDLOPT_SERVICE))
             return true;
         if (iter.matchOption(optMethod, ESDLOPT_METHOD))
@@ -703,13 +701,6 @@ public:
             throw( MakeStringException(0, "A service name must be provided") );
         }
 
-        if (!optVersionStr.isEmpty())
-        {
-            optVersion = atof( optVersionStr.get() );
-            if( optVersion <= 0 )
-                throw MakeStringException( 0, "Version option must be followed by a real number > 0" );
-        }
-
         if (!optXsltPath.length())
         {
             StringBuffer binXsltPath;
@@ -738,8 +729,8 @@ public:
 
     virtual int processCMD()
     {
-        cmdHelper.loadDefinition(optSource, optService, optVersion);
-        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, optVersion, NULL, optFlags );
+        cmdHelper.loadDefinition(optSource, optService, 0);
+        Owned<IEsdlDefObjectIterator> structs = cmdHelper.esdlDef->getDependencies( optService, optMethod, ESDLOPTLIST_DELIMITER, 0, NULL, optFlags );
 
         if(!optPreprocessOutputDir.isEmpty())
         {
@@ -768,7 +759,6 @@ public:
     void printOptions()
     {
         puts("Options:");
-        puts("  --version <version number> : Constrain to interface version");
         puts("  --method <method name>[;<method name>]* : Constrain to list of specific method(s)" );
         puts("  --xslt <xslt file path> : Path to xslt files used to transform EsdlDef to Java code" );
         puts("  --preprocess-output <raw output directory> : Output pre-processed xml file to specified directory before applying XSLT transform" );
@@ -798,7 +788,7 @@ public:
         StringBuffer xml;
 
         xml.appendf( "<esxdl name='%s'>", optService.get());
-        cmdHelper.defHelper->toXML( obj, xml, optVersion, NULL, optFlags );
+        cmdHelper.defHelper->toXML( obj, xml, 0, NULL, optFlags );
         xml.append("</esxdl>");
         saveAsFile(optPreprocessOutputDir, NULL, xml, NULL );
     }
@@ -836,8 +826,6 @@ public:
     StringAttr optXsltPath;
     StringAttr optMethod;
     StringAttr optPreprocessOutputDir;
-    StringAttr optVersionStr;
-    double optVersion;
     unsigned optFlags;
 
 protected:

+ 5 - 3
tools/esdlcmd/esdlcmd_shell.cpp

@@ -155,7 +155,7 @@ bool EsdlCMDShell::parseCommandLineOptions(ArgvIterator &iter)
             iter.next();
             break;
         }
-        if (iter.matchFlag(boolValue, "--version"))
+        if (iter.matchFlag(boolValue, ESDLOPT_VERSION))
         {
             fprintf(stdout, "%s\n", BUILD_TAG);
             return false;
@@ -180,7 +180,7 @@ bool EsdlCMDShell::parseCommandLineOptions(ArgvIterator &iter)
 void EsdlCMDShell::usage()
 {
     fprintf(stdout,"\nUsage:\n"
-        "    esdl [--version] <command> [<args>]\n\n"
+        "    esdl <command> [<args>]\n\n"
            "Commonly used commands:\n"
            "   xml               Generate XML from ESDL definition.\n"
            "   ecl               Generate ECL from ESDL definition.\n"
@@ -188,6 +188,7 @@ void EsdlCMDShell::usage()
            "   wsdl              Generate WSDL from ESDL definition.\n"
            "   publish           Publish ESDL Definition for ESP use.\n"
            "   list-definitions  List all ESDL definitions.\n"
+           "   get-definition    Get ESDL definition.\n"
            "   delete            Delete ESDL Definition.\n"
            "   bind-service      Configure ESDL based service on target ESP (with existing ESP Binding).\n"
            "   list-bindings     List all ESDL bindings.\n"
@@ -198,6 +199,7 @@ void EsdlCMDShell::usage()
            "   monitor           Generate ECL code for result monitoring / differencing\n"
            "   monitor-template  Generate a template for use with 'monitor' command\n"
            ""
-           "\nRun 'esdl help <command>' for more information on a specific command\n\n"
+           "\nRun 'esdl help <command>' for more information on a specific command\n"
+           "\nRun 'esdl --version' to get version information\n\n"
     );
 }

+ 20 - 0
tools/esdlcomp/esdlcomp.h

@@ -1087,6 +1087,13 @@ public:
             tags = p->next;
             delete p;
         }
+
+        if (name_)
+           free(name_);
+        if (request_)
+           free(request_);
+        if (response_)
+           free(response_);
     }
 
     const char *getName(){return name_;}
@@ -1164,6 +1171,13 @@ public:
         tags=NULL;
         next=NULL;
     }
+    ~EspMountInfo()
+    {
+       if (name_)
+          free(name_);
+       if (localPath_)
+          free(localPath_);
+    }
 
     const char *getName(){return name_;}
     void setName(const char *name)
@@ -1219,6 +1233,12 @@ public:
         next=NULL;
     }
 
+    ~EspStructInfo()
+    {
+       if (name_)
+          free(name_);
+    }
+
     const char *getName(){return name_;}
     void setName(const char *name)
     {