From 8c28c26a2cb6adf1e2f56af534b5157a9ec605e0 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 21 Sep 2006 19:29:33 +0000 Subject: [PATCH] Added a simple storage abstraction, and an in-memory sample. --- .project | 18 +- xmltooling/Makefile.am | 3 + xmltooling/XMLToolingConfig.cpp | 6 + xmltooling/XMLToolingConfig.h | 19 ++- xmltooling/exceptions.h | 1 + xmltooling/impl/MemoryStorageService.cpp | 263 ++++++++++++++++++++++++++++++ xmltooling/util/PThreads.cpp | 7 +- xmltooling/util/StorageService.cpp | 37 +++++ xmltooling/util/StorageService.h | 153 +++++++++++++++++ xmltooling/util/Threads.h | 8 +- xmltooling/util/Win32Threads.cpp | 5 + xmltooling/xmltooling.vcproj | 12 ++ xmltoolingtest/MemoryStorageServiceTest.h | 47 ++++++ xmltoolingtest/xmltoolingtest.vcproj | 30 +++- 14 files changed, 592 insertions(+), 17 deletions(-) create mode 100644 xmltooling/impl/MemoryStorageService.cpp create mode 100644 xmltooling/util/StorageService.cpp create mode 100644 xmltooling/util/StorageService.h create mode 100644 xmltoolingtest/MemoryStorageServiceTest.h diff --git a/.project b/.project index 573a04f..40ff0eb 100644 --- a/.project +++ b/.project @@ -18,34 +18,34 @@ org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser; - org.eclipse.cdt.make.core.enableAutoBuild - false - - org.eclipse.cdt.make.core.environment - org.eclipse.cdt.make.core.enableFullBuild - true + org.eclipse.cdt.make.core.enableAutoBuild + false org.eclipse.cdt.make.core.build.target.inc all - org.eclipse.cdt.make.core.enabledIncrementalBuild + org.eclipse.cdt.make.core.enableFullBuild true - org.eclipse.cdt.make.core.build.target.clean - clean + org.eclipse.cdt.make.core.enabledIncrementalBuild + true org.eclipse.cdt.make.core.build.command make + org.eclipse.cdt.make.core.build.target.clean + clean + + org.eclipse.cdt.make.core.enableCleanBuild true diff --git a/xmltooling/Makefile.am b/xmltooling/Makefile.am index 9a2bcdd..38cd95e 100644 --- a/xmltooling/Makefile.am +++ b/xmltooling/Makefile.am @@ -81,6 +81,7 @@ utilinclude_HEADERS = \ util/DateTime.h \ util/NDC.h \ util/ParserPool.h \ + util/StorageService.h \ util/Threads.h \ util/XMLConstants.h \ util/XMLHelper.h \ @@ -132,6 +133,7 @@ libxmltooling_la_SOURCES = \ encryption/impl/EncryptionImpl.cpp \ encryption/impl/EncryptionSchemaValidators.cpp \ impl/AnyElement.cpp \ + impl/MemoryStorageService.cpp \ impl/UnknownElement.cpp \ io/AbstractXMLObjectMarshaller.cpp \ io/AbstractXMLObjectUnmarshaller.cpp \ @@ -142,6 +144,7 @@ libxmltooling_la_SOURCES = \ util/DateTime.cpp \ util/NDC.cpp \ util/ParserPool.cpp \ + util/StorageService.cpp \ util/XMLConstants.cpp \ util/XMLHelper.cpp \ validation/ValidatorSuite.cpp \ diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index a7cbc42..f8e7f3b 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -30,6 +30,7 @@ #include "signature/CredentialResolver.h" #include "soap/SOAP.h" #include "util/NDC.h" +#include "util/StorageService.h" #include "util/XMLConstants.h" #include "validation/Validator.h" @@ -62,6 +63,8 @@ DECL_EXCEPTION_FACTORY(UnknownElementException,xmltooling); DECL_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling); DECL_EXCEPTION_FACTORY(UnknownExtensionException,xmltooling); DECL_EXCEPTION_FACTORY(ValidationException,xmltooling); +DECL_EXCEPTION_FACTORY(XMLSecurityException,xmltooling); +DECL_EXCEPTION_FACTORY(IOException,xmltooling); #ifndef XMLTOOLING_NO_XMLSEC DECL_EXCEPTION_FACTORY(SignatureException,xmlsignature); @@ -192,6 +195,8 @@ bool XMLToolingInternalConfig::init() REGISTER_EXCEPTION_FACTORY(UnknownElementException,xmltooling); REGISTER_EXCEPTION_FACTORY(UnknownAttributeException,xmltooling); REGISTER_EXCEPTION_FACTORY(ValidationException,xmltooling); + REGISTER_EXCEPTION_FACTORY(XMLSecurityException,xmltooling); + REGISTER_EXCEPTION_FACTORY(IOException,xmltooling); #ifndef XMLTOOLING_NO_XMLSEC XMLObjectBuilder::registerBuilder(QName(XMLConstants::XMLSIG_NS,Signature::LOCAL_NAME),new SignatureBuilder()); @@ -200,6 +205,7 @@ bool XMLToolingInternalConfig::init() registerCredentialResolvers(); registerTrustEngines(); #endif + registerStorageServices(); // Register xml:id as an ID attribute. static const XMLCh xmlid[] = UNICODE_LITERAL_2(i,d); diff --git a/xmltooling/XMLToolingConfig.h b/xmltooling/XMLToolingConfig.h index f60a06a..e1ce7f0 100644 --- a/xmltooling/XMLToolingConfig.h +++ b/xmltooling/XMLToolingConfig.h @@ -41,6 +41,7 @@ namespace xmlsignature { namespace xmltooling { + class XMLTOOL_API StorageService; class XMLTOOL_API TrustEngine; class XMLTOOL_API XSECCryptoX509CRL; @@ -53,7 +54,9 @@ namespace xmltooling { */ class XMLTOOL_API XMLToolingConfig : public Lockable { - MAKE_NONCOPYABLE(XMLToolingConfig); + MAKE_NONCOPYABLE(XMLToolingConfig); + protected: + XMLToolingConfig() : clock_skew_secs(180) {} public: virtual ~XMLToolingConfig() {} @@ -127,11 +130,17 @@ namespace xmltooling { virtual ParserPool& getValidatingParser() const=0; /** - * Set to catalog files to load into validating parser pool at initialization time. + * List of catalog files to load into validating parser pool at initialization time. * Like other path settings, the separator depends on the platform * (semicolon on Windows, colon otherwise). */ std::string catalog_path; + + /** + * Adjusts any clock comparisons to be more liberal/permissive by the + * indicated number of seconds. + */ + unsigned int clock_skew_secs; #ifndef XMLTOOLING_NO_XMLSEC /** @@ -155,8 +164,10 @@ namespace xmltooling { PluginManager TrustEngineManager; #endif - protected: - XMLToolingConfig() {} + /** + * Manages factories for StorageService plugins. + */ + PluginManager StorageServiceManager; }; }; diff --git a/xmltooling/exceptions.h b/xmltooling/exceptions.h index 1c07a34..55f8208 100644 --- a/xmltooling/exceptions.h +++ b/xmltooling/exceptions.h @@ -351,6 +351,7 @@ namespace xmltooling { DECL_XMLTOOLING_EXCEPTION(UnknownExtensionException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions from use of an unrecognized extension/plugin); DECL_XMLTOOLING_EXCEPTION(ValidationException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during object validation); DECL_XMLTOOLING_EXCEPTION(XMLSecurityException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions related to the XML security layer); + DECL_XMLTOOLING_EXCEPTION(IOException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions related to physical input/output errors); }; diff --git a/xmltooling/impl/MemoryStorageService.cpp b/xmltooling/impl/MemoryStorageService.cpp new file mode 100644 index 0000000..3a041ea --- /dev/null +++ b/xmltooling/impl/MemoryStorageService.cpp @@ -0,0 +1,263 @@ +/* + * Copyright 2001-2005 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * MemoryStorageService.cpp + * + * In-memory "persistent" storage, suitable for simple applications. + */ + +#include "internal.h" +#include "util/NDC.h" +#include "util/StorageService.h" +#include "util/Threads.h" +#include "util/XMLHelper.h" + +#include +#include + +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace xmltooling { + class XMLTOOL_DLLLOCAL MemoryStorageService : public StorageService + { + public: + MemoryStorageService(const DOMElement* e); + virtual ~MemoryStorageService(); + + void createString(const char* key, const char* value, time_t expiration); + bool readString(const char* key, string& value, time_t modifiedSince=0); + bool updateString(const char* key, const char* value=NULL, time_t expiration=0); + bool deleteString(const char* key); + + void createText(const char* key, const char* value, time_t expiration) { + return createString(key, value, expiration); + } + bool readText(const char* key, string& value, time_t modifiedSince=0) { + return readString(key, value, modifiedSince); + } + bool updateText(const char* key, const char* value=NULL, time_t expiration=0) { + return updateString(key, value, expiration); + } + bool deleteText(const char* key) { + return deleteString(key); + } + + void reap() { + shutdown_wait->signal(); + } + + private: + void cleanup(); + + struct XMLTOOL_DLLLOCAL Record { + Record() : modified(0), expiration(0) {} + Record(string s, time_t t1, time_t t2) : data(s), modified(t1), expiration(t2) {} + string data; + time_t modified, expiration; + }; + + map m_dataMap; + multimap m_expMap; + RWLock* m_lock; + CondWait* shutdown_wait; + Thread* cleanup_thread; + static void* cleanup_fn(void*); + bool shutdown; + int m_cleanupInterval; + Category& m_log; + }; + + StorageService* XMLTOOL_DLLLOCAL MemoryStorageServiceFactory(const DOMElement* const & e) + { + return new MemoryStorageService(e); + } + +}; + +static const XMLCh cleanupInterval[] = UNICODE_LITERAL_15(c,l,e,a,n,u,p,I,n,t,e,r,v,a,l); + +MemoryStorageService::MemoryStorageService(const DOMElement* e) + : m_lock(NULL), shutdown_wait(NULL), cleanup_thread(NULL), shutdown(false), m_cleanupInterval(0), + m_log(Category::getInstance(XMLTOOLING_LOGCAT".StorageService")) +{ + m_lock = RWLock::create(); + shutdown_wait = CondWait::create(); + cleanup_thread = Thread::create(&cleanup_fn, (void*)this); + + const XMLCh* tag=e ? e->getAttributeNS(NULL,cleanupInterval) : NULL; + if (tag && *tag) { + m_cleanupInterval = XMLString::parseInt(tag); + } + if (!m_cleanupInterval) + m_cleanupInterval=300; +} + +MemoryStorageService::~MemoryStorageService() +{ + // Shut down the cleanup thread and let it know... + shutdown = true; + shutdown_wait->signal(); + cleanup_thread->join(NULL); + + delete m_lock; + delete shutdown_wait; +} + +void* MemoryStorageService::cleanup_fn(void* cache_p) +{ + MemoryStorageService* cache = reinterpret_cast(cache_p); + +#ifndef WIN32 + // First, let's block all signals + Thread::mask_all_signals(); +#endif + + // Now run the cleanup process. + cache->cleanup(); + return NULL; +} + +void MemoryStorageService::cleanup() +{ +#ifdef _DEBUG + NDC ndc("cleanup"); +#endif + + + Mutex* mutex = Mutex::create(); + mutex->lock(); + + m_log.info("cleanup thread started...running every %d seconds", m_cleanupInterval); + + while (!shutdown) { + shutdown_wait->timedwait(mutex, m_cleanupInterval); + if (shutdown) + break; + + // Lock the "database". + m_lock->wrlock(); + + // Garbage collect any expired entries. + unsigned int count=0; + time_t now=time(NULL)-XMLToolingConfig::getConfig().clock_skew_secs; + multimap::iterator stop=m_expMap.upper_bound(now); + for (multimap::iterator i=m_expMap.begin(); i!=stop; m_expMap.erase(i++)) { + m_dataMap.erase(i->second); + ++count; + } + + m_lock->unlock(); + + if (count) + m_log.info("purged %d record(s) from storage", count); + } + + m_log.info("cleanup thread finished"); + + mutex->unlock(); + delete mutex; + Thread::exit(NULL); +} + +void MemoryStorageService::createString(const char* key, const char* value, time_t expiration) +{ + // Lock the maps. + m_lock->wrlock(); + SharedLock wrapper(m_lock, false); + + // Check for a duplicate. + map::iterator i=m_dataMap.find(key); + if (i!=m_dataMap.end()) + throw IOException("attempted to insert a record with duplicate key ($1)", params(1,key)); + + m_dataMap[key]=Record(value,time(NULL),expiration); + m_expMap.insert(multimap::value_type(expiration,key)); + + m_log.debug("inserted record (%s)", key); +} + +bool MemoryStorageService::readString(const char* key, string& value, time_t modifiedSince) +{ + SharedLock wrapper(m_lock); + map::iterator i=m_dataMap.find(key); + if (i==m_dataMap.end()) + return false; + else if (modifiedSince >= i->second.modified) + return false; + value = i->second.data; + return true; +} + +bool MemoryStorageService::updateString(const char* key, const char* value, time_t expiration) +{ + // Lock the maps. + m_lock->wrlock(); + SharedLock wrapper(m_lock, false); + + map::iterator i=m_dataMap.find(key); + if (i==m_dataMap.end()) + return false; + + if (value) + i->second.data = value; + + if (expiration && expiration != i->second.expiration) { + // Update secondary map. + pair::iterator,multimap::iterator> range=m_expMap.equal_range(i->second.expiration); + for (; range.first != range.second; ++range.first) { + if (range.first->second == i->first) { + m_expMap.erase(range.first); + break; + } + } + i->second.expiration = expiration; + m_expMap.insert(multimap::value_type(expiration,key)); + } + + i->second.modified = time(NULL); + m_log.debug("updated record (%s)", key); + return true; +} + +bool MemoryStorageService::deleteString(const char* key) +{ + // Lock the maps. + m_lock->wrlock(); + SharedLock wrapper(m_lock, false); + + // Find the record. + map::iterator i=m_dataMap.find(key); + if (i!=m_dataMap.end()) { + // Now find the reversed index of expiration to key, so we can clear it. + pair::iterator,multimap::iterator> range=m_expMap.equal_range(i->second.expiration); + for (; range.first != range.second; ++range.first) { + if (range.first->second == i->first) { + m_expMap.erase(range.first); + break; + } + } + // And finally delete the record itself. + m_dataMap.erase(i); + m_log.debug("deleted record (%s)", key); + return true; + } + + m_log.debug("deleting record (%s)....not found", key); + return false; +} diff --git a/xmltooling/util/PThreads.cpp b/xmltooling/util/PThreads.cpp index 2f9a1d0..6474ba3 100644 --- a/xmltooling/util/PThreads.cpp +++ b/xmltooling/util/PThreads.cpp @@ -269,7 +269,12 @@ void Thread::exit(void* return_val) { pthread_exit(return_val); } - + +void Thread::sleep(int seconds) +{ + sleep(seconds); +} + void Thread::mask_all_signals(void) { sigset_t sigmask; diff --git a/xmltooling/util/StorageService.cpp b/xmltooling/util/StorageService.cpp new file mode 100644 index 0000000..cefb07a --- /dev/null +++ b/xmltooling/util/StorageService.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * StorageService.cpp + * + * Registration of factories for built-in storage services + */ + +#include "internal.h" +#include "util/StorageService.h" + +using namespace xmltooling; +using namespace std; + +namespace xmltooling { + XMLTOOL_DLLLOCAL PluginManager::Factory MemoryStorageServiceFactory; +}; + +void XMLTOOL_API xmltooling::registerStorageServices() +{ + XMLToolingConfig& conf=XMLToolingConfig::getConfig(); + conf.StorageServiceManager.registerFactory(MEMORY_STORAGE_SERVICE, MemoryStorageServiceFactory); +} diff --git a/xmltooling/util/StorageService.h b/xmltooling/util/StorageService.h new file mode 100644 index 0000000..905884b --- /dev/null +++ b/xmltooling/util/StorageService.h @@ -0,0 +1,153 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file xmltooling/util/StorageService.h + * + * Generic data storage facility for use by services that require persistence. + */ + +#ifndef __xmltooling_storage_h__ +#define __xmltooling_storage_h__ + +#include + +#include + +namespace xmltooling { + + /** + * Generic data storage facility for use by services that require persistence. + */ + class XMLTOOL_API StorageService + { + MAKE_NONCOPYABLE(StorageService); + protected: + StorageService() {} + + public: + virtual ~StorageService() {} + + /** + * Creates a new "short" record in the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value null-terminated value of up to 255 bytes to store + * @param expiration an expiration timestamp, after which the record can be purged + * + * @throws IOException raised if errors occur in the insertion process + */ + virtual void createString(const char* key, const char* value, time_t expiration)=0; + + /** + * Returns an existing "short" record from the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value location in which to return the record value + * @param modifiedSince the record should not be returned if unmodified since this time, + * or 0 to always return + * @return true iff the record exists and was returned (based on the modifiedSince value) + * + * @throws IOException raised if errors occur in the read process + */ + virtual bool readString(const char* key, std::string& value, time_t modifiedSince=0)=0; + + /** + * Updates an existing "short" record in the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value null-terminated value of up to 255 bytes to store, or NULL to leave alone + * @param expiration a new expiration timestamp, or 0 to leave alone + * @return true iff the record exists and was updated + * + * @throws IOException raised if errors occur in the update process + */ + virtual bool updateString(const char* key, const char* value=NULL, time_t expiration=0)=0; + + /** + * Deletes an existing "short" record from the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @return true iff the record existed and was deleted + * + * @throws IOException raised if errors occur in the deletion process + */ + virtual bool deleteString(const char* key)=0; + + /** + * Creates a new "long" record in the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value null-terminated value of arbitrary length + * @param expiration an expiration timestamp, after which the record can be purged + * + * @throws IOException raised if errors occur in the insertion process + */ + virtual void createText(const char* key, const char* value, time_t expiration)=0; + + /** + * Returns an existing "long" record from the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value location in which to return the record value + * @param modifiedSince the record should not be returned if unmodified since this time, + * or 0 to always return + * @return true iff the record exists and was returned (based on the modifiedSince value) + * + * @throws IOException raised if errors occur in the read process + */ + virtual bool readText(const char* key, std::string& value, time_t modifiedSince=0)=0; + + /** + * Updates an existing "long" record in the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @param value null-terminated value of arbitrary length to store, or NULL to leave alone + * @param expiration a new expiration timestamp, or 0 to leave alone + * @return true iff the record exists and was updated + * + * @throws IOException raised if errors occur in the update process + */ + virtual bool updateText(const char* key, const char* value=NULL, time_t expiration=0)=0; + + /** + * Deletes an existing "long" record from the storage service. + * + * @param key null-terminated unique key of up to 255 bytes + * @return true iff the record existed and was deleted + * + * @throws IOException raised if errors occur in the deletion process + */ + virtual bool deleteText(const char* key)=0; + + /** + * Manually trigger a cleanup of expired records. + * The method MAY return without guaranteeing that + * cleanup has already occurred. + */ + virtual void reap()=0; + }; + + /** + * Registers StorageService classes into the runtime. + */ + void XMLTOOL_API registerStorageServices(); + + /** StorageService based on in-memory caching. */ + #define MEMORY_STORAGE_SERVICE "org.opensaml.xmlooling.MemoryStorageService" +}; + +#endif /* __xmltooling_storage_h__ */ diff --git a/xmltooling/util/Threads.h b/xmltooling/util/Threads.h index 25147c6..50d031f 100644 --- a/xmltooling/util/Threads.h +++ b/xmltooling/util/Threads.h @@ -78,7 +78,13 @@ namespace xmltooling * @param return_val the return value for the thread */ static void exit(void* return_val); - + + /** + * Sleeps the current thread for the specified amount of time. + * + * @param seconds time to sleep + */ + static void sleep(int secounds); #ifndef WIN32 /** * Masks all signals from a thread. diff --git a/xmltooling/util/Win32Threads.cpp b/xmltooling/util/Win32Threads.cpp index e239a17..8e5cdc0 100644 --- a/xmltooling/util/Win32Threads.cpp +++ b/xmltooling/util/Win32Threads.cpp @@ -383,6 +383,11 @@ void Thread::exit(void* return_val) ExitThread((DWORD)return_val); } +void Thread::sleep(int seconds) +{ + Sleep(seconds * 1000); +} + Mutex * Mutex::create() { return new MutexImpl(); diff --git a/xmltooling/xmltooling.vcproj b/xmltooling/xmltooling.vcproj index 8fdc20e..51cf2be 100644 --- a/xmltooling/xmltooling.vcproj +++ b/xmltooling/xmltooling.vcproj @@ -241,6 +241,10 @@ > + + @@ -273,6 +277,10 @@ > + + @@ -503,6 +511,10 @@ > + + diff --git a/xmltoolingtest/MemoryStorageServiceTest.h b/xmltoolingtest/MemoryStorageServiceTest.h new file mode 100644 index 0000000..1d91950 --- /dev/null +++ b/xmltoolingtest/MemoryStorageServiceTest.h @@ -0,0 +1,47 @@ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "XMLObjectBaseTestCase.h" + +#include + +class MemoryStorageServiceTest : public CxxTest::TestSuite { +public: + void setUp() { + } + + void tearDown() { + } + + void testMemoryService() { + auto_ptr storage( + XMLToolingConfig::getConfig().StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE,NULL) + ); + + string data; + TSM_ASSERT("Record found in storage.", !storage->readString("foo1", data)); + storage->createString("foo1", "bar1", time(NULL) - 300); + storage->createString("foo2", "bar2", time(NULL)); + TSM_ASSERT("Record not found in storage.", storage->readString("foo1", data)); + TSM_ASSERT_EQUALS("Record value doesn't match.", data, "bar1"); + TSM_ASSERT("Update failed.", storage->updateString("foo2", "bar1")); + TSM_ASSERT("Record not found in storage.", storage->readString("foo2", data)); + TSM_ASSERT_EQUALS("Record value doesn't match.", data, "bar1"); + TSM_ASSERT("Delete failed.", storage->deleteString("foo2")); + storage->reap(); + Thread::sleep(1); + } +}; diff --git a/xmltoolingtest/xmltoolingtest.vcproj b/xmltoolingtest/xmltoolingtest.vcproj index 8d365db..31feac6 100644 --- a/xmltoolingtest/xmltoolingtest.vcproj +++ b/xmltoolingtest/xmltoolingtest.vcproj @@ -208,6 +208,10 @@ > + + @@ -321,7 +325,7 @@ > @@ -330,7 +334,7 @@ > @@ -380,6 +384,28 @@ + + + + + + + +