diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml
index e506522..3ff3e70 100644
--- a/.github/workflows/github-actions.yml
+++ b/.github/workflows/github-actions.yml
@@ -1,13 +1,13 @@
name: github-actions
on: [push, pull_request]
jobs:
- windows-2019:
- runs-on: windows-2019
+ windows-2022:
+ runs-on: windows-2022
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Boost install
run: |
- (New-Object System.Net.WebClient).DownloadFile("https://archives.boost.io/release/1.87.0/binaries/boost_1_87_0-msvc-14.2-64.exe", "${{ runner.temp }}\boost.exe")
+ (New-Object System.Net.WebClient).DownloadFile("https://archives.boost.io/release/1.88.0/binaries/boost_1_88_0-msvc-14.2-64.exe", "${{ runner.temp }}\boost.exe")
Start-Process -Wait -FilePath "${{ runner.temp }}\boost.exe" "/SILENT","/SP-","/SUPPRESSMSGBOXES","/DIR=${{ runner.temp }}\boost-install"
- name: AVRO install
run: |
@@ -19,7 +19,7 @@ jobs:
cd ${{ runner.temp }}
mkdir avro-cpp-build
cd avro-cpp-build
- cmake -G"Visual Studio 16 2019" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/avro-cpp-install ${{ runner.temp }}/avro-cpp-1.11.3
+ cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/avro-cpp-install ${{ runner.temp }}/avro-cpp-1.11.3
cmake --build . --config Release --target avrocpp_s -j2
cmake --install .
- name: CMake build and install
@@ -27,15 +27,15 @@ jobs:
cd ${{ github.workspace }}/..
mkdir build
cd build
- cmake -G"Visual Studio 16 2019" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_ETP_SSL=FALSE ${{ github.workspace }}
+ cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_ETP_SSL=FALSE ${{ github.workspace }}
cmake --build . --config Release -j2
- windows-2019-with-fesapi:
- runs-on: windows-2019
+ windows-2022-with-fesapi:
+ runs-on: windows-2022
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Boost install
run: |
- (New-Object System.Net.WebClient).DownloadFile("https://archives.boost.io/release/1.87.0/binaries/boost_1_87_0-msvc-14.2-64.exe", "${{ runner.temp }}\boost.exe")
+ (New-Object System.Net.WebClient).DownloadFile("https://archives.boost.io/release/1.88.0/binaries/boost_1_88_0-msvc-14.2-64.exe", "${{ runner.temp }}\boost.exe")
Start-Process -Wait -FilePath "${{ runner.temp }}\boost.exe" "/SILENT","/SP-","/SUPPRESSMSGBOXES","/DIR=${{ runner.temp }}\boost-install"
- name: AVRO install
run: |
@@ -47,24 +47,24 @@ jobs:
cd ${{ runner.temp }}
mkdir avro-cpp-build
cd avro-cpp-build
- cmake -G"Visual Studio 16 2019" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/avro-cpp-install ${{ runner.temp }}/avro-cpp-1.11.3
+ cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/avro-cpp-install ${{ runner.temp }}/avro-cpp-1.11.3
cmake --build . --config Release --target avrocpp_s -j2
cmake --install .
- name: FESAPI install
run: |
- (New-Object System.Net.WebClient).DownloadFile("https://github.com/F2I-Consulting/fesapi/releases/download/v2.12.1.0/fesapi2_12_1_0-cpp-vs2019-x64.zip", "${{ runner.temp }}\fesapi.zip")
+ (New-Object System.Net.WebClient).DownloadFile("https://github.com/F2I-Consulting/fesapi/releases/download/v2.14.0.0/fesapi2_14_0_0-cpp-vs2019-x64.zip", "${{ runner.temp }}\fesapi.zip")
7z x ${{ runner.temp }}\fesapi.zip -o${{ runner.temp }}
- name: CMake build and install
run: |
cd ${{ github.workspace }}/..
mkdir build
cd build
- cmake -G"Visual Studio 16 2019" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_FESAPI=TRUE -DFESAPI_ROOT=${{ runner.temp }}/fesapi2_12_1_0-cpp-vs2019-x64 -DWITH_ETP_SSL=FALSE ${{ github.workspace }}
+ cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DBoost_INCLUDE_DIR=${{ runner.temp }}\boost-install -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_FESAPI=TRUE -DFESAPI_ROOT=${{ runner.temp }}/fesapi2_14_0_0-cpp-vs2019-x64 -DWITH_ETP_SSL=FALSE ${{ github.workspace }}
cmake --build . --config Release -j2
ubuntu-22:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: APT install
run: |
sudo apt update
@@ -91,8 +91,8 @@ jobs:
ubuntu-22-java11:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v5
+ - uses: actions/setup-java@v5
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '11'
@@ -137,8 +137,8 @@ jobs:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v4
+ - uses: actions/checkout@v5
+ - uses: actions/setup-java@v5
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '11'
@@ -148,13 +148,16 @@ jobs:
sudo apt install -y ${{ matrix.xcc_pkg }} libhdf5-dev libminizip-dev libboost-all-dev
- name: FESAPI install
run: |
- git clone --branch v2.12.1.0 --single-branch https://github.com/F2I-Consulting/fesapi.git ${{ runner.temp }}/fesapi-src
+ git clone --branch v2.14.0.0 --single-branch https://github.com/F2I-Consulting/fesapi.git ${{ runner.temp }}/fesapi-src
cd ${{ runner.temp }}
mkdir fesapi-build
cd fesapi-build
cmake -DMINIZIP_INCLUDE_DIR=/usr/include/minizip -DMINIZIP_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libminizip.so.1.0.0 -DCMAKE_BUILD_TYPE=Release -DWITH_JAVA_WRAPPING=TRUE -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/fesapi-install -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} ${{ runner.temp }}/fesapi-src
cmake --build . -j2
cmake --install .
+ mkdir -p ${{ runner.temp }}/fesapi-install/include/fesapi
+ cd ${{ runner.temp }}/fesapi-src/src
+ find . -name "*.h" -exec cp --parents \{\} ${{ runner.temp }}/fesapi-install/include/fesapi/ \;
- name: AVRO INSTALL
run: |
curl https://archive.apache.org/dist/avro/avro-1.11.3/cpp/avro-cpp-1.11.3.tar.gz -o ${{ runner.temp }}/avro-cpp-1.11.3.tar.gz
@@ -172,31 +175,31 @@ jobs:
cd ${{ github.workspace }}/..
mkdir build
cd build
- cmake -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_FESAPI=TRUE -DFESAPI_ROOT=${{ runner.temp }}/fesapi-install -DFESAPI_JAR=${{ runner.temp }}/fesapi-install/lib/fesapiJava-2.12.1.0.jar -DWITH_JAVA_WRAPPING=TRUE ${{ github.workspace }} -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }}
+ cmake -DAVRO_ROOT=${{ runner.temp }}/avro-cpp-install -DAVRO_USE_STATIC_LIBS=TRUE -DWITH_FESAPI=TRUE -DFESAPI_ROOT=${{ runner.temp }}/fesapi-install -DFESAPI_JAR=${{ runner.temp }}/fesapi-install/lib/fesapiJava-2.14.0.0.jar -DWITH_JAVA_WRAPPING=TRUE ${{ github.workspace }} -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }}
cmake --build . --config Release -j2
build_wheels_windows:
name: Build wheels on windows-latest
runs-on: windows-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Stub `setup.py` check
# It will be generated during CMake run
# https://github.com/pypa/cibuildwheel/issues/1139
run: touch python/setup.py
- name: Build wheels
- uses: pypa/cibuildwheel@v2.21.3
+ uses: pypa/cibuildwheel@v3.2.1
env:
CIBW_BUILD: cp38-win_amd64 cp39-win_amd64 cp310-win_amd64 cp311-win_amd64 cp312-win_amd64 cp313-win_amd64
CIBW_ARCHS: auto64
CIBW_BEFORE_ALL: >
%VCPKG_INSTALLATION_ROOT%\vcpkg install boost-uuid minizip hdf5[zlib] &&
cd ${{ runner.temp }} &&
- powershell -Command "(New-Object System.Net.WebClient).DownloadFile('https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.12.1.0.tar.gz', '${{ runner.temp }}\fesapi-2.12.1.0.tar.gz')" &&
- 7z x ${{ runner.temp }}\fesapi-2.12.1.0.tar.gz -o${{ runner.temp }} &&
- 7z x ${{ runner.temp }}\fesapi-2.12.1.0.tar -o${{ runner.temp }} &&
+ powershell -Command "(New-Object System.Net.WebClient).DownloadFile('https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.14.0.0.tar.gz', '${{ runner.temp }}\fesapi-2.14.0.0.tar.gz')" &&
+ 7z x ${{ runner.temp }}\fesapi-2.14.0.0.tar.gz -o${{ runner.temp }} &&
+ 7z x ${{ runner.temp }}\fesapi-2.14.0.0.tar -o${{ runner.temp }} &&
mkdir fesapi-build &&
cd fesapi-build &&
- cmake -DCMAKE_TOOLCHAIN_FILE=%VCPKG_INSTALLATION_ROOT%\scripts\buildsystems\vcpkg.cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/fesapi-install ${{ runner.temp }}\fesapi-2.12.1.0 &&
+ cmake -DCMAKE_TOOLCHAIN_FILE=%VCPKG_INSTALLATION_ROOT%\scripts\buildsystems\vcpkg.cmake -G"Visual Studio 17 2022" -A x64 -T host=x64 -Wno-dev -Wno-deprecated -DCMAKE_INSTALL_PREFIX=${{ runner.temp }}/fesapi-install ${{ runner.temp }}\fesapi-2.14.0.0 &&
cmake --build . --config Release -j2 &&
cmake --build . --config Release --target INSTALL &&
%VCPKG_INSTALLATION_ROOT%\vcpkg install openssl boost-beast avro-cpp &&
@@ -221,13 +224,14 @@ jobs:
name: Build wheels on ubuntu-latest
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Stub `setup.py` check
# It will be generated during CMake run
# https://github.com/pypa/cibuildwheel/issues/1139
run: touch python/setup.py
- name: Build wheels
- uses: pypa/cibuildwheel@v2.21.3
+ # Above cibuildwheel@v2.22.0, GNU 14 is most likely used instead of GNU 12 or 13 which makes AVRO 1.11.3 not compiling
+ uses: pypa/cibuildwheel@v2.22.0
env:
CIBW_BUILD: cp38-manylinux_* cp39-manylinux_* cp310-manylinux_* cp311-manylinux_* cp312-manylinux_* cp313-manylinux_*
CIBW_ARCHS: auto64
@@ -239,11 +243,11 @@ jobs:
yum install -y epel-release &&
yum --enablerepo=epel install -y minizip1.2-devel hdf5-devel cmake3 &&
cd / &&
- wget https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.12.1.0.zip &&
- unzip v2.12.1.0.zip &&
+ wget https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.14.0.0.zip &&
+ unzip v2.14.0.0.zip &&
mkdir fesapi-build &&
cd fesapi-build &&
- cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:STRING=/fesapi-install /fesapi-2.12.1.0 &&
+ cmake3 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:STRING=/fesapi-install /fesapi-2.14.0.0 &&
cmake3 --build . -j2 --config Release &&
cmake3 --install . &&
cd / &&
@@ -277,13 +281,13 @@ jobs:
name: Build wheels on macos-14
runs-on: macos-14
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Stub `setup.py` check
# It will be generated during CMake run
# https://github.com/pypa/cibuildwheel/issues/1139
run: touch python/setup.py
- name: Build wheels
- uses: pypa/cibuildwheel@v2.21.3
+ uses: pypa/cibuildwheel@v3.2.1
env:
CIBW_BUILD: cp38-macosx_* cp39-macosx_* cp310-macosx_* cp311-macosx_* cp312-macosx_* cp313-macosx_*
CIBW_ARCHS: auto64
@@ -312,11 +316,11 @@ jobs:
cmake --build . -j2 --config Release &&
cmake --install . &&
cd ${{ github.workspace }}/.. &&
- wget --no-verbose https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.12.1.0.zip &&
- unzip v2.12.1.0.zip &&
+ wget --no-verbose https://github.com/F2I-Consulting/fesapi/archive/refs/tags/v2.14.0.0.zip &&
+ unzip v2.14.0.0.zip &&
mkdir fesapi-build &&
cd fesapi-build &&
- cmake -DCMAKE_BUILD_TYPE=Release -DBOOST_ROOT=${{ github.workspace }}/../boost-install -DMINIZIP_ROOT=${{ github.workspace }}/../minizip-install -DHDF5_ROOT=${{ github.workspace }}/../hdf5-install -DHDF5_USE_STATIC_LIBRARIES=TRUE -DCMAKE_INSTALL_PREFIX:STRING=${{ github.workspace }}/../fesapi-install ${{ github.workspace }}/../fesapi-2.12.1.0 &&
+ cmake -DCMAKE_BUILD_TYPE=Release -DBOOST_ROOT=${{ github.workspace }}/../boost-install -DMINIZIP_ROOT=${{ github.workspace }}/../minizip-install -DHDF5_ROOT=${{ github.workspace }}/../hdf5-install -DHDF5_USE_STATIC_LIBRARIES=TRUE -DCMAKE_INSTALL_PREFIX:STRING=${{ github.workspace }}/../fesapi-install ${{ github.workspace }}/../fesapi-2.14.0.0 &&
cmake --build . -j2 --config Release &&
cmake --install . &&
cd ${{ github.workspace }}/.. &&
@@ -329,6 +333,8 @@ jobs:
cd ${{ github.workspace }}/.. &&
wget --no-verbose https://archive.apache.org/dist/avro/avro-1.11.3/cpp/avro-cpp-1.11.3.tar.gz &&
tar xf avro-cpp-1.11.3.tar.gz &&
+ sed -i '' 's/cmake_minimum_required (VERSION 3.1)/cmake_minimum_required (VERSION 3.5)/' avro-cpp-1.11.3/CMakeLists.txt &&
+ sed -i '' 's/if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.0)/if (APPLE)/' avro-cpp-1.11.3/CMakeLists.txt &&
sed -i '' 's/install (TARGETS avrocpp avrocpp_s/install (TARGETS avrocpp_s/' avro-cpp-1.11.3/CMakeLists.txt &&
sed -i '' 's/install (TARGETS avrogencpp RUNTIME DESTINATION bin)//' avro-cpp-1.11.3/CMakeLists.txt &&
mkdir avro-build &&
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7ba54a..d2b79bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,8 +15,8 @@ set (FETPAPI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# version mechanism
set (Fetpapi_VERSION_MAJOR 0)
-set (Fetpapi_VERSION_MINOR 3)
-set (Fetpapi_VERSION_PATCH 1)
+set (Fetpapi_VERSION_MINOR 4)
+set (Fetpapi_VERSION_PATCH 0)
set (Fetpapi_VERSION_TWEAK 0)
set (Fetpapi_VERSION ${Fetpapi_VERSION_MAJOR}.${Fetpapi_VERSION_MINOR}.${Fetpapi_VERSION_PATCH}.${Fetpapi_VERSION_TWEAK})
@@ -200,7 +200,6 @@ set (ALL_SOURCES_AND_HEADERS
${FETPAPI_HEADERS}
${FETPAPI_PROTOCOL_SOURCES}
${FETPAPI_PROTOCOL_HEADERS}
- ${FETPAPI_TOOLS_HEADERS}
${FETPAPI_FESAPI_SOURCES}
${FETPAPI_FESAPI_HEADERS}
${FETPAPI_SSL_SOURCES}
@@ -224,8 +223,6 @@ target_include_directories(${PROJECT_NAME} INTERFACE
# organizing sources and headers in the Visual Studio Project
if (WIN32)
- source_group ("tools" FILES ${FETPAPI_TOOLS_HEADERS})
-
set (ETP_PREFIX "etp")
source_group ("${ETP_PREFIX}" FILES ${FETPAPI_SOURCES} ${FETPAPI_HEADERS})
source_group ("${ETP_PREFIX}\\ProtocolHandlers" FILES ${FETPAPI_PROTOCOL_SOURCES} ${FETPAPI_PROTOCOL_HEADERS})
@@ -307,12 +304,6 @@ INSTALL (
COMPONENT fetpapi_headers
)
-INSTALL (
- FILES ${FETPAPI_TOOLS_HEADERS}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fetpapi/tools
- COMPONENT fetpapi_headers
-)
-
if (WITH_ETP_SSL)
INSTALL (
FILES ${FETPAPI_SSL_HEADERS}
diff --git a/README.md b/README.md
index e75b4d1..4142656 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
Download (build and install if necessary) third party libraries:
- BOOST : All versions from version 1.66 should be ok but you may experience some [min/max build issues](https://github.com/boostorg/beast/issues/1980) using version 1.72 or 1.73.
- AVRO : https://avro.apache.org/releases.html#Download (starting from version 1.9.0 [except 1.11.1](https://issues.apache.org/jira/browse/AVRO-3601), build it with the above boost library.)
-- (OPTIONALLY) OpenSSL : version 1.1 is known to work.
+- (OPTIONALLY) OpenSSL : version 3.4 is known to work.
- (OPTIONALLY) [FESAPI](https://github.com/F2I-Consulting/fesapi/releases) : All versions from version 2.7.0.0 should be ok but a minimal version of 2.11.0.0 is recommended to automatically recognize FESAPI CMake Variables using CMake find Module and build silently the EtpClient example.
# Configure the build
diff --git a/cmake/FetpapiClientUsingFesapi.java b/cmake/FetpapiClientUsingFesapi.java
index a5effb6..0a05e70 100644
--- a/cmake/FetpapiClientUsingFesapi.java
+++ b/cmake/FetpapiClientUsingFesapi.java
@@ -16,7 +16,7 @@ Licensed to the Apache Software Foundation (ASF) under one
specific language governing permissions and limitations
under the License.
-----------------------------------------------------------------------*/
-package com.f2i_consulting.fetpapi.client;
+package com.f2i_consulting.example;
import java.util.Optional;
import java.util.UUID;
diff --git a/cmake/fetpapiCsWithFesapi.csproj.template b/cmake/fetpapiCsWithFesapi.csproj.template
index 327f39f..8025923 100644
--- a/cmake/fetpapiCsWithFesapi.csproj.template
+++ b/cmake/fetpapiCsWithFesapi.csproj.template
@@ -10,7 +10,11 @@
Properties
F2iConsulting.Fetpapi
${CS_LIBRARY_NAME}
+
+
+ v4.8
512
diff --git a/cmake/fetpapiCsWithoutFesapi.csproj.template b/cmake/fetpapiCsWithoutFesapi.csproj.template
index 3b01749..d98085a 100644
--- a/cmake/fetpapiCsWithoutFesapi.csproj.template
+++ b/cmake/fetpapiCsWithoutFesapi.csproj.template
@@ -10,7 +10,11 @@
Properties
F2iConsulting.Fetpapi
${CS_LIBRARY_NAME}
+
+
+ v4.8
512
diff --git a/cmake/pyproject.toml.in b/cmake/pyproject.toml.in
index c8fd895..ffe9606 100644
--- a/cmake/pyproject.toml.in
+++ b/cmake/pyproject.toml.in
@@ -16,7 +16,6 @@ readme = "README.md"
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
- 'License :: OSI Approved :: Apache Software License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS',
@@ -29,9 +28,10 @@ classifiers=[
'Programming Language :: Python :: 3.12',
'Topic :: Software Development',
'Topic :: Software Development :: Libraries',
- 'Topic :: Software Development :: Libraries :: Application Frameworks ',
+ 'Topic :: Software Development :: Libraries :: Application Frameworks',
'Topic :: File Formats',
]
+license = {text = "Apache-2.0"}
keywords = [
"energistics",
"resqml",
@@ -43,7 +43,7 @@ keywords = [
]
requires-python = ">=3.8"
dependencies = [
- 'fesapi==2.12.1',
+ 'fesapi==2.14.0',
]
[project.urls]
diff --git a/cmake/swigEtp1_2Include.i.in b/cmake/swigEtp1_2Include.i.in
index 6b01bb5..8f99e3a 100644
--- a/cmake/swigEtp1_2Include.i.in
+++ b/cmake/swigEtp1_2Include.i.in
@@ -32,6 +32,7 @@ under the License.
#ifdef WITH_FESAPI
%include "${FESAPI_INCLUDE_DIR}/fesapi/nsDefinitions.h"
%import(module="fesapi") "${FESAPI_INCLUDE_DIR}/fesapi/common/DataObjectReference.h"
+%import(module="fesapi") "${FESAPI_INCLUDE_DIR}/fesapi/common/DataObjectRepository.h"
%import(module="fesapi") "${FESAPI_INCLUDE_DIR}/fesapi/common/HdfProxyFactory.h"
%import(module="fesapi") "${FESAPI_INCLUDE_DIR}/fesapi/common/AbstractObject.h"
#endif
@@ -298,7 +299,7 @@ typedef long long time_t;
%include "std_array.i"
%typemap(javaimports) SWIGTYPE %{
- import com.f2i_consulting.fetpapi.*;
+import com.f2i_consulting.fetpapi.*;
%}
namespace Energistics {
@@ -376,22 +377,22 @@ namespace Energistics {
std::string get_string();
void set_string(const std::string& v);
- Energistics::Etp::v12::Datatypes::ArrayOfBoolean get_ArrayOfBoolean();
+ Energistics::Etp::v12::Datatypes::ArrayOfBoolean const& get_ArrayOfBoolean() const;
void set_ArrayOfBoolean(const Energistics::Etp::v12::Datatypes::ArrayOfBoolean& v);
- Energistics::Etp::v12::Datatypes::ArrayOfInt get_ArrayOfInt();
+ Energistics::Etp::v12::Datatypes::ArrayOfInt const& get_ArrayOfInt() const;
void set_ArrayOfInt(const Energistics::Etp::v12::Datatypes::ArrayOfInt& v);
- Energistics::Etp::v12::Datatypes::ArrayOfLong get_ArrayOfLong();
+ Energistics::Etp::v12::Datatypes::ArrayOfLong const& get_ArrayOfLong() const;
void set_ArrayOfLong(const Energistics::Etp::v12::Datatypes::ArrayOfLong& v);
- Energistics::Etp::v12::Datatypes::ArrayOfFloat get_ArrayOfFloat();
+ Energistics::Etp::v12::Datatypes::ArrayOfFloat const& get_ArrayOfFloat() const;
void set_ArrayOfFloat(const Energistics::Etp::v12::Datatypes::ArrayOfFloat& v);
- Energistics::Etp::v12::Datatypes::ArrayOfDouble get_ArrayOfDouble();
+ Energistics::Etp::v12::Datatypes::ArrayOfDouble const& get_ArrayOfDouble() const;
void set_ArrayOfDouble(const Energistics::Etp::v12::Datatypes::ArrayOfDouble& v);
- Energistics::Etp::v12::Datatypes::ArrayOfString get_ArrayOfString();
+ Energistics::Etp::v12::Datatypes::ArrayOfString const& get_ArrayOfString() const;
void set_ArrayOfString(const Energistics::Etp::v12::Datatypes::ArrayOfString& v);
std::string get_bytes();
@@ -411,25 +412,25 @@ namespace Energistics {
public:
size_t idx() const;
- Energistics::Etp::v12::Datatypes::ArrayOfBoolean get_ArrayOfBoolean();
+ Energistics::Etp::v12::Datatypes::ArrayOfBoolean const& get_ArrayOfBoolean() const;
void set_ArrayOfBoolean(const Energistics::Etp::v12::Datatypes::ArrayOfBoolean& v);
- Energistics::Etp::v12::Datatypes::ArrayOfInt get_ArrayOfInt();
+ Energistics::Etp::v12::Datatypes::ArrayOfInt const& get_ArrayOfInt() const;
void set_ArrayOfInt(const Energistics::Etp::v12::Datatypes::ArrayOfInt& v);
- Energistics::Etp::v12::Datatypes::ArrayOfLong get_ArrayOfLong();
+ Energistics::Etp::v12::Datatypes::ArrayOfLong const& get_ArrayOfLong() const;
void set_ArrayOfLong(const Energistics::Etp::v12::Datatypes::ArrayOfLong& v);
- Energistics::Etp::v12::Datatypes::ArrayOfFloat get_ArrayOfFloat();
+ Energistics::Etp::v12::Datatypes::ArrayOfFloat const& get_ArrayOfFloat() const;
void set_ArrayOfFloat(const Energistics::Etp::v12::Datatypes::ArrayOfFloat& v);
- Energistics::Etp::v12::Datatypes::ArrayOfDouble get_ArrayOfDouble();
+ Energistics::Etp::v12::Datatypes::ArrayOfDouble const& get_ArrayOfDouble() const;
void set_ArrayOfDouble(const Energistics::Etp::v12::Datatypes::ArrayOfDouble& v);
- Energistics::Etp::v12::Datatypes::ArrayOfString get_ArrayOfString();
+ Energistics::Etp::v12::Datatypes::ArrayOfString const& get_ArrayOfString() const;
void set_ArrayOfString(const Energistics::Etp::v12::Datatypes::ArrayOfString& v);
- std::string get_bytes();
+ std::string const& get_bytes() const;
void set_bytes(const std::string& v);
};
@@ -1267,10 +1268,9 @@ namespace Energistics {
}
%fragment("data_array_handler_reference_function", "header", fragment="data_array_handler_reference_init") {
-
- static PyObject *data_array_handler_reference() {
- static PyObject *data_array_handler_reference_string = SWIG_Python_str_FromChar("__data_array_handler_reference");
- return data_array_handler_reference_string;
+ static PyObject *data_array_handler_reference() {
+ static PyObject *data_array_handler_reference_string = SWIG_Python_str_FromChar("__data_array_handler_reference");
+ return data_array_handler_reference_string;
}
}
@@ -1639,17 +1639,7 @@ namespace ETP_NS
void setDataspaceProtocolHandlers(std::shared_ptr dataspaceHandlers);
void setDataspaceOSDUProtocolHandlers(std::shared_ptr dataspaceOSDUHandlers);
- template int64_t sendWithSpecificHandler(const T & mb, std::shared_ptr specificHandler, int64_t correlationId = 0, int32_t messageFlags = 0)
- {
- int64_t msgId = encode(mb, correlationId, messageFlags); // put the message to write in the queue
-
- if (sendingQueue.size() == 1) {
- do_write();
- }
- specificProtocolHandlers[msgId] = specificHandler;
-
- return msgId;
- }
+ template int64_t sendWithSpecificHandler(const T & mb, std::shared_ptr specificHandler, int64_t correlationId = 0, int32_t messageFlags = 0) {}
%template(sendWithSpecificHandler) sendWithSpecificHandler;
%template(sendWithSpecificHandler) sendWithSpecificHandler;
%template(sendWithSpecificHandler) sendWithSpecificHandler;
@@ -1724,15 +1714,7 @@ namespace ETP_NS
%template(sendWithSpecificHandler) sendWithSpecificHandler;
%template(sendWithSpecificHandler) sendWithSpecificHandler;
- template int64_t send(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0)
- {
- if (protocolHandlers.size() > mb.protocolId) {
- return sendWithSpecificHandler(mb, protocolHandlers[mb.protocolId], correlationId, messageFlags);
- }
- else {
- throw std::logic_error("The agent has no registered handler at all for the protocol " + std::to_string(mb.protocolId));
- }
- }
+ template int64_t send(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0) {}
%template(send) send;
%template(send) send;
%template(send) send;
@@ -1807,12 +1789,7 @@ namespace ETP_NS
%template(send) send;
%template(send) send;
- template void sendAndBlock(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0)
- {
- int64_t msgId = send(mb, correlationId, messageFlags);
- while (isMessageStillProcessing(msgId)) {}
- }
-
+ template int64_t sendAndBlock(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0) {}
%template(sendAndBlock) sendAndBlock;
%template(sendAndBlock) sendAndBlock;
%template(sendAndBlock) sendAndBlock;
@@ -1966,37 +1943,38 @@ namespace ETP_NS
std::vector getDataspaceInfo(const std::map& dataspaceUris);
/**
- * Copy by reference some dataspaces into another one.
+ * A customer sends to a store to lock or unlock one or more dataspaces.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
+ * An OSDU locked dataspace will have its custom data "locked" to true. It will also have its custom datm "read-only" to true for all users.
+ * As a reminder, a custom data "read-only" can be true with a custom data "locked" to false in case the dataspace is not locked but in read only for the particular current ETP user.
*
- * @param sourceDataspaceUris ETP general map : One each for each source dataspace to be copied. They are identified by their URI.
- * @param targetDataspaceUri The URI of the ETP dataspace where the sourceDataspaces have to be copied by reference.
- * @param return The map keys corresponding to the dataspaces which have been successfully copied into the target dataspace.
+ * @param dataspaceUris ETP general map where the values must be the URIs for the dataspaces the customer wants to lock or unlock.
+ * @param lock true for locking the dataspaces, false to unlock the dataspaces
*/
- std::vector copyDataspacesContent(const std::map& sourceDataspaceUris, const std::string& targetDataspaceUri);
+ std::vector lockDataspaces(const std::map& dataspaceUris, bool lock);
/**
- * A customer sends to a store to lock or unlock one or more dataspaces.
+ * Copy by reference some dataspaces into another one.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
- * @param dataspaceUris ETP general map where the values must be the URIs for the dataspaces the customer wants to lock or unlock.
- * @param lock true for locking the dataspaces, false to unlock the dataspaces
- * @param return The map keys corresponding to the dataspaces which have been successfully locked or unlocked.
+ * @param sourceDataspaceUris ETP general map : One each for each source dataspace to be copied. They are identified by their URI.
+ * @param targetDataspaceUri The URI of the ETP dataspace where the sourceDataspaces have to be copied by reference.
+ * @param return The map keys corresponding to the dataspaces which have been successfully copied into the target dataspace.
*/
- std::vector lockDataspaces(const std::map& dataspaceUris, bool lock);
+ std::vector copyDataspacesContent(const std::map& sourceDataspaceUris, const std::string& targetDataspaceUri);
/**
* Copy by reference some dataobjects into another dataspace.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
- * @param sourceUris ETP general map : One each for each source dataobject to be copied. They are identified by their URI.
- * @param targetDataspaceUri The URI of the ETP dataspace where the source dataobjects have to be copied by reference.
- * @param return The map keys corresponding to the dataobjects which have been successfully copied into the target dataspace.
+ * @param sourceDataobjectUris ETP general map : One for each source dataobject to be copied. They are identified by their URI.
+ * @param targetDataspaceUri The URI of the ETP dataspace where the source dataobjects have to be copied by reference.
+ * @param return The map keys corresponding to the dataobjects which have been successfully copied into the target dataspace.
*/
- std::vector copyToDataspace(const std::map& sourceUris, const std::string& targetDataspaceUri);
+ std::vector copyToDataspace(const std::map& sourceDataobjectUris, const std::string& targetDataspaceUri);
/****************
*** DISCOVERY ***
@@ -2074,6 +2052,26 @@ namespace ETP_NS
*/
std::vector deleteDataObjects(const std::map& uris);
+ /*********************
+ ***** STORE OSDU *****
+ **********************/
+
+ /**
+ * A customer sends to a store to copy by value a dataobject in the same dataspace with potentially some of its sources based on their datatypes.
+ * This function should be used with caution if Store OSDU Handlers have been overidden.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
+ *
+ * @param sourceDataobjectUri The URI of the dataobject to be copied.
+ * @param sourcesDepth The "depth" or how many "levels" (or "jumps") in the data model (graph) from the starting point (specified by the URI) that you want to copy
+ * Depth MUST always be greater than zero.
+ * @param dataObjectTypes Optionally, specify the types of data objects that you want to copy.
+ * The default is an empty array, which means ALL data types negotiated for the current ETP session.
+ * They ARE case sensitive. EXAMPLES: "witsml20.Well", "witsml20.Wellbore", "prodml21.WellTest", "resqml20.obj_TectonicBoundaryFeature", "eml21.DataAssuranceRecord"
+ * To indicate that all data objects within a data schema version are supported, you can use a star (*) as a wildcard, EXAMPLE: "witsml20.*", "prodml21.*", "resqml20.*"
+ * @param return The received dataobjects in a map where the key makes the link between the asked uris and the received dataobjects.
+ */
+ std::vector copyDataObjectsByValue(const std::string& sourceDataobjectUri, int32_t sourcesDepth = 0, const std::vector& dataObjectTypes = {});
+
/****************
** TRANSACTION **
****************/
@@ -2131,19 +2129,14 @@ namespace ETP_NS
std::string getDataspaceUri(const std::string& uri);
/**
- * @param session Provide this parameter if you want to send a protocol exception in case of non validation.
- */
- Energistics::Etp::v12::Datatypes::ErrorInfo validateUri(const std::string & uri, ETP_NS::AbstractSession* session = nullptr);
-
- /**
- * @param session Provide this parameter if you want to send a protocol exception in case of non validation.
+ * Validate an ETP URI
*/
- Energistics::Etp::v12::Datatypes::ErrorInfo validateDataObjectUri(const std::string & uri, ETP_NS::AbstractSession* session = nullptr);
+ bool validateUri(const std::string& uri);
/**
- * Build a protocol exception message which only contains a single error message (not a messsage map).
+ * Validate an ETP dataobject URI
*/
- Energistics::Etp::v12::Protocol::Core::ProtocolException buildSingleMessageProtocolException(int32_t m_code, const std::string & m_message);
+ bool validateDataObjectUri(const std::string& uri);
}
/******************* CLIENT ***************************/
@@ -2156,7 +2149,7 @@ namespace ETP_NS
* Run the websocket and then the ETP session.
* Everything related to this session (including the completion handlers) will operate on the same unique thread in a single event loop.
*/
- bool run();
+ void run();
};
class InitializationParameters
@@ -2175,7 +2168,7 @@ namespace ETP_NS
InitializationParameters(const std::string& instanceUuid, const std::string & host, unsigned short port, const std::string & urlPath = "");
virtual ~InitializationParameters();
- void setMaxWebSocketMessagePayloadSize(int64_t value);
+ void setMaxWebSocketMessagePayloadSize(uint64_t value);
uint64_t getMaxWebSocketMessagePayloadSize() const;
void setPreferredMaxFrameSize(uint64_t value);
@@ -2224,7 +2217,7 @@ namespace ETP_NS
#ifdef WITH_FESAPI
%typemap(javaimports) FesapiHdfProxyFactory %{
- import com.f2i_consulting.fesapi.common.HdfProxyFactory;
+import com.f2i_consulting.fesapi.common.HdfProxyFactory;
%}
%typemap(csimports) FesapiHdfProxyFactory %{
using F2iConsulting.Fesapi.common;
@@ -2281,7 +2274,9 @@ namespace ETP_NS
}
#ifdef WITH_FESAPI
-%pragma(java) moduleimports="import com.f2i_consulting.fesapi.common.AbstractObject;"
-%pragma(java) jniclassimports="import com.f2i_consulting.fesapi.common.AbstractObject;"
+%pragma(java) moduleimports="import com.f2i_consulting.fesapi.common.AbstractObject;
+import com.f2i_consulting.fesapi.common.DataObjectRepository;"
+%pragma(java) jniclassimports="import com.f2i_consulting.fesapi.common.AbstractObject;
+import com.f2i_consulting.fesapi.common.DataObjectRepository;"
%pragma(csharp) moduleimports="using F2iConsulting.Fesapi.common;"
#endif
\ No newline at end of file
diff --git a/cs/CMakeLists.txt b/cs/CMakeLists.txt
index 042fde8..eff2b9c 100644
--- a/cs/CMakeLists.txt
+++ b/cs/CMakeLists.txt
@@ -9,21 +9,6 @@ message("Generating SWIG C# files...")
# Cleaning
execute_process(COMMAND powershell "Remove-Item ${CMAKE_SOURCE_DIR}/cs/src/* -recurse -exclude .gitignore")
-# The name of the library is different on Windows because it includes the version
-if (WIN32)
- if (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_RELEASE_POSTFIX}.${Fetpapi_VERSION})
- else (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_DEBUG_POSTFIX}.${Fetpapi_VERSION})
- endif (SWIG_LINKED_TO_RELEASE)
-else (WIN32)
- if (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_RELEASE_POSTFIX})
- else (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_DEBUG_POSTFIX})
- endif (SWIG_LINKED_TO_RELEASE)
-endif (WIN32)
-
# SWIG execution
set (EXECUTE_COMMAND "${SWIG_EXECUTABLE}")
list (APPEND EXECUTE_COMMAND -v)
@@ -36,7 +21,7 @@ if (WITH_ETP_SSL)
list (APPEND EXECUTE_COMMAND -DWITH_ETP_SSL)
endif (WITH_ETP_SSL)
list (APPEND EXECUTE_COMMAND -dllimport)
-list (APPEND EXECUTE_COMMAND ${ASSEMBLY_NAME}.dll)
+list (APPEND EXECUTE_COMMAND ${PROJECT_NAME}${CMAKE_RELEASE_POSTFIX}-${Fetpapi_VERSION_MAJOR}.${Fetpapi_VERSION_MINOR}.dll)
list (APPEND EXECUTE_COMMAND -namespace)
list (APPEND EXECUTE_COMMAND F2iConsulting.Fetpapi)
list (APPEND EXECUTE_COMMAND -o)
diff --git a/example/withFesapi/etpClient.cpp b/example/withFesapi/etpClient.cpp
index f7d1ffd..dc92b35 100644
--- a/example/withFesapi/etpClient.cpp
+++ b/example/withFesapi/etpClient.cpp
@@ -21,7 +21,11 @@ under the License.
#include
#include
+#include
+#include
+#include
#include
+#include
#include
#include "etp/ClientSessionLaunchers.h"
@@ -47,6 +51,7 @@ void printHelp()
std::cout << "\tBlockingImport" << std::endl << "\t\tList all dataobjects from the project/study named dataspace (or the first dataspace) and get the first one in a blocking way" << std::endl << std::endl;
std::cout << "\tBlockingExport" << std::endl << "\t\tPut a dummy horizon feature into a dummy dataspace which is also created" << std::endl << std::endl;
std::cout << "\tPing" << std::endl << "\t\tPing the server" << std::endl << std::endl;
+ std::cout << "\tPutDummyHorizon" << std::endl << "\t\tPut a dummy horizon to the store" << std::endl << std::endl;
std::cout << "\tList" << std::endl << "\t\tList the objects which have been got from ETP to the in-memory Dataobject repository" << std::endl << std::endl;
std::cout << "\tPutXmlAndHdfAtOnce" << std::endl << "\t\tPut a dummy point set representation to the store sending XML and HDF5 points at once." << std::endl << std::endl;
std::cout << "\tGetDataspaces" << std::endl << "\t\tGet all store dataspaces" << std::endl << std::endl;
@@ -68,6 +73,7 @@ void printHelp()
std::cout << "\tDeleteDataObject URI" << std::endl << "\t\tDelete a dataobject" << std::endl << std::endl;
std::cout << "\tDeleteDataspace URI" << std::endl << "\t\tDelete a dataspace" << std::endl << std::endl;
std::cout << "\tGetDeletedResources dataspaceURI" << std::endl << "\t\tGet all deleted resources" << std::endl << std::endl;
+ std::cout << "\tGetAllRepsAndProps dataspace" << std::endl << "\t\tGet all the representations and all their properties from a dataspace" << std::endl << std::endl;
std::cout << "\tquit" << std::endl << "\t\tQuit the session." << std::endl << std::endl;
}
@@ -80,11 +86,10 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
while (command != "quit")
{
if (session->isEtpSessionClosed()) {
- command = "quit";
- }
- else {
- std::getline(std::cin, command);
+ std::cout << "The ETP session has been lost. You should quit if FETPAPI cannot reconnect by itself" << std::endl;
}
+
+ std::getline(std::cin, command);
auto commandTokens = tokenize(command, ' ');
if (commandTokens.empty()) {
@@ -191,8 +196,8 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
const auto resources = session->getResources(mb.context, mb.scope);
for (auto& resource : resources) {
std::cout << resource.uri << std::endl;
- if (resource.has_sourceCount()) std::cout << "Source count: " << resource.sourceCount.get() << std::endl;
- if (resource.has_targetCount()) std::cout << "Target count: " << resource.targetCount.get() << std::endl;
+ if (resource.has_sourceCount()) std::cout << "Source count: " << resource.sourceCount.value() << std::endl;
+ if (resource.has_targetCount()) std::cout << "Target count: " << resource.targetCount.value() << std::endl;
}
continue;
}
@@ -239,9 +244,9 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
std::cerr << " The UUID " << uuid << " from URI " << commandTokens[1] << " does not correspond to a representation which is on client side. Please get first this dataobject from the store before to call GetXYZPoints on it." << std::endl;
continue;
}
- auto xyzPointCount = rep->getXyzPointCountOfPatch(0);
+ auto xyzPointCount = rep->getXyzPointCountOfAllPatches();
std::unique_ptr xyzPoints(new double[xyzPointCount * 3]);
- rep->getXyzPointsOfPatch(0, xyzPoints.get());
+ rep->getXyzPointsOfAllPatches(xyzPoints.get());
for (auto xyzPointIndex = 0; xyzPointIndex < xyzPointCount && xyzPointIndex < 20; ++xyzPointIndex) {
std::cout << "XYZ Point Index " << xyzPointIndex << " : " << xyzPoints[xyzPointIndex * 3] << "," << xyzPoints[xyzPointIndex * 3 + 1] << "," << xyzPoints[xyzPointIndex * 3 + 2] << std::endl;
}
@@ -270,6 +275,72 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
std::cout << dataspace.uri << std::endl;
}
}
+ else if (commandTokens[0] == "GetAllRepsAndProps") {
+ if (commandTokens.size() == 1) {
+ std::cerr << "Please provide some ETP URIs of a dataspace" << std::endl;
+ continue;
+ }
+ std::map dataspaceUris;
+ dataspaceUris["0"] = commandTokens[1];
+
+ Energistics::Etp::v12::Datatypes::Object::ContextInfo ctxInfo;
+ ctxInfo.uri = dataspaceUris["0"];
+ ctxInfo.depth = 0;
+ ctxInfo.navigableEdges = Energistics::Etp::v12::Datatypes::Object::RelationshipKind::Both;
+ ctxInfo.includeSecondaryTargets = false;
+ ctxInfo.includeSecondarySources = false;
+ const auto resources = session->getResources(ctxInfo, Energistics::Etp::v12::Datatypes::Object::ContextScopeKind::targets);
+ std::cout << "************ GET ALL " << resources.size() << " DATAOBJECTS ************" << std::endl;
+ if (!resources.empty()) {
+ std::map< std::string, std::string > query;
+ size_t index = 0;
+ for (auto& resource : resources) {
+ query[std::to_string(index++)] = resource.uri;
+ }
+ const auto dataobjects = session->getDataObjects(query);
+ for (const auto& dataobjectEntry : dataobjects) {
+ repo.addOrReplaceGsoapProxy(dataobjectEntry.second.data, ETP_NS::EtpHelpers::getDataObjectType(dataobjectEntry.second.resource.uri), ETP_NS::EtpHelpers::getDataspaceUri(dataobjectEntry.second.resource.uri));
+ }
+ // Parse reps
+ auto global_start = std::chrono::high_resolution_clock::now();
+ for (auto* rep : repo.getDataObjects()) {
+ std::cout << "Representation " << rep->getTitle() << std::endl;
+ std::unique_ptr ijkGridPoints(new double[rep->getXyzPointCountOfAllPatches() * 3]);
+ auto t_start = std::chrono::high_resolution_clock::now();
+ try {
+ rep->getXyzPointsOfAllPatches(ijkGridPoints.get());
+ std::cout << "XYZ POINTS IN " << std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() << " ms" << std::endl;
+ }
+ catch (...) {
+ std::cerr << "Error reading XYZ points." << std::endl;
+ }
+
+ auto allProps = rep->getValuesPropertySet();
+ size_t propIndex = 1;
+ for (auto* prop : allProps) {
+ size_t valuesCount = prop->getValuesCountOfPatch(0);
+ if (dynamic_cast(prop) != nullptr) {
+ std::cout << "Continuous Prop " << propIndex++ << "/" << allProps.size() << " : " << prop->getTitle() << std::endl;
+ std::unique_ptr propValues(new double[valuesCount]);
+ t_start = std::chrono::high_resolution_clock::now();
+ prop->getDoubleValuesOfPatch(0, propValues.get());
+ std::cout << "Continuous Prop IN " << std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() << " ms" << std::endl;
+ }
+ else {
+ std::cout << "Non Continuous Prop " << propIndex++ << "/" << allProps.size() << " : " << prop->getTitle() << std::endl;
+ std::unique_ptr propValues(new int[valuesCount]);
+ t_start = std::chrono::high_resolution_clock::now();
+ prop->getInt32ValuesOfPatch(0, propValues.get());
+ std::cout << "Non Continuous Prop IN " << std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() << " ms" << std::endl;
+ }
+ }
+ }
+ std::cout << "GLOBALLY DONE IN " << std::chrono::duration(std::chrono::high_resolution_clock::now() - global_start).count() << " ms" << std::endl;
+ }
+ else {
+ std::cout << "There is no dataobject in this dataspace" << std::endl;
+ }
+ }
else if (commandTokens[0] == "PutDataspace") {
if (commandTokens.size() == 1) {
std::cerr << "Please provide some ETP URI of a dataspace" << std::endl;
@@ -418,6 +489,106 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
std::cout << "PING at " << ping.currentDateTime << std::endl;
std::cout << "Please Set Verbosity to 1 if you don't see anything" << std::endl;
}
+ else if (commandTokens[0] == "PutDummyHorizon") {
+ Energistics::Etp::v12::Datatypes::Object::Dataspace dataspace;
+ dataspace.path = "demo/PutHorizon3";
+ dataspace.uri = "eml:///dataspace('" + dataspace.path + "')";
+ Energistics::Etp::v12::Datatypes::DataValue dataValue;
+ Energistics::Etp::v12::Datatypes::ArrayOfString aos;
+
+ aos.values.push_back("data.default.viewers@osdu.example.com");
+ //aos.values.push_back("data.default.viewers@opendes.contoso.com");
+ dataValue.item.set_ArrayOfString(aos);
+ dataspace.customData["viewers"] = dataValue;
+
+ aos.values[0] = "data.default.owners@osdu.example.com";
+ //aos.values[0] = "data.default.owners@opendes.contoso.com";
+ dataValue.item.set_ArrayOfString(aos);
+ dataspace.customData["owners"] = dataValue;
+
+ aos.values[0] = "osdu-public-usa-dataset";
+ //aos.values[0] = "opendes-ReservoirDDMS-Legal-Tag";
+ dataValue.item.set_ArrayOfString(aos);
+ dataspace.customData["legaltags"] = dataValue;
+
+ aos.values[0] = "US";
+ dataValue.item.set_ArrayOfString(aos);
+ dataspace.customData["otherRelevantDataCountries"] = dataValue;
+
+ std::map deleteDs;
+ deleteDs["0"] = dataspace.uri;
+ session->deleteDataspaces(deleteDs);
+
+ std::map dataspaces;
+ dataspaces["0"] = dataspace;
+ auto successKeys = session->putDataspaces(dataspaces);
+ if (successKeys.size() == 1) std::cout << "Dataspace has been put" << std::endl;
+ else std::cout << "Error when putting dataspace" << std::endl;
+
+ COMMON_NS::DataObjectRepository tmpRepo;
+ tmpRepo.setDefaultStandard(COMMON_NS::DataObjectRepository::EnergisticsStandard::RESQML2_0_1);
+ tmpRepo.setDefaultStandard(COMMON_NS::DataObjectRepository::EnergisticsStandard::EML2_0);
+ auto* local_3d_crs = tmpRepo.createLocalDepth3dCrs("b2129512-b8f9-4721-8a70-1abac53ef406", "Default CRS",
+ 0.0, 0.0, 0.0, 0.0,
+ gsoap_resqml2_0_1::eml20__LengthUom::m, 5215,
+ gsoap_resqml2_0_1::eml20__LengthUom::m, "Unknown",
+ false);
+ tmpRepo.setDefaultCrs(local_3d_crs);
+ tmpRepo.setHdfProxyFactory(new ETP_NS::FesapiHdfProxyFactory(session.get()));
+ auto* hdf_proxy = tmpRepo.createHdfProxy("f8160b8f-0517-4c55-ab6e-ed8bcdc87111", "Hdf Proxy",
+ ".", "fake.h5",
+ COMMON_NS::DataObjectRepository::openingMode::OVERWRITE);
+ hdf_proxy->setUriSource(dataspace.uri);
+ tmpRepo.setDefaultHdfProxy(hdf_proxy);
+ auto* horizon_feature = tmpRepo.createHorizon("c0f12836-41f4-44a8-a3fd-95ac78f6232d", "My horizon feature");
+ auto* horizon_interpretation = tmpRepo.createHorizonInterpretation(horizon_feature, "dc217b29-8ceb-4b77-bdcc-6bcfd9cd3baf", "My horizon interpretation");
+ auto* horizon_grid_2d_representation = tmpRepo.createGrid2dRepresentation(horizon_interpretation, "7721fb3c-39ba-4d59-ba0b-f9451706a94c", "My horizon representation");
+
+ std::vector< std::string > dataspacesToLock;
+ dataspacesToLock.push_back(dataspace.uri);
+
+ auto transaction_start = std::chrono::high_resolution_clock::now();
+
+ session->startTransaction(dataspacesToLock);
+
+ const size_t ni = 10000;
+ const size_t nj = 1000;
+ std::unique_ptr resqml_points(new double[ni * nj]);
+ for (double i = 0; i < ni * nj; ++i) {
+ resqml_points[(int)i] = i * 100;
+ }
+ horizon_grid_2d_representation->setGeometryAsArray2dOfExplicitZ(resqml_points.get(), ni, nj, hdf_proxy,
+ 0.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0, 25.0,
+ 0.0, 1.0, 0.0, 50.0);
+
+ for (size_t propIndex = 0; propIndex < 1; ++propIndex) {
+ auto t_start = std::chrono::high_resolution_clock::now();
+ auto* prop = tmpRepo.createContinuousProperty(horizon_grid_2d_representation, "", "", 1, gsoap_eml2_3::eml23__IndexableElement::nodes, gsoap_resqml2_0_1::resqml20__ResqmlUom::m,
+ gsoap_resqml2_0_1::resqml20__ResqmlPropertyKind::length);
+ std::unique_ptr prop_values(new double[ni * nj]);
+ prop->pushBackDoubleHdf5Array2dOfValues(prop_values.get(), ni, nj, hdf_proxy);
+ std::cout << " Pushed prop " << propIndex << " in " << std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() << " ms" << std::endl;
+ std::cout << " Global time " << std::chrono::duration(std::chrono::high_resolution_clock::now() - transaction_start).count() << " s" << std::endl;
+ }
+
+ tmpRepo.setUriSource(dataspace.uri);
+ std::map dataobjects;
+ auto allUuids = tmpRepo.getUuids();
+ int index = 0;
+ for (auto& uuid : allUuids)
+ dataobjects[std::to_string(index++)] = ETP_NS::FesapiHelpers::buildEtpDataObjectFromEnergisticsObject(tmpRepo, uuid);
+ successKeys = session->putDataObjects(dataobjects);
+ for (std::string& str : successKeys)
+ std::cout << "successKey : " << str << std::endl;
+
+ std::cout << "commit : " << session->commitTransaction() << std::endl;
+
+ if (session != nullptr && !session->isWebSocketSessionClosed())
+ horizon_grid_2d_representation->getZValues(resqml_points.get());
+
+ tmpRepo.clear();
+ }
else if (commandTokens[0] == "GetDataspaces") {
const auto dataspaces = session->getDataspaces();
for (auto& dataspace : dataspaces) {
@@ -509,8 +680,9 @@ void askUser(std::shared_ptr session, COMMON_NS::DataOb
Energistics::Etp::v12::Datatypes::AnyArray data;
Energistics::Etp::v12::Datatypes::ArrayOfInt arrayOfInt;
arrayOfInt.values = { 0,1,2,3,4,5,6,7,8,9 };
- data.item.set_ArrayOfInt(arrayOfInt);
+ data.item.set_ArrayOfInt(std::move(arrayOfInt));
pda.dataArrays["0"].array.data = data;
+ std::cout << "Start sending the array" << std::endl;
session->send(pda, 0, 0x02);
}
@@ -552,7 +724,9 @@ int main(int argc, char **argv)
std::string authorization;
std::getline(std::cin, authorization);
- bool successfulConnection = false;
+ std::cout << "Give the data partition id you want to direct your requests (or hit enter if no data partition)" << std::endl;
+ std::string dataPartition;
+ std::getline(std::cin, dataPartition);
COMMON_NS::DataObjectRepository repo;
repo.setDefaultStandard(COMMON_NS::DataObjectRepository::EnergisticsStandard::RESQML2_0_1);
@@ -562,16 +736,16 @@ int main(int argc, char **argv)
ETP_NS::InitializationParameters initializationParams = argc == 2
? ETP_NS::InitializationParameters(gen(), argv[1]) // URL based
: ETP_NS::InitializationParameters(gen(), argv[1], std::stoi(argv[2]), argc < 4 ? "/" : argv[3]); // IP Port and target based
- std::map< std::string, std::string > additionalHeaderField = { {"data-partition-id", "osdu"} }; // Example for OSDU RDDMS
+ std::map< std::string, std::string > additionalHeaderField = { {"data-partition-id", dataPartition} }; // Example for OSDU RDDMS
initializationParams.setAdditionalHandshakeHeaderFields(additionalHeaderField);
std::cout << "Creating a client session..." << std::endl;
auto clientSession = ETP_NS::ClientSessionLaunchers::createClientSession(&initializationParams, authorization);
+ clientSession->setVerbose(false);
repo.setHdfProxyFactory(new ETP_NS::FesapiHdfProxyFactory(clientSession.get()));
std::thread sessionThread(&ETP_NS::ClientSession::run, clientSession);
- sessionThread.detach();
// Wait for the ETP session to be opened
auto t_start = std::chrono::high_resolution_clock::now();
@@ -585,6 +759,8 @@ int main(int argc, char **argv)
clientSession->setTimeOut(60000);
askUser(clientSession, repo);
+ sessionThread.join();
+
#ifdef _WIN32
_CrtDumpMemoryLeaks();
#endif
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 61f9996..cd343a5 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -20,9 +20,9 @@ file (REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/java/src/com/f2i_consulting/fetpapi/etp
# The assembly name is used to load the debug vs release FETPAPI library in the Java example
if (WIN32)
if (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_RELEASE_POSTFIX}.${Fetpapi_VERSION})
+ set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_RELEASE_POSTFIX}-${Fetpapi_VERSION_MAJOR}.${Fetpapi_VERSION_MINOR})
else (SWIG_LINKED_TO_RELEASE)
- set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_DEBUG_POSTFIX}.${Fetpapi_VERSION})
+ set (ASSEMBLY_NAME ${PROJECT_NAME}${CMAKE_DEBUG_POSTFIX}-${Fetpapi_VERSION_MAJOR}.${Fetpapi_VERSION_MINOR})
endif (SWIG_LINKED_TO_RELEASE)
else (WIN32)
if (SWIG_LINKED_TO_RELEASE)
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 1455314..8e461ac 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -58,7 +58,7 @@ if (WITH_FESAPI)
set (FESAPI_LIBRARY_RELEASE_WLE ",'${FESAPI_LIBRARY_RELEASE_WLE}'")
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
- set (EXTRA_COMPILE_ARGS "extra-compile-args=['/DSWIG_TYPE_TABLE=FESTAPI', '/utf-8']")
+ set (EXTRA_COMPILE_ARGS "extra-compile-args=['/DSWIG_TYPE_TABLE=FESTAPI', '/std:c++17', '/utf-8']")
else ()
set (EXTRA_COMPILE_ARGS "extra-compile-args=['-DSWIG_TYPE_TABLE=FESTAPI', '-std=c++17']")
endif()
diff --git a/python/example/PutHorizon.ipynb b/python/example/PutHorizon.ipynb
index 7961b9d..96ebd41 100644
--- a/python/example/PutHorizon.ipynb
+++ b/python/example/PutHorizon.ipynb
@@ -140,7 +140,7 @@
"id": "abbc43cb",
"metadata": {},
"source": [
- "Let's create a dataspace"
+ "Let's create a dataspace with the OSDU ACL mandatory information"
]
},
{
@@ -152,7 +152,31 @@
"source": [
"dataspace = fetpapi.Dataspace()\n",
"dataspace.path = \"demo/PutHorizon\"\n",
- "dataspace.uri = \"eml:///dataspace('\" + dataspace.path + \"')\""
+ "dataspace.uri = \"eml:///dataspace('\" + dataspace.path + \"')\"\n",
+ "dataspace.customData = fetpapi.MapStringDataValue()\n",
+ "dataValue = fetpapi.DataValue()\n",
+ "aos = fetpapi.ArrayOfString()\n",
+ "dataValue.item = fetpapi.DataValueitem_t()\n",
+ "tmp = fetpapi.StringVector()\n",
+ "tmp.push_back(\"data.default.viewers@osdu.example.com\")\n",
+ "aos.values = tmp\n",
+ "dataValue.item.set_ArrayOfString(aos)\n",
+ "dataspace.customData[\"viewers\"] = dataValue\n",
+ "tmp.clear()\n",
+ "tmp.push_back(\"data.default.owners@osdu.example.com\")\n",
+ "aos.values = tmp\n",
+ "dataValue.item.set_ArrayOfString(aos)\n",
+ "dataspace.customData[\"owners\"] = dataValue\n",
+ "tmp.clear()\n",
+ "tmp.push_back(\"osdu-public-usa-dataset\")\n",
+ "aos.values = tmp\n",
+ "dataValue.item.set_ArrayOfString(aos)\n",
+ "dataspace.customData[\"legaltags\"] = dataValue\n",
+ "tmp.clear()\n",
+ "tmp.push_back(\"US\")\n",
+ "aos.values = tmp\n",
+ "dataValue.item.set_ArrayOfString(aos)\n",
+ "dataspace.customData[\"otherRelevantDataCountries\"] = dataValue"
]
},
{
@@ -242,7 +266,7 @@
"resqml_points = fesapi.DoubleArray(6)\n",
"for i in range(6):\n",
" resqml_points.setitem(i, i*100)\n",
- "horizon_grid_2d_representation.setGeometryAsArray2dOfExplicitZ(resqml_points, 2, 3, hdf_proxy,\n",
+ "horizon_grid_2d_representation.setGeometryAsArray2dOfExplicitZ(resqml_points.cast(), 2, 3, hdf_proxy,\n",
" 0.0, 0.0, 0.0,\n",
" 1.0, 0.0, 0.0, 25.0,\n",
" 0.0, 1.0, 0.0, 50.0)"
diff --git a/python/example/etp_client_example.py b/python/example/etp_client_example.py
index 46fa2e3..3091caa 100644
--- a/python/example/etp_client_example.py
+++ b/python/example/etp_client_example.py
@@ -79,28 +79,53 @@ def start_etp_server(client_session):
nb_xyz_points = ijk_grid.getXyzPointCountOfAllPatches()
print("XYZ points count :", nb_xyz_points)
xyz_points = fesapi.DoubleArray(nb_xyz_points * 3)
- ijk_grid.getXyzPointsOfAllPatches(xyz_points)
+ ijk_grid.getXyzPointsOfAllPatches(xyz_points.cast())
ijk_grid.loadSplitInformation()
origin_index = ijk_grid.getXyzPointIndexFromCellCorner(0, 0, 0, 0)
print("Cell 0,0,0 corner 0 is at index ", origin_index)
print("Cell 0,0,0 corner 0 is ", xyz_points.getitem(origin_index * 3), " ", xyz_points.getitem(origin_index * 3 + 1), " ", xyz_points.getitem(origin_index * 3 + 2))
ijk_grid.unloadSplitInformation()
+
+ if ijk_grid.getValuesPropertyCount() > 0:
+ prop = ijk_grid.getValuesProperty(0)
+ print("Prop at index 0 : " + prop.getTitle())
+ print(type(prop))
+
+ if isinstance(prop, fesapi.Resqml2_ContinuousProperty):
+ prop_values = fesapi.DoubleArray(ijk_grid.getICellCount() * ijk_grid.getJCellCount() * ijk_grid.getKCellCount())
+ prop.getDoubleValuesOfPatch(0, prop_values.cast())
+ print("Cell 0,0,0 has prop value ", prop_values.getitem(0))
+ print("Cell 1,0,0 has prop value ", prop_values.getitem(1))
+ print("Cell 2,0,0 has prop value ", prop_values.getitem(2))
+ print("Cell 3,0,0 has prop value ", prop_values.getitem(3))
+ print("Cell 4,0,0 has prop value ", prop_values.getitem(4))
+ print("Cell 5,0,0 has prop value ", prop_values.getitem(5))
+ else:
+ print(f"This property is a {type(prop)}")
+ else:
+ print("This IJK grid has no property")
else:
print("This dataspace has no IJK Grid")
print("Read data of the first 2d grid");
if repo.getHorizonGrid2dRepresentationCount() > 0:
grid2d = repo.getHorizonGrid2dRepresentation(0)
- print("2d Grid : " + grid2d.getTitle())
+ print("2d grid : " + grid2d.getTitle())
print(f"iCount : {grid2d.getNodeCountAlongIAxis()} jCount : {grid2d.getNodeCountAlongJAxis()}")
nb_z_points = grid2d.getNodeCountAlongIAxis() * grid2d.getNodeCountAlongJAxis()
print(f"XYZ points count : {nb_z_points}")
z_points = fesapi.DoubleArray(nb_z_points)
- grid2d.getZValues(z_points)
+ grid2d.getZValues(z_points.cast())
print("Z value at index 0 : ", z_points.getitem(0))
print("Z value at index 1 : ", z_points.getitem(1))
+
+ if grid2d.getValuesPropertyCount() > 0:
+ prop = grid2d.getValuesProperty(0)
+ print("Prop at index 0 : " + prop.getTitle())
+ else:
+ print("This 2d grid has no property")
else:
print("This dataspace has no 2d Grid")
diff --git a/python/example/fetpapi.ipynb b/python/example/fetpapi.ipynb
index 85bf62a..48055dd 100644
--- a/python/example/fetpapi.ipynb
+++ b/python/example/fetpapi.ipynb
@@ -131,6 +131,8 @@
" sleep(0.25)\t\n",
"if client_session.isEtpSessionClosed():\n",
" print(\"The ETP session could not be established in 5 seconds.\")\n",
+ " if not etp_server_url.endswith(\"/\"):\n",
+ " print(\"You may try adding an ending slash to your ETP server URL.\")\n",
"else:\n",
" print(\"Now connected to ETP Server\")"
]
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 574b0b3..2657944 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,3 @@
set(FESAPI_TOOLS_HEADERS ${CMAKE_CURRENT_LIST_DIR}/nsDefinitions.h )
include(${CMAKE_CURRENT_LIST_DIR}/etp/CMakeLists.txt)
-include(${CMAKE_CURRENT_LIST_DIR}/tools/CMakeLists.txt)
diff --git a/src/etp/AbstractClientSessionCRTP.h b/src/etp/AbstractClientSessionCRTP.h
index acce0a3..3a6e676 100644
--- a/src/etp/AbstractClientSessionCRTP.h
+++ b/src/etp/AbstractClientSessionCRTP.h
@@ -30,14 +30,15 @@ namespace ETP_NS
virtual ~AbstractClientSessionCRTP() = default;
- void on_connect(boost::system::error_code ec) {
+ void on_ssl_handshake(boost::system::error_code ec) {
if (ec) {
- std::cerr << "on_connect : " << ec.message() << std::endl;
+ std::cerr << "ERROR at Websocket connection : " << ec.message() << std::endl;
+ return;
}
#if BOOST_VERSION < 107000
// Perform the websocket handshake
- derived().ws().async_handshake_ex(responseType,
+ derived().ws()->async_handshake_ex(responseType,
etpServerHost + ":" + etpServerPort, etpServerTarget,
[&](websocket::request_type& m)
{
@@ -52,11 +53,11 @@ namespace ETP_NS
}
},
std::bind(
- &AbstractClientSessionCRTP::on_handshake,
+ &ClientSession::on_handshake,
std::static_pointer_cast(shared_from_this()),
std::placeholders::_1));
#else
- derived().ws().set_option(websocket::stream_base::decorator(
+ derived().ws()->set_option(websocket::stream_base::decorator(
[&](websocket::request_type& m)
{
m.insert(boost::beast::http::field::sec_websocket_protocol, "etp12.energistics.org");
@@ -71,10 +72,10 @@ namespace ETP_NS
})
);
// Perform the websocket handshake
- derived().ws().async_handshake(responseType,
+ derived().ws()->async_handshake(responseType,
etpServerHost + ":" + etpServerPort, etpServerTarget,
std::bind(
- &AbstractClientSessionCRTP::on_handshake,
+ &ClientSession::on_handshake,
std::static_pointer_cast(shared_from_this()),
std::placeholders::_1));
#endif
@@ -85,7 +86,7 @@ namespace ETP_NS
* The ETP session had to be closed before.
*/
FETPAPI_DLL_IMPORT_OR_EXPORT void do_close() {
- derived().ws().async_close(websocket::close_code::normal,
+ derived().ws()->async_close(websocket::close_code::normal,
std::bind(
&AbstractSession::on_close,
shared_from_this(),
@@ -100,7 +101,7 @@ namespace ETP_NS
}
// Read a message into our buffer
- derived().ws().async_read(
+ derived().ws()->async_read(
receivedBuffer,
std::bind(
&AbstractSession::on_read,
@@ -109,28 +110,9 @@ namespace ETP_NS
std::placeholders::_2));
}
- void on_handshake(boost::system::error_code ec)
- {
- if (ec) {
- std::cerr << "on_handshake : " << ec.message() << std::endl;
- std::cerr << "Sometimes some ETP server require a trailing slash at the end of their URL. Did you also check your optional \"data-partition-id\" additional Header Field?" << std::endl;
- return;
- }
-
- if (!responseType.count(boost::beast::http::field::sec_websocket_protocol) ||
- responseType[boost::beast::http::field::sec_websocket_protocol] != "etp12.energistics.org")
- std::cerr << "The client MUST specify the Sec-Websocket-Protocol header value of etp12.energistics.org, and the server MUST reply with the same" << std::endl;
-
- successfulConnection = true;
- webSocketSessionClosed = false;
-
- send(requestSession, 0, 0x02);
- do_read();
- }
-
- void setMaxWebSocketMessagePayloadSize(int64_t value) final {
+ void setMaxWebSocketMessagePayloadSize(uint64_t value) final {
maxWebSocketMessagePayloadSize = value;
- derived().ws().read_message_max(value);
+ derived().ws()->read_message_max(value);
}
protected:
@@ -140,12 +122,12 @@ namespace ETP_NS
Derived& derived() { return static_cast(*this); }
void do_write() {
- const std::lock_guard specificProtocolHandlersLock(specificProtocolHandlersMutex);
if (sendingQueue.empty()) {
fesapi_log("The sending queue is empty.");
return;
}
+ const std::lock_guard specificProtocolHandlersLock(specificProtocolHandlersMutex);
bool previousSentMessageCompleted = specificProtocolHandlers.find(std::get<0>(sendingQueue.front())) == specificProtocolHandlers.end();
if (!previousSentMessageCompleted) {
@@ -154,16 +136,26 @@ namespace ETP_NS
else {
fesapi_log("Sending Message id :", std::to_string(std::get<0>(sendingQueue.front())));
- derived().ws().async_write(
+ derived().ws()->async_write(
boost::asio::buffer(std::get<1>(sendingQueue.front())),
- std::bind(
- &AbstractSession::on_write,
- shared_from_this(),
- std::placeholders::_1,
- std::placeholders::_2));
-
- // Register the handler to respond to the sent message
- specificProtocolHandlers[std::get<0>(sendingQueue.front())] = std::get<2>(sendingQueue.front());
+ [this, self{ this->shared_from_this() }](boost::system::error_code ec, std::size_t)
+ ->void
+ {
+ if (ec) {
+ std::cerr << "on_write : " << ec.message() << std::endl;
+ }
+ else {
+ // Register the handler to respond to the sent message
+ const std::lock_guard specificProtocolHandlersLock(specificProtocolHandlersMutex);
+ specificProtocolHandlers[std::get<0>(sendingQueue.front())] = std::get<2>(sendingQueue.front());
+ }
+
+ // Remove the sent message from the queue
+ const std::lock_guard sendingQueueLock(sendingQueueMutex);
+ sendingQueue.pop();
+
+ do_write();
+ });
}
}
};
diff --git a/src/etp/AbstractSession.cpp b/src/etp/AbstractSession.cpp
index 20737ee..9409afd 100644
--- a/src/etp/AbstractSession.cpp
+++ b/src/etp/AbstractSession.cpp
@@ -42,18 +42,46 @@ void AbstractSession::on_read(boost::system::error_code ec, std::size_t bytes_tr
boost::ignore_unused(bytes_transferred);
if (ec) {
+ // If read completes with an error, it indicates there is an issue with the connection, so async_close would also complete with an error.
+ // Therefore, there is no need to call async_close; the destructor of websocket::stream will forcefully close the underlying socket.
+ flushReceivingBuffer();
if (ec == websocket::error::closed) {
// This indicates that the web socket (and consequently etp) session was closed
- fesapi_log("The other endpoint closed the web socket (and consequently etp) connection.");
- webSocketSessionClosed = true;
- flushReceivingBuffer();
+ if (etpSessionClosed) {
+ fesapi_log("The other endpoint closed the web socket (and consequently etp) connection in a graceful way.");
+ }
+ else {
+ std::cerr << "The other endpoint closed the web socket(and consequently etp) connection in a graceful way." << std::endl;
+ }
+ }
+#if BOOST_VERSION > 106900
+ else if (ec == boost::beast::error::timeout) {
+ // This indicates that the web socket (and consequently etp) session was closed
+ std::cerr << "Beast timeout has been reached" << std::endl;
}
+#endif
else {
- // This indicates an unexpected error
- fesapi_log("on_read : error code number", ec.value(), "->", ec.message());
+ if (etpSessionClosed) {
+ // This error may be a common one to ignore in case of SSL short read : https://github.com/boostorg/beast/issues/824
+ fesapi_log("It looks that the other endpoint has closed the websocket session in a non graceful way.");
+ }
+ else {
+ // This indicates an unexpected error
+ std::cerr << "on_read : error code number " << ec.value() << std::endl;
+ std::cerr << "on_read : error message " << ec.message() << std::endl;
+ std::cerr << "on_read : error category " << ec.category().name() << std::endl;
+ }
}
+ const std::lock_guard specificProtocolHandlersLock(specificProtocolHandlersMutex);
+ specificProtocolHandlers.clear();
+ const std::lock_guard sendingQueueLock(sendingQueueMutex);
+ std::queue< std::tuple, std::shared_ptr> > empty;
+ std::swap(sendingQueue, empty);
+ webSocketSessionClosed = true;
+ etpSessionClosed = true;
+
return;
}
@@ -128,7 +156,7 @@ void AbstractSession::on_read(boost::system::error_code ec, std::size_t bytes_tr
normalProtocolHandlerIt->second->decodeMessageBody(receivedMh, d);
}
else {
- std::cerr << "Received a message with id " << receivedMh.messageId << " for which non protocol handlers is associated. Protocol " << receivedMhProtocol << std::endl;
+ std::cerr << "Received a message with id " << receivedMh.messageId << " for which no protocol handler is associated. Protocol " << receivedMhProtocol << std::endl;
send(ETP_NS::EtpHelpers::buildSingleMessageProtocolException(4, "The agent does not support the protocol " + std::to_string(receivedMhProtocol) + " identified in a message header."), receivedMh.messageId, 0x02);
}
}
@@ -141,7 +169,7 @@ void AbstractSession::on_read(boost::system::error_code ec, std::size_t bytes_tr
send(ETP_NS::EtpHelpers::buildSingleMessageProtocolException(19, "The agent is unable to de-serialize the body of the message id " + std::to_string(receivedMh.messageId) + " : " + std::string(e.what())), 0, 0x02);
}
- if (specificProtocolHandlers.empty() && isCloseRequested)
+ if (specificProtocolHandlers.empty() && isCloseRequested_)
{
etpSessionClosed = true;
send(Energistics::Etp::v12::Protocol::Core::CloseSession(), 0, 0x02);
@@ -255,7 +283,7 @@ std::vector AbstractSession::lockDataspaces(const std::map AbstractSession::copyToDataspace(const std::map& sourceUris, const std::string& targetDataspaceUri)
+std::vector AbstractSession::copyToDataspace(const std::map& sourceDataobjectUris, const std::string& targetDataspaceUri)
{
std::shared_ptr handlers = getDataspaceOSDUProtocolHandlers();
if (handlers == nullptr) {
@@ -263,7 +291,7 @@ std::vector AbstractSession::copyToDataspace(const std::map result = handlers->getSuccessKeys();
@@ -420,7 +448,7 @@ std::vector AbstractSession::deleteDataObjects(const std::map AbstractSession::copyDataObjectsByValue(const std::string& uri, int32_t sourcesDepth, const std::vector& dataObjectTypes)
+std::vector AbstractSession::copyDataObjectsByValue(const std::string& sourceDataobjectUri, int32_t sourcesDepth, const std::vector& dataObjectTypes)
{
std::shared_ptr handlers = getStoreOSDUProtocolHandlers();
if (handlers == nullptr) {
@@ -428,7 +456,7 @@ std::vector AbstractSession::copyDataObjectsByValue(const std::stri
}
Energistics::Etp::v12::Protocol::StoreOSDU::CopyDataObjectsByValue msg;
- msg.uri = uri;
+ msg.uri = sourceDataobjectUri;
msg.sourcesDepth = sourcesDepth;
msg.dataObjectTypes = dataObjectTypes;
sendAndBlock(msg, 0, 0x02);
diff --git a/src/etp/AbstractSession.h b/src/etp/AbstractSession.h
index 0b1dd39..95fa00a 100644
--- a/src/etp/AbstractSession.h
+++ b/src/etp/AbstractSession.h
@@ -57,10 +57,7 @@ namespace ETP_NS
* If the ETP session is not set up, it returns the nil UUID.
*/
const boost::uuids::uuid& getIdentifier() {
- if (isEtpSessionClosed()) {
- identifier = boost::uuids::nil_uuid();
- }
-
+ std::lock_guard lock(identifierMutex);
return identifier;
}
@@ -78,11 +75,6 @@ namespace ETP_NS
return _timeOut;
}
- /**
- * The list of subscriptions recorded by customers on this session.
- */
- std::unordered_map subscriptions;
-
/**
* Set the Core protocol handlers
*/
@@ -169,7 +161,7 @@ namespace ETP_NS
* @param messageFlags The message flags to be sent within the header
* @return The ID of the message that has been put in the sending queue.
*/
- template void sendAndBlock(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0)
+ template int64_t sendAndBlock(const T & mb, int64_t correlationId = 0, int32_t messageFlags = 0)
{
int64_t msgId = send(mb, correlationId, messageFlags);
// The correlationId of the first message MUST be set to 0 and the correlationId of all successive
@@ -184,6 +176,8 @@ namespace ETP_NS
throw std::runtime_error("Time out waiting for a response of message id " + std::to_string(msgId));
}
}
+
+ return msgId;
}
/**
@@ -197,12 +191,22 @@ namespace ETP_NS
*/
template int64_t sendWithSpecificHandler(const T & mb, std::shared_ptr specificHandler, int64_t correlationId = 0, int32_t messageFlags = 0)
{
+ if (mb.protocolId != 0 || mb.messageTypeId != 1) {
+ // Wait for a reconnection
+ while (isEtpSessionClosed() && !isCloseRequested()) {}
+ // Check if reconnection is successful
+ if (isEtpSessionClosed() && !isCloseRequested()) {
+ throw std::runtime_error("The ETP session could not be opened in order to send the message.");
+ }
+ }
+
// Encode the message into AVRO format
auto queueItem = encode(mb, correlationId, messageFlags);
const std::lock_guard sendingQueueLock(sendingQueueMutex);
// Set the handlers which are going to be called for the response to this sent message
std::get<2>(queueItem) = specificHandler;
+
// Push the message into the queue
sendingQueue.push(queueItem);
fesapi_log("*************************************************");
@@ -223,6 +227,47 @@ namespace ETP_NS
return std::get<0>(queueItem);
}
+ /**
+ * Send a message to the server and register a specific handler for the response and block the thread until the answer of the server has been processed by the handlers
+ * Please look at setTimeOut if you want to set the default timeout value which is 10 000 ms.
+ *
+ * @param mb The ETP message body to send
+ * @param correlationId The ID of the message which this message is answering to.
+ * @param messageFlags The message flags to be sent within the header
+ * @return The ID of the message that has been put in the sending queue.
+ */
+ template int64_t sendWithSpecificHandlerAndBlock(const T& mb, std::shared_ptr specificHandler, int64_t correlationId = 0, int32_t messageFlags = 0)
+ {
+ const int64_t msgId = sendWithSpecificHandler(mb, specificHandler, correlationId, messageFlags);
+ // The correlationId of the first message MUST be set to 0 and the correlationId of all successive
+ // messages in the same multipart request or notification MUST be set to the messageId of the first
+ // message of the multipart request or notification.
+ // If the request message is itself multipart, the correlationId of each message of the multipart
+ // response MUST be set to the messageId of the FIRST message in the multipart request.
+
+ const auto t_start = std::chrono::high_resolution_clock::now();
+ while (isMessageStillProcessing(correlationId == 0 ? msgId : correlationId)) {
+ if (std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() > _timeOut) {
+ throw std::runtime_error("Time out waiting for a response of message id " + std::to_string(msgId));
+ }
+ }
+
+ // If the message has not been answered correctly
+ if (isEtpSessionClosed() && !isCloseRequested()) {
+ // Wait for a reconnection
+ while (isEtpSessionClosed() && !isCloseRequested()) {}
+ // Check if reconnection is successfull
+ if (isEtpSessionClosed()) {
+ throw std::runtime_error("The ETP session could not be opened in order to send again the message.");
+ }
+ else {
+ return sendWithSpecificHandlerAndBlock(mb, specificHandler, correlationId, messageFlags);
+ }
+ }
+
+ return msgId;
+ }
+
/**
* Close the web socket session (without sending any ETP message)
*/
@@ -238,18 +283,6 @@ namespace ETP_NS
*/
FETPAPI_DLL_IMPORT_OR_EXPORT void on_read(boost::system::error_code ec, std::size_t bytes_transferred);
- void on_write(boost::system::error_code ec, std::size_t) {
- if(ec) {
- std::cerr << "on_write : " << ec.message() << std::endl;
- }
-
- // Remove the sent message from the queue
- const std::lock_guard sendingQueueLock(sendingQueueMutex);
- sendingQueue.pop();
-
- do_write();
- }
-
void on_close(boost::system::error_code ec) {
if(ec) {
std::cerr << "on_close : " << ec.message() << std::endl;
@@ -262,6 +295,11 @@ namespace ETP_NS
webSocketSessionClosed = true;
}
+ /**
+ * Check if the the closing of the session has been requested by this session or not.
+ */
+ FETPAPI_DLL_IMPORT_OR_EXPORT bool isCloseRequested() const { return isCloseRequested_; }
+
/**
* Check if the websocket session (starting after the HTTP handshake/upgrade) is not opened yet or has been closed.
*/
@@ -275,10 +313,9 @@ namespace ETP_NS
const std::lock_guard specificProtocolHandlersLock(specificProtocolHandlersMutex);
return (!sendingQueue.empty() && std::get<0>(sendingQueue.front()) <= msgId) || specificProtocolHandlers.count(msgId) > 0;
}
- //FETPAPI_DLL_IMPORT_OR_EXPORT bool isMessageStillProcessing(int64_t msgId) const { return specificProtocolHandlers.count(msgId) > 0; }
- virtual void setMaxWebSocketMessagePayloadSize(int64_t value) = 0;
- int64_t getMaxWebSocketMessagePayloadSize() const { return maxWebSocketMessagePayloadSize; }
+ virtual void setMaxWebSocketMessagePayloadSize(uint64_t value) = 0;
+ uint64_t getMaxWebSocketMessagePayloadSize() const { return maxWebSocketMessagePayloadSize; }
/****************
***** CORE ******
@@ -290,7 +327,7 @@ namespace ETP_NS
* This method does not block.
*/
FETPAPI_DLL_IMPORT_OR_EXPORT void close() {
- isCloseRequested = true;
+ isCloseRequested_ = true;
sendingQueueMutex.lock();
specificProtocolHandlersMutex.lock();
if (specificProtocolHandlers.empty() && sendingQueue.empty()) {
@@ -313,7 +350,7 @@ namespace ETP_NS
FETPAPI_DLL_IMPORT_OR_EXPORT void closeAndBlock() {
close();
auto t_start = std::chrono::high_resolution_clock::now();
- while (!isEtpSessionClosed()) {
+ while (!webSocketSessionClosed) {
if (std::chrono::duration(std::chrono::high_resolution_clock::now() - t_start).count() > _timeOut) {
throw std::runtime_error("Time out waiting for closing");
}
@@ -325,8 +362,6 @@ namespace ETP_NS
*/
FETPAPI_DLL_IMPORT_OR_EXPORT bool isEtpSessionClosed() const { return webSocketSessionClosed || etpSessionClosed; }
- void setEtpSessionClosed(bool etpSessionClosed_) { etpSessionClosed = etpSessionClosed_; }
-
/****************
*** DATASPACE ***
****************/
@@ -334,7 +369,7 @@ namespace ETP_NS
/**
* A customer sends to a store to discover all dataspaces available on the store.
* This function should be used with caution if Dataspace Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param storeLastWriteFilter An optional filter to limit the dataspaces returned by date/time last saved to the store.
* The store returns a list of dataspaces whose last changed date/time is greater than the specified date/time.
@@ -346,7 +381,7 @@ namespace ETP_NS
/**
* A customer sends to a store to create one or more dataspaces.
* This function should be used with caution if Dataspace Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param dataspaces ETP general map : One each for each dataspace the customer wants to add or update.
* @param return The map keys corresponding to the dataspaces which have been put successfully into the store.
@@ -356,7 +391,7 @@ namespace ETP_NS
/**
* A customer sends to a store to delete one or more dataspaces.
* This function should be used with caution if Dataspace Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param dataspaceUris ETP general map where the values must be the URIs for the dataspaces the customer wants to delete.
* @param return The map keys corresponding to the dataspaces which have been deleted successfully.
@@ -370,28 +405,19 @@ namespace ETP_NS
/**
* A customer sends to a store to discover information of particular dataspaces.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param dataspaceUris ETP general map : One each for each dataspace, identified by their URI, the customer wants to get info about.
* @param return The dataspaces the store could return.
*/
FETPAPI_DLL_IMPORT_OR_EXPORT std::vector getDataspaceInfo(const std::map& dataspaceUris);
- /**
- * Copy by reference some dataspaces into another one.
- * This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
- *
- * @param sourceDataspaceUris ETP general map : One each for each source dataspace to be copied. They are identified by their URI.
- * @param targetDataspaceUri The URI of the ETP dataspace where the sourceDataspaces have to be copied by reference.
- * @param return The map keys corresponding to the dataspaces which have been successfully copied into the target dataspace.
- */
- FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyDataspacesContent(const std::map& sourceDataspaceUris, const std::string& targetDataspaceUri);
-
/**
* A customer sends to a store to lock or unlock one or more dataspaces.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
+ * An OSDU locked dataspace will have its custom data "locked" to true. It will also have its custom datm "read-only" to true for all users.
+ * As a reminder, a custom data "read-only" can be true with a custom data "locked" to false in case the dataspace is not locked but in read only for the particular current ETP user.
*
* @param dataspaceUris ETP general map where the values must be the URIs for the dataspaces the customer wants to lock or unlock.
* @param lock true for locking the dataspaces, false to unlock the dataspaces
@@ -399,16 +425,27 @@ namespace ETP_NS
*/
FETPAPI_DLL_IMPORT_OR_EXPORT std::vector lockDataspaces(const std::map& dataspaceUris, bool lock);
+ /**
+ * Copy by reference some dataspaces into another one.
+ * This function should be used with caution if Dataspace OSDU Handlers have been overidden.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
+ *
+ * @param sourceDataspaceUris ETP general map : One each for each source dataspace to be copied. They are identified by their URI.
+ * @param targetDataspaceUri The URI of the ETP dataspace where the sourceDataspaces have to be copied by reference.
+ * @param return The map keys corresponding to the dataspaces which have been successfully copied into the target dataspace.
+ */
+ FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyDataspacesContent(const std::map& sourceDataspaceUris, const std::string& targetDataspaceUri);
+
/**
* Copy by reference some dataobjects into another dataspace.
* This function should be used with caution if Dataspace OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
- * @param sourceUris ETP general map : One each for each source dataobject to be copied. They are identified by their URI.
- * @param targetDataspaceUri The URI of the ETP dataspace where the source dataobjects have to be copied by reference.
- * @param return The map keys corresponding to the dataobjects which have been successfully copied into the target dataspace.
+ * @param sourceDataobjectUris ETP general map : One for each source dataobject to be copied. They are identified by their URI.
+ * @param targetDataspaceUri The URI of the ETP dataspace where the source dataobjects have to be copied by reference.
+ * @param return The map keys corresponding to the dataobjects which have been successfully copied into the target dataspace.
*/
- FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyToDataspace(const std::map& sourceUris, const std::string& targetDataspaceUri);
+ FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyToDataspace(const std::map& sourceDataobjectUris, const std::string& targetDataspaceUri);
/****************
*** DISCOVERY ***
@@ -417,7 +454,7 @@ namespace ETP_NS
/**
* A Customer sends this message to a store to discover data objects in the store.
* This function should be used with caution if Discovery Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param context Includes the URI of the dataspace or data object to begin the discovery, what specific types of data objects are of interest,
* and how many "levels" of relationships in the model to discover, among others.
@@ -438,7 +475,7 @@ namespace ETP_NS
/**
* A customer sends to a store to discover data objects that have been deleted (which are sometimes called "tombstones").
* This function should be used with caution if Discovery Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param dataspaceUri The URI of the dataspace where the objects were deleted.
* @param deleteTimeFilter An optional filter to filter the discovery on a date when the data object was deleted in a particular store.
@@ -459,7 +496,7 @@ namespace ETP_NS
/**
* A customer sends to a store to get one or more data objects, each identified by a URI.
* This function should be used with caution if Store Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param uris ETP general map where the values MUST be the URIs of a data object to be retrieved.
* @param return The received dataobjects in a map where the key makes the link between the asked uris and the received dataobjects.
@@ -469,7 +506,7 @@ namespace ETP_NS
/**
* A customer sends to a store to add or update one or more data objects.
* This function should be used with caution if Store Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param uris ETP general map where the values MUST be the data for each data object in the request, including each one's URI.
* @param return The map keys corresponding to the dataObjects which have been put successfully.
@@ -479,7 +516,7 @@ namespace ETP_NS
/**
* A customer sends to a store to delete one or more data objects from the store.
* This function should be used with caution if Store Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param uris ETP general map where the values MUST be the URIs of a data object to be deleted.
* @param return The map keys corresponding to the dataObjects which have been deleted successfully.
@@ -491,16 +528,20 @@ namespace ETP_NS
**********************/
/**
- * A customer sends to a store to copy by value a dataobject with potentially some of its sources based on their datatypes.
+ * A customer sends to a store to copy by value a dataobject in the same dataspace with potentially some of its sources based on their datatypes.
* This function should be used with caution if Store OSDU Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
- * @param uri The URI of the dataobject to be copied.
- * @param sourcesDepth The number of level if sources of the dataobject to be copied as well.
- * @param sourcesDepth The number of level if sources of the dataobject to be copied as well.
- * @param return The received dataobjects in a map where the key makes the link between the asked uris and the received dataobjects.
+ * @param sourceDataobjectUri The URI of the dataobject to be copied.
+ * @param sourcesDepth The "depth" or how many "levels" (or "jumps") in the data model (graph) from the starting point (specified by the URI) that you want to copy
+ * Depth MUST always be greater than zero.
+ * @param dataObjectTypes Optionally, specify the types of data objects that you want to copy.
+ * The default is an empty array, which means ALL data types negotiated for the current ETP session.
+ * They ARE case sensitive. EXAMPLES: "witsml20.Well", "witsml20.Wellbore", "prodml21.WellTest", "resqml20.obj_TectonicBoundaryFeature", "eml21.DataAssuranceRecord"
+ * To indicate that all data objects within a data schema version are supported, you can use a star (*) as a wildcard, EXAMPLE: "witsml20.*", "prodml21.*", "resqml20.*"
+ * @param return The received dataobjects in a map where the key makes the link between the asked uris and the received dataobjects.
*/
- FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyDataObjectsByValue(const std::string& uri, int32_t sourcesDepth = 0, const std::vector& dataObjectTypes = {});
+ FETPAPI_DLL_IMPORT_OR_EXPORT std::vector copyDataObjectsByValue(const std::string& sourceDataobjectUri, int32_t sourcesDepth = 0, const std::vector& dataObjectTypes = {});
/****************
** TRANSACTION **
@@ -509,7 +550,7 @@ namespace ETP_NS
/**
* A customer sends to a store to begin a transaction.
* This function should be used with caution if Transaction Handlers have been overidden.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
*
* @param dataspaceUris Indicates the dataspaces involved in the transaction. An empty STRING means the default dataspace. An empty LIST means all dataspaces.
* @param readOnly Indicates that the request in the transaction is read-only (i.e., "get" messages).
@@ -521,7 +562,7 @@ namespace ETP_NS
* A customer sends to a store to commit and end a transaction. This message implies that the customer
* has received from or sent to the store all the data required for some purpose. The customer asserts that
* the data sent in the scope of this transaction is a consistent unit of work.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
* @return Failure message or empty string if success
*/
FETPAPI_DLL_IMPORT_OR_EXPORT std::string rollbackTransaction();
@@ -530,7 +571,7 @@ namespace ETP_NS
* A customer sends to a store to cancel a transaction. The store MUST disregard any requests or data sent
* with that transaction. The current transaction (the one being canceled) MUST NOT change the state of
* the store.
- * It actually sends a message and block the current thread until a response has been received from the store.
+ * It actually sends a message and blocks the current thread until a response has been received from the store.
* @return Failure message or empty string if success
*/
FETPAPI_DLL_IMPORT_OR_EXPORT std::string commitTransaction();
@@ -570,7 +611,7 @@ namespace ETP_NS
/// which should be determined by the limits imposed by the WebSocket library used by each endpoint.
/// See https://www.boost.org/doc/libs/1_75_0/libs/beast/doc/html/beast/using_websocket/messages.html
/// and https://www.boost.org/doc/libs/1_75_0/libs/beast/doc/html/beast/ref/boost__beast__websocket__stream/read_message_max/overload1.html
- int64_t maxWebSocketMessagePayloadSize{ 16000000 };
+ uint64_t maxWebSocketMessagePayloadSize{ 16000000 };
/// Indicates if the websocket session is opened or not. It becomes false after the websocket handshake
std::atomic webSocketSessionClosed{ true };
/// Indicates if the ETP1.2 session is opened or not. It becomes false after the requestSession and openSession message
@@ -585,9 +626,11 @@ namespace ETP_NS
/// The next available message id.
std::atomic messageId;
/// The identifier of the session
- boost::uuids::uuid identifier;
+ boost::uuids::uuid identifier{ boost::uuids::nil_uuid() };
+ std::mutex identifierMutex;
/// Indicates that the endpoint request to close the websocket session
- bool isCloseRequested{ false };
+ bool isCloseRequested_{ false };
+ size_t reconnectionTryCount_ = 0;
AbstractSession() = default;
@@ -597,6 +640,11 @@ namespace ETP_NS
receivedBuffer.consume(receivedBuffer.size());
}
+ void setEtpSessionClosed(bool etpSessionClosed_) {
+ etpSessionClosed = etpSessionClosed_;
+ reconnectionTryCount_ = 0;
+ }
+
/**
* Write the current buffer on the web socket
*/
@@ -624,7 +672,7 @@ namespace ETP_NS
avro::encode(*e, mh);
avro::encode(*e, mb);
e->flush();
- const int64_t byteCount = e->byteCount();
+ const uint64_t byteCount = e->byteCount();
if (byteCount < maxWebSocketMessagePayloadSize) {
return std::make_tuple(mh.messageId, *avro::snapshot(*out).get(), nullptr);
@@ -713,5 +761,7 @@ namespace ETP_NS
protocolHandlers[protocolId] = coreHandlers;
}
+
+ friend void CoreHandlers::decodeMessageBody(const Energistics::Etp::v12::Datatypes::MessageHeader& mh, avro::DecoderPtr d);
};
}
diff --git a/src/etp/ClientSession.h b/src/etp/ClientSession.h
index f11bf40..86403ba 100644
--- a/src/etp/ClientSession.h
+++ b/src/etp/ClientSession.h
@@ -48,9 +48,7 @@ namespace ETP_NS
* Since this is a loop, you may want to operate this method on a dedicated thread not to block your program.
* This method returns only when the session is closed.
*/
- bool run() {
- successfulConnection = false;
-
+ void run() {
// Look up the domain name before to run the session
// It is important to do this before to run the io context. Otherwise running the io context would return immediately if nothing has to be done.
resolver.async_resolve(
@@ -66,17 +64,39 @@ namespace ETP_NS
// Run will return only when there will no more be any uncomplete operations (such as a reading operation for example)
getIoContext().run();
- return successfulConnection;
+ // Try to reconnect up to 10 times
+ if (!isCloseRequested_ && reconnectionTryCount_ < 10) {
+ ++reconnectionTryCount_;
+ std::cerr << "Session has been disconnected, trying to reconnect... " << reconnectionTryCount_ << "/10" << std::endl;
+ getIoContext().restart();
+ run();
+ }
+
+ if (!isCloseRequested_ && reconnectionTryCount_ >= 10) {
+ std::cerr << "Could not reconnect after 10 retries... Give up and close" << reconnectionTryCount_ << "/10" << std::endl;
+ isCloseRequested_ = true;
+ }
}
- virtual void on_resolve(boost::system::error_code ec, tcp::resolver::results_type results) = 0;
+ void on_resolve(boost::system::error_code ec, tcp::resolver::results_type results) {
+ if (ec) {
+ std::cerr << "on_resolve : " << ec.message() << std::endl;
+ }
+
+ asyncConnect(results);
+ }
+
+ virtual void asyncConnect(const tcp::resolver::results_type& results) = 0;
+
virtual bool isTls() const = 0;
void on_handshake(boost::system::error_code ec)
{
if (ec) {
- std::cerr << "on_handshake : " << ec.message() << std::endl;
- std::cerr << "Sometimes some ETP server require a trailing slash at the end of their URL. Did you also check your optional \"data-partition-id\" additional Header Field?" << std::endl;
+ std::cerr << "on WS handshake, error code number : " << ec.value() << std::endl;
+ std::cerr << "on WS handshake, error message : " << ec.message() << std::endl;
+ std::cerr << "on WS handshake, error category : " << ec.category().name() << std::endl;
+ std::cerr << "Sometimes some ETP server require a trailing slash at the end of their URL. Did you also check your optional \"data-partition-id\" additional Header Field? Has your token expired?" << std::endl;
return;
}
@@ -84,7 +104,7 @@ namespace ETP_NS
responseType[boost::beast::http::field::sec_websocket_protocol] != "etp12.energistics.org")
std::cerr << "The client MUST specify the Sec-Websocket-Protocol header value of etp12.energistics.org, and the server MUST reply with the same" << std::endl;
- successfulConnection = true;
+ fesapi_log("Now connected to Websocket");
webSocketSessionClosed = false;
send(requestSession, 0, 0x02);
@@ -104,7 +124,6 @@ namespace ETP_NS
std::map additionalHandshakeHeaderFields_;
websocket::response_type responseType; // In order to check handshake sec_websocket_protocol
Energistics::Etp::v12::Protocol::Core::RequestSession requestSession;
- bool successfulConnection = false;
/**
* @param initializationParams The initialization parameters of the session including IP host, port, requestedProtocols, supportedDataObjects
@@ -114,7 +133,7 @@ namespace ETP_NS
*/
ClientSession(
InitializationParameters const* initializationParams, const std::string& target, const std::string& etpServerAuth, const std::string& proxyAuth = "") :
- ioc(4),
+ ioc(),
resolver(ioc),
etpServerHost(initializationParams->getEtpServerHost()),
etpServerPort(std::to_string(initializationParams->getEtpServerPort())),
diff --git a/src/etp/ClientSessionLaunchers.cpp b/src/etp/ClientSessionLaunchers.cpp
index 43f672f..8b777b1 100644
--- a/src/etp/ClientSessionLaunchers.cpp
+++ b/src/etp/ClientSessionLaunchers.cpp
@@ -67,12 +67,15 @@ std::shared_ptr ETP_NS::ClientSessionLaunchers::createCli
#ifdef WITH_ETP_SSL
if (initializationParams->getEtpServerPort() == 443 || initializationParams->isTlsForced()) {
// The SSL context is required, and holds certificates
- boost::asio::ssl::context ctx{ boost::asio::ssl::context::sslv23_client };
+ // From official ETP documentation : If the ETP server is supporting TLS, it MUST support v1.2 or greater
+ boost::asio::ssl::context ctx{ boost::asio::ssl::context::tlsv12_client };
ctx.set_default_verify_paths();
ctx.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::no_sslv3
+ | boost::asio::ssl::context::no_tlsv1
+ | boost::asio::ssl::context::no_tlsv1_1
| boost::asio::ssl::context::single_dh_use
);
@@ -95,7 +98,7 @@ std::shared_ptr ETP_NS::ClientSessionLaunchers::createCli
std::size_t preferredMaxFrameSize = getNegotiatedMaxWebSocketFramePayloadSize(restClientSession->getResponse().body(), initializationParams->getPreferredMaxFrameSize());
- result = std::make_shared(ctx, initializationParams, "/" + initializationParams->getEtpServerUrlPath(),
+ result = std::make_shared(std::move(ctx), initializationParams, "/" + initializationParams->getEtpServerUrlPath(),
authorization, proxyAuthorization,
initializationParams->getAdditionalHandshakeHeaderFields(), preferredMaxFrameSize);
}
diff --git a/src/etp/EtpHelpers.cpp b/src/etp/EtpHelpers.cpp
index a194952..366eea7 100644
--- a/src/etp/EtpHelpers.cpp
+++ b/src/etp/EtpHelpers.cpp
@@ -18,15 +18,16 @@ under the License.
-----------------------------------------------------------------------*/
#include "EtpHelpers.h"
-#if (defined(_WIN32) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))))
#include
-#endif
-#include "AbstractSession.h"
#include "EtpException.h"
std::string ETP_NS::EtpHelpers::getDataObjectType(const std::string& uri)
{
+ if (!ETP_NS::EtpHelpers::validateDataObjectUri(uri)) {
+ throw ETP_NS::EtpException(9, "The dataobject ETP URI \"" + uri + "\" is invalid.");
+ }
+
const std::size_t lastSlash = uri.find_last_of("/");
const std::size_t lastOpenParenthesis = uri.find_last_of("(");
return lastSlash != std::string::npos && lastOpenParenthesis != std::string::npos
@@ -36,9 +37,13 @@ std::string ETP_NS::EtpHelpers::getDataObjectType(const std::string& uri)
std::string ETP_NS::EtpHelpers::getDataspaceUri(const std::string& uri)
{
+ if (!ETP_NS::EtpHelpers::validateUri(uri)) {
+ throw ETP_NS::EtpException(9, "The ETP URI \"" + uri + "\" is invalid.");
+ }
+
const size_t dataspacePos = uri.find("dataspace('");
if (dataspacePos == std::string::npos) {
- return "";
+ return "eml:///";
}
const size_t closingParenthesisPos = uri.find(')', dataspacePos);
@@ -48,72 +53,23 @@ std::string ETP_NS::EtpHelpers::getDataspaceUri(const std::string& uri)
return uri.substr(0, closingParenthesisPos+1);
}
-Energistics::Etp::v12::Datatypes::ErrorInfo ETP_NS::EtpHelpers::validateUri(const std::string & uri, ETP_NS::AbstractSession* session)
+bool ETP_NS::EtpHelpers::validateUri(const std::string & uri)
{
- Energistics::Etp::v12::Datatypes::ErrorInfo errorInfo;
- errorInfo.code = -1;
// Regular expressions are not handled before GCC 4.9
// https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions
-#if (defined(_WIN32) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))))
- const bool result =
+ return
std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)])?", std::regex::ECMAScript)) ||
std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)]/)?(resqml20|eml20)\.obj_[a-zA-Z0-9]+[(][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}(,.*)?[)]", std::regex::ECMAScript)) ||
- std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)]/)?(witsml|resqml|prodml|eml)([0-9]{2})\[a-zA-Z0-9]+[(][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}(,.*)?[)]", std::regex::ECMAScript));
- if (!result) {
- std::cerr << "The URI \"" + uri + "\" is invalid." << std::endl;
- }
-#else
- const bool result = uri.find("eml:///") == 0;
-#endif
-
- if (!result) {
- errorInfo.code = 9;
- errorInfo.message = "The URI " + uri + " is invalid.";
-
- if (session != nullptr) {
- Energistics::Etp::v12::Protocol::Core::ProtocolException error;
- error.error.emplace(errorInfo);
- session->send(error);
- }
- }
-
- return errorInfo;
-
+ std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)]/)?(witsml|resqml|prodml|eml)([0-9]{2})\.[a-zA-Z0-9]+[(][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}(,.*)?[)]", std::regex::ECMAScript));
}
-Energistics::Etp::v12::Datatypes::ErrorInfo ETP_NS::EtpHelpers::validateDataObjectUri(const std::string & uri, AbstractSession* session)
+bool ETP_NS::EtpHelpers::validateDataObjectUri(const std::string & uri)
{
- Energistics::Etp::v12::Datatypes::ErrorInfo errorInfo;
- errorInfo.code = -1;
// Regular expressions are not handled before GCC 4.9
// https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions
-#if (defined(_WIN32) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))))
- const bool result = (uri.find("resqml20") != std::string::npos || uri.find("eml20") != std::string::npos)
+ return (uri.find("resqml20") != std::string::npos || uri.find("eml20") != std::string::npos)
? std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)]/)?(resqml20|eml20)\.obj_[a-zA-Z0-9]+[(][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}(,.*)?[)]", std::regex::ECMAScript))
: std::regex_match(uri, std::regex("^eml:///(dataspace[(]'.*'[)]/)?(witsml|resqml|prodml|eml)([0-9]{2})\.[a-zA-Z0-9]+[(][a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}(,.*)?[)]", std::regex::ECMAScript));
- if (!result) {
- std::cerr << "The data object URI \"" + uri + "\" is invalid." << std::endl;
- }
-#else
- const bool result = uri.find("eml:///") == 0 &&
- (uri.find("resqml20.obj_") != std::string::npos || uri.find("eml20.obj_") != std::string::npos ||
- uri.find("witsml20.") != std::string::npos || uri.find("eml21.") != std::string::npos ||
- uri.find("prodml21.") != std::string::npos || uri.find("eml22.") != std::string::npos ||
- uri.find("witsml21.") != std::string::npos);
-#endif
-
- if (!result) {
- errorInfo.code = 9;
- errorInfo.message = "The data object URI " + uri + " is invalid.";
-
- if (session != nullptr) {
- Energistics::Etp::v12::Protocol::Core::ProtocolException error;
- error.error.emplace(errorInfo);
- session->send(error);
- }
- }
-
- return errorInfo;
}
Energistics::Etp::v12::Protocol::Core::ProtocolException ETP_NS::EtpHelpers::buildSingleMessageProtocolException(int32_t m_code, const std::string & m_message)
@@ -131,11 +87,11 @@ std::pair ETP_NS::EtpHelpers::getUuidAndVersionFromUri
{
std::pair result;
- Energistics::Etp::v12::Datatypes::ErrorInfo error = ETP_NS::EtpHelpers::validateDataObjectUri(uri);
- if (error.code > -1) {
- throw ETP_NS::EtpException(error.code, error.message);
+ if (!ETP_NS::EtpHelpers::validateDataObjectUri(uri)) {
+ throw ETP_NS::EtpException(9, "Invalid URI");
}
+ // old code to be updated
if (uri[6] != '/') {
throw ETP_NS::EtpException(2, "The URI " + uri + " uses some dataspaces. This agent does not support dataspace.");
}
diff --git a/src/etp/EtpHelpers.h b/src/etp/EtpHelpers.h
index 80b509e..aa30a4a 100644
--- a/src/etp/EtpHelpers.h
+++ b/src/etp/EtpHelpers.h
@@ -40,7 +40,6 @@ namespace COMMON_NS
namespace ETP_NS
{
- class AbstractSession;
namespace EtpHelpers {
@@ -61,14 +60,14 @@ namespace ETP_NS
FETPAPI_DLL_IMPORT_OR_EXPORT std::string getDataspaceUri(const std::string& uri);
/**
- * @param session Provide this parameter if you want to send a protocol exception in case of non validation.
+ * Validate an ETP URI
*/
- FETPAPI_DLL_IMPORT_OR_EXPORT Energistics::Etp::v12::Datatypes::ErrorInfo validateUri(const std::string & uri, AbstractSession* session = nullptr);
+ FETPAPI_DLL_IMPORT_OR_EXPORT bool validateUri(const std::string& uri);
/**
- * @param session Provide this parameter if you want to send a protocol exception in case of non validation.
+ * Validate an ETP dataobject URI
*/
- FETPAPI_DLL_IMPORT_OR_EXPORT Energistics::Etp::v12::Datatypes::ErrorInfo validateDataObjectUri(const std::string & uri, AbstractSession* session = nullptr);
+ FETPAPI_DLL_IMPORT_OR_EXPORT bool validateDataObjectUri(const std::string& uri);
/**
* Build a protocol exception message which only contains a single error message (not a messsage map).
diff --git a/src/etp/EtpMessages.h b/src/etp/EtpMessages.h
index f60b982..ae35941 100644
--- a/src/etp/EtpMessages.h
+++ b/src/etp/EtpMessages.h
@@ -1,18 +1,20 @@
#ifndef ETP_MESSAGES__
#define ETP_MESSAGES__
+#include
#include
+#include
#include