diff --git a/frontend/Makefile b/frontend/Makefile index 56386b6dbb0d0b1e6c7a17054c37485ccee4baa4..45d9a5e9cc355255402525de44bdb1153507512d 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -6,7 +6,7 @@ all: test_client frontend_ssi.so # XrdSsi server plugin -frontend_ssi.so: TestSsiServiceProvider.o TestSsiService.o TestSsiRequestProc.o test.pb.o +frontend_ssi.so: TestSsiServiceProvider.o TestSsiRequestProc.o test.pb.o $(LINK.cc) -shared $^ $(LOADLIBES) $(LDLIBS) -o $@ # XrdSsi test client @@ -35,4 +35,4 @@ clean: rm -f frontend_ssi.o frontend_ssi.so \ test_client test_client.o TestSsiRequest.o \ test.pb.cc test.pb.h test.pb.o \ - TestSsiRequestProc.o TestSsiService.o TestSsiServiceProvider.o + TestSsiRequestProc.o TestSsiServiceProvider.o diff --git a/frontend/TestSsiClient.h b/frontend/TestSsiClient.h index f82c1b968829459070064b7d9dfcbc5b76bc9a94..b5a228f51e6f628dca97e378cfbd6b91ae166702 100644 --- a/frontend/TestSsiClient.h +++ b/frontend/TestSsiClient.h @@ -2,10 +2,10 @@ #define __TEST_SSI_CLIENT_H #include <iostream> -#include <stdexcept> #include <XrdSsi/XrdSsiProvider.hh> #include <XrdSsi/XrdSsiService.hh> +#include "XrdSsiException.h" #include "TestSsiRequest.h" // Probably we want to allow multiple resources, e.g. streaming and non-streaming versions of the service @@ -15,22 +15,6 @@ const std::string TestSsiResource("/test"); -// Class to convert a XRootD error into a std::exception - -class XrdSsiException : public std::exception -{ -public: - XrdSsiException(const std::string &err_msg) : error_msg(err_msg) {} - XrdSsiException(const XrdSsiErrInfo &eInfo) : error_msg(eInfo.Get()) {} - - const char* what() const noexcept { return error_msg.c_str(); } - -private: - std::string error_msg; -}; - - - // XrdSsiProviderClient is instantiated and managed by the SSI library extern XrdSsiProvider *XrdSsiProviderClient; @@ -84,17 +68,17 @@ public: // Serialize the request object - std::string data; + std::string request_str; - if(!request_msg.SerializeToString(&data)) + if(!request_msg.SerializeToString(&request_str)) { throw XrdSsiException("SerializeToString() failed"); } - requestP = new TestSsiRequest(data, timeout); + requestP = new TestSsiRequest(request_str, timeout); // Transfer ownership of the request to the service object - // TestSsiRequest handles deletion of the data buffer, so we can allow the pointer to go out-of-scope + // TestSsiRequest handles deletion of the request buffer, so we can allow the pointer to go out-of-scope serverP->ProcessRequest(*requestP, resource); diff --git a/frontend/TestSsiRequestProc.cpp b/frontend/TestSsiRequestProc.cpp index 44b629cef24df55e69bb1c6c4d20158a976d141c..6e761eefa38c4528ae1f0a5b95e963545203f2bf 100644 --- a/frontend/TestSsiRequestProc.cpp +++ b/frontend/TestSsiRequestProc.cpp @@ -1,46 +1,16 @@ #include <iostream> +#include "XrdSsiException.h" #include "TestSsiRequestProc.h" +#include "TestSsiProtobuf.h" -void RequestProc::Execute() -{ - using namespace std; - - const string metadata("Have some metadata!"); - const string response("Have a response!"); - - cerr << "Execute()" << endl; - - // Deserialize the Request - - //int reqLen; - //const char *reqData = GetRequest(reqLen); - - // Parse the request - - ReleaseRequestBuffer(); // Optional - - // Perform the requested action - - // Optional: send alerts - - // Optional: send metadata ahead of the response +// This is for specialized private methods called by RequestProc::Execute to handle actions, alerts +// and metadata - SetMetadata(metadata.c_str(), metadata.size()); - - // Send the response - - SetResponse(response.c_str(), response.size()); -} - - - -void RequestProc::Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel) +template <> +void RequestProc<xrdssi::test::Request, xrdssi::test::Result>::ExecuteMetadata() { - using namespace std; - - cerr << "Finished()" << endl; - - // Reclaim any allocated resources + const std::string metadata("Have some metadata!"); + SetMetadata(metadata.c_str(), metadata.size()); } diff --git a/frontend/TestSsiRequestProc.h b/frontend/TestSsiRequestProc.h index 4499b95827a99114c2450f366db17cd3412802ee..82e3e2aef97d79702388468c0d1cb0d05ea13323 100644 --- a/frontend/TestSsiRequestProc.h +++ b/frontend/TestSsiRequestProc.h @@ -2,6 +2,7 @@ #define __TEST_SSI_REQUEST_PROC_H #include <XrdSsi/XrdSsiResponder.hh> +#include "XrdSsiException.h" /* * The XrdSsiResponder class knows how to safely interact with the request object. It allows handling asynchronous @@ -17,14 +18,92 @@ * RequestProc is a kind of agent object that the service object creates for each request that it receives. */ +template <typename RequestType, typename ResponseType> class RequestProc : public XrdSsiResponder { public: - RequestProc() {} - virtual ~RequestProc() {} + RequestProc() {} + virtual ~RequestProc() {} void Execute(); virtual void Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel=false) override; + +private: + void ExecuteAction() {} + void ExecuteAlerts() {} + void ExecuteMetadata() {} + + RequestType request; + ResponseType response; }; + + +template <typename RequestType, typename ResponseType> +void RequestProc<RequestType, ResponseType>::Execute() +{ + using namespace std; + + cerr << "Execute()" << endl; + + // Unpack the Request buffer into a string object. + // + // We need to construct this with an explicit length, as request_buffer is a binary buffer, not a + // null-terminated string. + + int request_len; + const char *request_buffer = GetRequest(request_len); + const std::string request_str(request_buffer, request_len); + + // Deserialize the Request + + if(!request.ParseFromString(request_str)) + { + throw XrdSsiException("ParseFromString() failed"); + } + + // Release the request buffer (optional, perhaps it is more efficient to reuse it) + + ReleaseRequestBuffer(); + + // Perform the requested action + + ExecuteAction(); + + // Optional: send alerts + + ExecuteAlerts(); + + // Optional: send metadata ahead of the response + + ExecuteMetadata(); + + // Serialize the Response + + std::string response_str; + + if(!response.SerializeToString(&response_str)) + { + throw XrdSsiException("SerializeToString() failed"); + } + + // Send the response + + SetResponse(response_str.c_str(), response_str.length()); +} + + + +// Create specialized versions of this method to handle cancellation/cleanup for specific message types + +template <typename RequestType, typename ResponseType> +void RequestProc<RequestType, ResponseType>::Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel) +{ + using namespace std; + + cerr << "Finished()" << endl; + + // Reclaim any allocated resources +} + #endif diff --git a/frontend/TestSsiService.cpp b/frontend/TestSsiService.cpp deleted file mode 100644 index 90d0dfc10b2560065ced27e409fb519ac20b6cb4..0000000000000000000000000000000000000000 --- a/frontend/TestSsiService.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include <iostream> - -#include "TestSsiService.h" -#include "TestSsiRequestProc.h" - - - -void TestSsiService::ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef) -{ - using namespace std; - - cerr << "Called ProcessRequest()" << endl; - - RequestProc theProcessor; - - // Bind the processor to the request. This works because the - // it inherited the BindRequest method from XrdSsiResponder. - - theProcessor.BindRequest(reqRef); - - // Execute the request, upon return the processor is deleted - - theProcessor.Execute(); - - // Unbind the request from the responder (required) - - theProcessor.UnBindRequest(); - - cerr << "ProcessRequest.UnBind()" << endl; -} - diff --git a/frontend/TestSsiService.h b/frontend/TestSsiService.h index f679869a4c9290f66bcffb9320c4a9f13673eb28..168faad9992bb57ebd3bec4023ee107c9a8b4383 100644 --- a/frontend/TestSsiService.h +++ b/frontend/TestSsiService.h @@ -3,30 +3,55 @@ #include <XrdSsi/XrdSsiService.hh> +#include "TestSsiRequestProc.h" + /* * Service Object, obtained using GetService() method of the TestSsiServiceProvider factory */ +template <typename RequestType, typename ResponseType> class TestSsiService : public XrdSsiService { public: + TestSsiService() {} + virtual ~TestSsiService() {} + + // The pure abstract method ProcessRequest() is called when the client calls its ProcessRequest() method to hand off + // its request and resource objects. The client’s request and resource objects are transmitted to the server and passed + // into the service’s ProcessRequest() method. -// The pure abstract method ProcessRequest() is called when the client calls its ProcessRequest() method to hand off -// its request and resource objects. The client’s request and resource objects are transmitted to the server and passed -// into the service’s ProcessRequest() method. + virtual void ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef) override; -virtual void ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef) override; + // Additional virtual methods: + // + // Attach(): optimize handling of detached requests + // Prepare(): perform preauthorization and resource optimization +}; -// Additional virtual methods: -// -// Attach(): optimize handling of detached requests -// Prepare(): perform preauthorization and resource optimization - TestSsiService() {} -virtual ~TestSsiService() {} -}; +template <typename RequestType, typename ResponseType> +void TestSsiService<RequestType, ResponseType>::ProcessRequest(XrdSsiRequest &reqRef, XrdSsiResource &resRef) +{ + std::cerr << "Called ProcessRequest()" << std::endl; + + RequestProc<RequestType, ResponseType> processor; + + // Bind the processor to the request. Inherits the BindRequest method from XrdSsiResponder. + + processor.BindRequest(reqRef); + + // Execute the request, upon return the processor is deleted + + processor.Execute(); + + // Unbind the request from the responder (required) + + processor.UnBindRequest(); + + std::cerr << "ProcessRequest.UnBind()" << std::endl; +} #endif diff --git a/frontend/TestSsiServiceProvider.cpp b/frontend/TestSsiServiceProvider.cpp index 9bfac64216f10d6bd7bc8256b93523c57925fb5f..6e2c24607f1c2dfdce3700454b7d65a1e36130e4 100644 --- a/frontend/TestSsiServiceProvider.cpp +++ b/frontend/TestSsiServiceProvider.cpp @@ -43,7 +43,7 @@ XrdSsiService* TestSsiServiceProvider::GetService(XrdSsiErrInfo &eInfo, const st cerr << "Called GetService(" << contact << "," << oHold << ")" << endl; - XrdSsiService *ptr = new TestSsiService; + XrdSsiService *ptr = new TestSsiService<xrdssi::test::Request, xrdssi::test::Result>; return ptr; } diff --git a/frontend/XrdSsiException.h b/frontend/XrdSsiException.h new file mode 100644 index 0000000000000000000000000000000000000000..0dd36f15d58e8afc23c93dcac24bbe0c22b93b38 --- /dev/null +++ b/frontend/XrdSsiException.h @@ -0,0 +1,24 @@ +#ifndef __XRD_SSI_EXCEPTION_H +#define __XRD_SSI_EXCEPTION_H + +// Class to convert a XRootD error into a std::exception +// Perhaps should be part of XRootD? + +#include <stdexcept> +#include <XrdSsi/XrdSsiErrInfo.hh> + + + +class XrdSsiException : public std::exception +{ +public: + XrdSsiException(const std::string &err_msg) : error_msg(err_msg) {} + XrdSsiException(const XrdSsiErrInfo &eInfo) : error_msg(eInfo.Get()) {} + + const char* what() const noexcept { return error_msg.c_str(); } + +private: + std::string error_msg; +}; + +#endif