-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Develop RDFox adapter for rest api integration
Establish Connection to RDFox REST API Data Store Management Data Loading in Turtle Format SPARQL Query Execution Error Handling Unit and Integration Tests Documentation Updates Signed-off-by: Haonan Qiu <[email protected]>
- Loading branch information
q632394
committed
Oct 17, 2024
1 parent
ffce704
commit 24b871e
Showing
17 changed files
with
617 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#include "helper.h" | ||
|
||
#include <algorithm> | ||
|
||
/** | ||
* @brief Converts a given string to lowercase. | ||
* | ||
|
8 changes: 7 additions & 1 deletion
8
cdsp/knowledge-layer/connector/websocket-client/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
cdsp/knowledge-layer/symbolic-reasoner/rdfox/rdfox-adapter/README.md
This file was deleted.
Oops, something went wrong.
4 changes: 3 additions & 1 deletion
4
...r/rdfox/rdfox-install-test/CMakeLists.txt → ...r/rdfox/rdfox-service-test/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
25 changes: 25 additions & 0 deletions
25
cdsp/knowledge-layer/symbolic-reasoner/rdfox/src/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# RDFoxAdapter | ||
|
||
The RDFoxAdapter class provides an interface for interacting with an RDFox server over HTTP. It enables operations like checking the existence of a datastore, creating a datastore, loading data in Turtle format, querying using SPARQL, and deleting a datastore. | ||
|
||
> [!NOTE] Data store | ||
> When the RDFoxAdapter initializes creates (if is does not exists) a datastore called `vehicle_ds` in the RDFox server. | ||
## Features | ||
|
||
- **Initialize a Datastore:** Checks if a specified datastore exists on the RDFox server. If not, it creates the datastore. | ||
- **Load Data:** Loads Turtle data into a specified datastore. | ||
- **Query Data:** Executes SPARQL queries against the RDFox datastore and retrieves results. | ||
- **Delete Datastore:** Removes a specified datastore from the RDFox server. | ||
- **Send HTTP Requests:** Supports sending GET and POST HTTP requests to interact with RDFox. | ||
|
||
## Methods | ||
|
||
- **initialize():** Ensures the datastore is present; creates it if missing. | ||
- **loadData(const std::string& ttl_data):** Loads Turtle data into the datastore. | ||
- **queryData(const std::string& sparql_query):** Executes a SPARQL query and returns the result. | ||
- **deleteDataStore():** Deletes the datastore if it exists. | ||
|
||
> [!NOTE] See test | ||
> - [../tests/test_rdfox_adapter_integration.cpp](../tests/test_rdfox_adapter_integration.cpp) | ||
> - [../tests/test_rdfox_adapter_unit.cpp](../tests/test_rdfox_adapter_unit.cpp) |
179 changes: 179 additions & 0 deletions
179
cdsp/knowledge-layer/symbolic-reasoner/rdfox/src/rdfox-adapter.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
#include "rdfox-adapter.h" | ||
|
||
#include <iostream> | ||
|
||
RDFoxAdapter::RDFoxAdapter(const std::string& host, const std::string& port, | ||
const std::string& auth_base64, | ||
const std::string& data_store = "vehicle_ds") | ||
: host_(host), | ||
port_(port), | ||
auth_header_base64_("Basic " + auth_base64), | ||
data_store_(data_store) { | ||
std::cout << "Initializing RDFox adapter..." << std::endl; | ||
} | ||
|
||
/** | ||
* @brief Initializes the RDFoxAdapter by ensuring the data store is created. | ||
* | ||
* This method checks if the data store specified by `data_store_` exists. | ||
* If the data store exists, it logs a message indicating its existence. | ||
* If the data store does not exist, it attempts to create it by sending | ||
* a POST request to the appropriate endpoint. If the creation is successful, | ||
* a success message is logged. Otherwise, an exception is thrown. | ||
* | ||
* @throws std::runtime_error if the data store creation fails. | ||
*/ | ||
void RDFoxAdapter::initialize() { | ||
// checks if the data store exists, create it if not | ||
if (checkDataStore()) { | ||
std::cout << "Data store '" + data_store_ + "' is already created." << std::endl; | ||
} else { | ||
std::cout << "Data store '" << data_store_ << "' does not exist. Creating it..." | ||
<< std::endl; | ||
// Creates a data store | ||
std::string target = "/datastores/" + data_store_; | ||
if (sendPostRequest(target, "", "application/json")) { | ||
std::cout << "Data store '" << data_store_ << "' created successfully." << std::endl; | ||
} else { | ||
throw std::runtime_error("Failed to create datastore '" + data_store_ + "'"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Loads Turtle data into the RDFox datastore. | ||
* | ||
* @param ttl_data A string containing the Turtle data to be loaded into the datastore. | ||
* @return A boolean value indicating whether the data was successfully loaded. | ||
*/ | ||
bool RDFoxAdapter::loadData(const std::string& ttl_data) { | ||
std::string target = "/datastores/" + data_store_ + "/content"; | ||
return sendPostRequest(target, ttl_data, "text/turtle") ? true : false; | ||
}; | ||
|
||
/** | ||
* Executes a SPARQL query against the RDFox datastore. | ||
* | ||
* @param sparql_query The SPARQL query string to be executed. | ||
* @return The response from the datastore as a string if the query is successful, | ||
* otherwise an empty string. | ||
*/ | ||
std::string RDFoxAdapter::queryData(const std::string& sparql_query) { | ||
std::string target = "/datastores/" + data_store_ + "/sparql"; | ||
auto response = sendPostRequest(target, sparql_query, "application/sparql-query"); | ||
return response.has_value() ? response.value() : ""; | ||
} | ||
|
||
bool RDFoxAdapter::deleteDataStore() { | ||
if (checkDataStore()) { | ||
std::string target = "/datastores/" + data_store_; | ||
std::string responseBody; | ||
if (sendRequest(http::verb::delete_, target, "", "", "", responseBody)) { | ||
std::cout << "Data store '" + data_store_ + "' have been removed successfully." | ||
<< std::endl; | ||
} else { | ||
std::cout << "Data store '" + data_store_ + "' could not be removed." << std::endl; | ||
return false; | ||
} | ||
} else { | ||
std::cout << "Data store '" + data_store_ + "' does not exists anymore." << std::endl; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* @brief Checks if the data store exists on the server. | ||
* | ||
* @return true if the data store is found in the server's response; false otherwise. | ||
*/ | ||
bool RDFoxAdapter::checkDataStore() { | ||
std::string target = "/datastores"; | ||
std::string response = sendGetRequest(target, "text/csv; charset=UTF-8"); | ||
if (response.find(data_store_) != std::string::npos) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
std::optional<std::string> RDFoxAdapter::sendPostRequest(const std::string& target, | ||
const std::string& body, | ||
const std::string& contentType) { | ||
std::string responseBody; | ||
if (sendRequest(http::verb::post, target, body, contentType, "", responseBody)) { | ||
return responseBody; | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
std::string RDFoxAdapter::sendGetRequest(const std::string& target, const std::string& acceptType) { | ||
std::string responseBody; | ||
if (sendRequest(http::verb::get, target, "", "", acceptType, responseBody)) { | ||
return responseBody; | ||
} | ||
return ""; | ||
} | ||
|
||
/** | ||
* Sends an HTTP request to a specified target and retrieves the response. | ||
* | ||
* @param method The HTTP method to use for the request (e.g., GET, POST). | ||
* @param target The target URI for the request. | ||
* @param body The body content to send with the request. | ||
* @param contentType The MIME type of the body content. | ||
* @param acceptType The MIME type that the client is willing to accept in the response. | ||
* @param responseBody A reference to a string where the response body will be stored. | ||
* @return True if the request was successful and the response status is OK, Created, or No Content; | ||
* false otherwise. | ||
*/ | ||
bool RDFoxAdapter::sendRequest(http::verb method, const std::string& target, | ||
const std::string& body, const std::string& contentType, | ||
const std::string& acceptType, std::string& responseBody) { | ||
net::io_context ioc; | ||
tcp::resolver resolver(ioc); | ||
tcp::socket socket(ioc); | ||
|
||
try { | ||
// Resolve and connect to the host | ||
auto const results = resolver.resolve(host_, port_); | ||
net::connect(socket, results.begin(), results.end()); | ||
|
||
// Set up the HTTP request | ||
http::request<http::string_body> req{method, target, 11}; | ||
req.set(http::field::host, host_); | ||
req.set(http::field::authorization, auth_header_base64_); | ||
if (!contentType.empty()) { | ||
req.set(http::field::content_type, contentType); | ||
} | ||
if (!acceptType.empty()) { | ||
req.set(http::field::accept, acceptType); | ||
} | ||
req.body() = body; | ||
req.prepare_payload(); | ||
|
||
// Send the request and receive the response | ||
http::write(socket, req); | ||
beast::flat_buffer buffer; | ||
http::response<http::string_body> res; | ||
http::read(socket, buffer, res); | ||
|
||
responseBody = res.body(); | ||
|
||
if (res.result() != http::status::ok && res.result() != http::status::created && | ||
res.result() != http::status::no_content) { | ||
std::cerr << createErrorMessage(res.body(), res.result_int()) << std::endl; | ||
return false; | ||
} | ||
return true; | ||
} catch (const beast::system_error& e) { | ||
std::cerr << "Network error: " << e.what() << std::endl; | ||
return false; | ||
} catch (const std::exception& e) { | ||
std::cerr << "Error in request: " << e.what() << std::endl; | ||
return false; | ||
} | ||
} | ||
|
||
std::string RDFoxAdapter::createErrorMessage(const std::string& error_msg, int error_code) { | ||
return error_msg + " (Code: " + std::to_string(error_code) + ")"; | ||
} |
Oops, something went wrong.