diff --git a/livesupport/src/modules/core/include/LiveSupport/Core/XmlRpcTools.h b/livesupport/src/modules/core/include/LiveSupport/Core/XmlRpcTools.h index ad510f85d..7c0b555eb 100644 --- a/livesupport/src/modules/core/include/LiveSupport/Core/XmlRpcTools.h +++ b/livesupport/src/modules/core/include/LiveSupport/Core/XmlRpcTools.h @@ -681,6 +681,18 @@ class XmlRpcTools XmlRpc::XmlRpcValue & returnValue) throw (); + /** + * Extract a fault string from the XML-RPC parameters. + * + * @param xmlRpcValue the XML-RPC parameter to extract from. + * @return a fault string that was found in the XML-RPC parameter. + * @exception std::invalid_argument if there was no "faultString" + * member in xmlRpcValue. + */ + static Ptr::Ref + extractFaultString(XmlRpc::XmlRpcValue & xmlRpcValue) + throw (std::invalid_argument); + /** * Convert a fault string to an XmlRpcValue. * diff --git a/livesupport/src/modules/core/src/XmlRpcTools.cxx b/livesupport/src/modules/core/src/XmlRpcTools.cxx index 874c0398f..e42953f9b 100644 --- a/livesupport/src/modules/core/src/XmlRpcTools.cxx +++ b/livesupport/src/modules/core/src/XmlRpcTools.cxx @@ -1066,6 +1066,25 @@ XmlRpcTools :: pathToXmlRpcValue( } +/*------------------------------------------------------------------------------ + * Extract a fault string from the XML-RPC parameters. + *----------------------------------------------------------------------------*/ +Ptr::Ref +XmlRpcTools :: extractFaultString(XmlRpc::XmlRpcValue & xmlRpcValue) + throw (std::invalid_argument) +{ + if (!xmlRpcValue.hasMember(faultStringName) + || xmlRpcValue[faultStringName].getType() + != XmlRpc::XmlRpcValue::TypeString) { + throw std::invalid_argument("missing or bad faultString argument"); + } + + Ptr::Ref faultString(new Glib::ustring( + xmlRpcValue[faultStringName] )); + return faultString; +} + + /*------------------------------------------------------------------------------ * Convert a fault string to an XmlRpcValue. *----------------------------------------------------------------------------*/ diff --git a/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h b/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h index b06d3b185..383f1c9ba 100644 --- a/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h +++ b/livesupport/src/modules/schedulerClient/include/LiveSupport/SchedulerClient/SchedulerClientInterface.h @@ -50,7 +50,8 @@ #include "LiveSupport/Core/ScheduleEntry.h" #include "LiveSupport/Core/XmlRpcException.h" #include "LiveSupport/Core/Playlist.h" -#include "LiveSupport/Core/AudioClip.h" +#include "LiveSupport/Core/SearchCriteria.h" +#include "LiveSupport/Core/AsyncState.h" namespace LiveSupport { namespace SchedulerClient { @@ -167,6 +168,70 @@ class SchedulerClientInterface throw (XmlRpcException) = 0; + /** + * Start the schedule backup creation process. + * This will produce a combined backup, including a storage portion. + * The scheduler daemon first calls the storage server, and gets + * a storage backup archive file from it; then it adds the schedule + * backup to this archive file. + * + * @param sessionId a valid, authenticated session id. + * @param criteria the search criteria for the storage portion + * of the backup. + * @param fromTime entries are included in the schedule backup + * starting from this time. + * @param toTime entries are included in the schedule backup + * up to but not including this time. + * @return a token which can be used to query the backup process. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + createBackupOpen(Ptr::Ref sessionId, + Ptr::Ref criteria, + Ptr::Ref fromTime, + Ptr::Ref toTime) const + throw (XmlRpcException) + = 0; + + /** + * Check on the progress of the schedule backup creation process. + * + * @param token the token obtained from createBackupOpen(). + * @param url return parameter; + * if a finishedState is returned, it contains the + * URL of the created backup file. + * @param path return parameter; + * if a finishedState is returned, it contains the + * local access path of the created backup file. + * @param errorMessage return parameter; + * if a failedState is returned, it contains the + * fault string. + * @return the state of the backup process: one of pendingState, + * finishedState, or failedState. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual AsyncState + createBackupCheck(const Glib::ustring & token, + Ptr::Ref & url, + Ptr::Ref & path, + Ptr::Ref & errorMessage) const + throw (XmlRpcException) + = 0; + + /** + * Close the schedule backup creation process. + * + * @param token the token obtained from createBackupOpen(). + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual void + createBackupClose(const Glib::ustring & token) const + throw (XmlRpcException) + = 0; + /** * A virtual destructor, as this class has virtual functions. */ diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx index 49b77877b..9e369c9d6 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.cxx @@ -366,3 +366,154 @@ SchedulerDaemonXmlRpcClient :: removeFromSchedule( xmlRpcClient.close(); } + +/*------------------------------------------------------------------------------ + * Start the schedule backup creation process. + *----------------------------------------------------------------------------*/ +Ptr::Ref +SchedulerDaemonXmlRpcClient :: createBackupOpen( + Ptr::Ref sessionId, + Ptr::Ref criteria, + Ptr::Ref fromTime, + Ptr::Ref toTime) const + throw (Core::XmlRpcException) +{ + XmlRpcValue xmlRpcParams; + XmlRpcValue xmlRpcResult; + + XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), + xmlRpcPort, + xmlRpcUri->c_str(), + false); + + XmlRpcTools::sessionIdToXmlRpcValue(sessionId, xmlRpcParams); + XmlRpcTools::searchCriteriaToXmlRpcValue(criteria, xmlRpcParams); + XmlRpcTools::fromTimeToXmlRpcValue(fromTime, xmlRpcParams); + XmlRpcTools::toTimeToXmlRpcValue(toTime, xmlRpcParams); + + if (!xmlRpcClient.execute("createBackupOpen", + xmlRpcParams, + xmlRpcResult)) { + throw Core::XmlRpcCommunicationException( + "cannot execute XML-RPC method 'createBackupOpen'"); + } + + if (xmlRpcClient.isFault()) { + std::stringstream eMsg; + eMsg << "XML-RPC method 'createBackupOpen' returned error message:\n" + << xmlRpcResult; + throw Core::XmlRpcMethodFaultException(eMsg.str()); + } + + xmlRpcClient.close(); + + Ptr::Ref token; + try { + token = XmlRpcTools::extractToken(xmlRpcResult); + } catch (std::invalid_argument &e) { + throw Core::XmlRpcMethodResponseException(e); + } + + return token; +} + + +/*------------------------------------------------------------------------------ + * Check on the progress of the schedule backup creation process. + *----------------------------------------------------------------------------*/ +AsyncState +SchedulerDaemonXmlRpcClient :: createBackupCheck( + const Glib::ustring & token, + Ptr::Ref & url, + Ptr::Ref & path, + Ptr::Ref & errorMessage) const + throw (Core::XmlRpcException) +{ + XmlRpcValue xmlRpcParams; + XmlRpcValue xmlRpcResult; + + XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), + xmlRpcPort, + xmlRpcUri->c_str(), + false); + + Ptr::Ref tokenPtr(new const Glib::ustring(token)); + XmlRpcTools::tokenToXmlRpcValue(tokenPtr, xmlRpcParams); + + if (!xmlRpcClient.execute("createBackupCheck", + xmlRpcParams, + xmlRpcResult)) { + throw Core::XmlRpcCommunicationException( + "cannot execute XML-RPC method 'createBackupCheck'"); + } + + if (xmlRpcClient.isFault()) { + std::stringstream eMsg; + eMsg << "XML-RPC method 'createBackupCheck' returned error message:\n" + << xmlRpcResult; + throw Core::XmlRpcMethodFaultException(eMsg.str()); + } + + xmlRpcClient.close(); + + AsyncState state; + try { + state = XmlRpcTools::extractBackupStatus(xmlRpcResult); + } catch (std::invalid_argument &e) { + throw Core::XmlRpcMethodResponseException(e); + } + + if (state == AsyncState::finishedState) { + try { + url = XmlRpcTools::extractUrl(xmlRpcResult); + path = XmlRpcTools::extractPath(xmlRpcResult); + } catch (std::invalid_argument &e) { + throw Core::XmlRpcMethodResponseException(e); + } + } else if (state == AsyncState::failedState) { + try { + errorMessage = XmlRpcTools::extractFaultString(xmlRpcResult); + } catch (std::invalid_argument &e) { + throw Core::XmlRpcMethodResponseException(e); + } + } + + return state; +} + + +/*------------------------------------------------------------------------------ + * + *----------------------------------------------------------------------------*/ +void +SchedulerDaemonXmlRpcClient :: createBackupClose( + const Glib::ustring & token) const + throw (Core::XmlRpcException) +{ + XmlRpcValue xmlRpcParams; + XmlRpcValue xmlRpcResult; + + XmlRpcClient xmlRpcClient(xmlRpcHost->c_str(), + xmlRpcPort, + xmlRpcUri->c_str(), + false); + + Ptr::Ref tokenPtr(new const Glib::ustring(token)); + XmlRpcTools::tokenToXmlRpcValue(tokenPtr, xmlRpcParams); + + if (!xmlRpcClient.execute("createBackupClose", + xmlRpcParams, + xmlRpcResult)) { + throw Core::XmlRpcCommunicationException( + "cannot execute XML-RPC method 'createBackupClose'"); + } + + if (xmlRpcClient.isFault()) { + std::stringstream eMsg; + eMsg << "XML-RPC method 'createBackupClose' returned error message:\n" + << xmlRpcResult; + throw Core::XmlRpcMethodFaultException(eMsg.str()); + } + + xmlRpcClient.close(); +} diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h index 1dfd9ed27..3d3b09c6c 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClient.h @@ -252,6 +252,67 @@ class SchedulerDaemonXmlRpcClient : removeFromSchedule(Ptr::Ref sessionId, Ptr::Ref scheduleEntryId) throw (XmlRpcException); + + /** + * Start the schedule backup creation process. + * This will produce a combined backup, including a storage portion. + * The scheduler daemon first calls the storage server, and gets + * a storage backup archive file from it; then it adds the schedule + * backup to this archive file. + * + * @param sessionId a valid, authenticated session id. + * @param criteria the search criteria for the storage portion + * of the backup. + * @param fromTime entries are included in the schedule backup + * starting from this time. + * @param toTime entries are included in the schedule backup + * up to but not including this time. + * @return a token which can be used to query the backup process. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + createBackupOpen(Ptr::Ref sessionId, + Ptr::Ref criteria, + Ptr::Ref fromTime, + Ptr::Ref toTime) const + throw (XmlRpcException); + + /** + * Check on the progress of the schedule backup creation process. + * + * @param token the token obtained from createBackupOpen(). + * @param url return parameter; + * if a finishedState is returned, it contains the + * URL of the created backup file. + * @param path return parameter; + * if a finishedState is returned, it contains the + * local access path of the created backup file. + * @param errorMessage return parameter; + * if a failedState is returned, it contains the + * fault string. + * @return the state of the backup process: one of pendingState, + * finishedState, or failedState. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual AsyncState + createBackupCheck(const Glib::ustring & token, + Ptr::Ref & url, + Ptr::Ref & path, + Ptr::Ref & errorMessage) const + throw (XmlRpcException); + + /** + * Close the schedule backup creation process. + * + * @param token the token obtained from createBackupOpen(). + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual void + createBackupClose(const Glib::ustring & token) const + throw (XmlRpcException); }; diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx index 32cbcec28..551ecf4a5 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.cxx @@ -332,3 +332,53 @@ SchedulerDaemonXmlRpcClientTest :: xmlRpcErrorTest(void) CPPUNIT_ASSERT(gotException); } + +/*------------------------------------------------------------------------------ + * Test the create backup functions. + *----------------------------------------------------------------------------*/ +void +SchedulerDaemonXmlRpcClientTest :: createBackupTest(void) + throw (CPPUNIT_NS::Exception) +{ + Ptr::Ref criteria(new SearchCriteria); + criteria->setLimit(10); + Ptr::Ref from(new ptime(time_from_string("2004-07-23 10:00:00"))); + Ptr::Ref to(new ptime(time_from_string("2004-07-23 11:00:00"))); + + Ptr::Ref token; + CPPUNIT_ASSERT_NO_THROW( + token = schedulerClient->createBackupOpen(sessionId, + criteria, + from, + to); + ); + CPPUNIT_ASSERT(token); + + Ptr::Ref url; + Ptr::Ref path; + Ptr::Ref errorMessage; + AsyncState status; + int iterations = 20; + do { + std::cerr << "-/|\\"[iterations%4] << '\b'; + sleep(1); + CPPUNIT_ASSERT_NO_THROW( + status = schedulerClient->createBackupCheck(*token, + url, + path, + errorMessage); + ); + CPPUNIT_ASSERT(status == AsyncState::pendingState + || status == AsyncState::finishedState + || status == AsyncState::failedState); + } while (--iterations && status == AsyncState::pendingState); + + CPPUNIT_ASSERT_EQUAL(AsyncState::finishedState, status); + // TODO: test accessibility of the URL? + + CPPUNIT_ASSERT_NO_THROW( + schedulerClient->createBackupClose(*token); + ); + // TODO: test existence of schedule backup in tarball +} + diff --git a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h index f9ffcf0c3..9613d5fbb 100644 --- a/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h +++ b/livesupport/src/modules/schedulerClient/src/SchedulerDaemonXmlRpcClientTest.h @@ -75,6 +75,7 @@ class SchedulerDaemonXmlRpcClientTest : public BaseTestMethod CPPUNIT_TEST(displayScheduleEmptyTest); CPPUNIT_TEST(playlistMgmtTest); CPPUNIT_TEST(xmlRpcErrorTest); + CPPUNIT_TEST(createBackupTest); CPPUNIT_TEST_SUITE_END(); private: @@ -132,6 +133,14 @@ class SchedulerDaemonXmlRpcClientTest : public BaseTestMethod void xmlRpcErrorTest(void) throw (CPPUNIT_NS::Exception); + /** + * Test the create backup functions. + * + * @exception CPPUNIT_NS::Exception on test failures. + */ + void + createBackupTest(void) throw (CPPUNIT_NS::Exception); + public: