// $Revision: 1.37 $ // StockServer.C // Copyright (C) 1994, 1995 Taligent, Inc. All rights reserved. #ifndef TaligentSamples_STOCKSERVER #include "StockServer.h" #endif #ifndef TaligentSamples_STOCKCALLER #include "StockCaller.h" #endif #ifndef TaligentSamples_LOCALSTOCKDATA #include #endif #ifndef TaligentSamples_STOCKTYPES #include #endif #ifndef Taligent_ASSERTIONS #include // Included for Assertion. #endif #ifndef Taligent_DATETIME #include // Included for TGregorianCalendar. #endif #ifndef Taligent_DISKDICTIONARY #include #endif #ifndef Taligent_DISPATCHERTHREAD #include #endif #ifndef Taligent_LOCALOBJECTNAME #include #endif #ifndef Taligent_LOCALSERVICE #include #endif #ifndef Taligent_MESSAGESTREAMS #include // Included for TRequestReceiverStream. #endif #ifndef Taligent_MULTIPLEROOTLOCATOR #include #endif //============================================================================== // TStockServer TaligentTypeExtensionMacro(TStockServer); void TStockServer::AddStockData( const TStandardText& stockName, const TDirectory& sourceFileDirectory, const TStandardText& sourceFileName) { TMappedFile inputFile(sourceFileDirectory.LookUp(sourceFileName), MOpenFile::kRead); TMemorySurrogate memory; inputFile.GetMemorySurrogate(memory); char* inputPointer = (char*)memory.GetStartAddress(); TDequeOf stock(new TOperatorComparator, new TMonomorphicStreamer); try { long month; long day; long year; long volume; double high; double low; double close; char lineBuffer[80]; TGregorianCalendar calendar; TDays date; short index; TPositionalNumberFormatter formatter; TFloatingPointNumberFormatter floatFormatter; qprintf("### Reading ... "); while (true) { char* bufferPointer = lineBuffer; if (*inputPointer == '\0') break; while (*inputPointer != '\n') { *bufferPointer++ = *inputPointer++; } *bufferPointer = 0; inputPointer++; TStandardText text(lineBuffer); TTextRange range(0, (TTextCount)strlen(lineBuffer)); TFormatableNumber num; TScanResult result; formatter.Scan(text, range, num, result); month = (long)num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); formatter.Scan(text, range, num, result); day = (long)num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); formatter.Scan(text, range, num, result); year = 1900 + (long)num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); formatter.Scan(text, range, num, result); volume = (long)num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); floatFormatter.Scan(text, range, num, result); high = num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); floatFormatter.Scan(text, range, num, result); low = num.GetNumber(); range.SetBegin(range.GetBegin() + result.GetLengthUsed() + 1); floatFormatter.Scan(text, range, num, result); close = num.GetNumber(); calendar.SetField(TCalendar::kYearInEra, year); calendar.SetField(TCalendar::kMonthInYear, month); calendar.SetField(TCalendar::kDayInMonth, day); calendar.GetTime(date); stock.Add(new TStockDay(date, high, low, close, volume)); } } catch (...) { stock.DeleteAll(); throw; } qprintf("Adding ... "); const bool kReplaceExistingValue = true; GetDictionary()->Add(stockName, stock, kReplaceExistingValue); stock.DeleteAll(); qprintf("Done.\n"); } TStockServer::TStockServer() : TStockDatabase(), fDataDirectoryName(), fDiskDictionaryName(), fDiskDictionary(NIL) { } TStockServer::TStockServer( const TStandardText& dataDirectoryName, const TStandardText& diskDictionaryName) : TStockDatabase(), fDataDirectoryName(dataDirectoryName), fDiskDictionaryName(diskDictionaryName), fDiskDictionary(NIL) { fDiskDictionary = CreateOrOpenDiskDictionary(); } TStockServer::~TStockServer() { delete fDiskDictionary; } TStream& TStockServer::operator>>=(TStream& toStream) const { ::WriteVersion(toStream, kOriginalVersion); TStockDatabase::operator>>=(toStream); fDataDirectoryName >>= toStream; fDiskDictionaryName >>= toStream; return toStream; } TStream& TStockServer::operator<<=(TStream& fromStream) { ::ReadVersion(fromStream, kOriginalVersion, kOriginalVersion); delete fDiskDictionary; fDiskDictionary = NIL; TStockDatabase::operator<<=(fromStream); fDataDirectoryName <<= fromStream; fDiskDictionaryName <<= fromStream; fDiskDictionary = CreateOrOpenDiskDictionary(); return fromStream; } void TStockServer::CopyAvailableNames(TCollectionOf& collectionToFill) { TServerDictionaryIterator iterator(GetDictionary()); for (TStandardText* name = iterator.FirstKey(); name != NIL; name = iterator.NextKey()) { collectionToFill.Add(::Copy(*name)); } } void TStockServer::CopyAllStocks(TCollectionOf& collectionToFill) { TServerDictionaryIterator iterator(GetDictionary()); for (TStandardText* name = iterator.FirstKey(); name != NIL; name = iterator.NextKey()) { collectionToFill.Add(CopyStock(*name)); } } TStockData* TStockServer::CopyStock(const TStandardText& stockName) { TStockData* returnValue = NIL; if (GetDictionary()->Member(stockName)) { returnValue = HandleCreateStock(stockName); } return returnValue; } bool TStockServer::CopyStockData( const TStandardText& stockName, TCollectionOf& collectionToFill, const TRangeOfDays& rangeOfDays) { bool success = false; TDeleterFor > diskCollection = GetDictionary()->Copy(stockName); if (diskCollection != NIL) { TDeleterFor > iterator = diskCollection->CreateIterator(); for (TStockDay* item = iterator->First(); item != NIL; item = iterator->Next()) { if (rangeOfDays.Contains(item->GetDate())) collectionToFill.Add(item); } success = collectionToFill.Count() > 0; } return success; } TPseudoTimeStamp TStockServer::GetTimeStamp() { // Start higher than zero because the default is zero. This server // doesn't change so its timestamp can be static. const CollectionIndex kInitialTimeStampValue = 1; return TPseudoTimeStamp(kInitialTimeStampValue); } TStockServer::TServerDictionary* TStockServer::GetDictionary() { TServerDictionary* result = NIL; if (fDiskDictionary != NIL) { result = fDiskDictionary; } else { static const TStandardText kDefaultDataDirectoryName("RuntimeEnv/Data/StockServerDATA"); static const TStandardText kDefaultDiskDictionaryName("StockServerDATA"); fDataDirectoryName = kDefaultDataDirectoryName; fDiskDictionaryName = kDefaultDiskDictionaryName; fDiskDictionary = CreateOrOpenDiskDictionary(); result = fDiskDictionary; } return result; } TStockServer::TServerDictionary* TStockServer::CreateOrOpenDiskDictionary() { TServerDictionary* result = NIL; try { TDirectory dataDirectory; try { TPathName dataDirectoryPath; TPathNameParser::GetDefaultParser().HostSpecificToPathName(fDataDirectoryName, dataDirectoryPath); TMultipleRootLocator directoryFinder(dataDirectoryPath); dataDirectory = directoryFinder.GetWritableDirectory(); result = new TServerDictionary(dataDirectory, fDiskDictionaryName); } catch (const TMultipleRootLocatorException& exception) { qprintf("\n### Couldn't find server data directory!\n"); throw; } catch (const TPersistentStoreDoesNotExistException& exception) { qprintf("Creating disk dictionary ... "); TComparator* keyComparator = new TOperatorComparator; TStreamer* keyStreamer = new TMonomorphicStreamer; TStreamer >* valueStreamer = new TPolymorphicStreamer >; result = new TServerDictionary(dataDirectory, fDiskDictionaryName, keyComparator, keyStreamer, valueStreamer); } } catch (...) { qprintf("\n### TStockServer::CreateOrOpenDiskDictionary caught exception!\n"); throw TStockException(TStockException::kDataInaccessible); } return result; } TStockData* TStockServer::HandleCreateStock(const TStandardText& name) { TCollectionOf* data = GetDictionary()->Copy(name); return new TLocalStockData(name, data); } TStockServer::TStockServer( const TStockServer& source) : TStockDatabase(), fDataDirectoryName(), fDiskDictionaryName(), fDiskDictionary(NIL) { ::Assertion(false, "Can't call TStockServer copy constructor."); } TStockServer& TStockServer::operator=( const TStockServer& source) { ::Assertion(false, "Can't call TStockServer assignment operator."); return *this; } //============================================================================== // TStockServerShutdownHandler TStockServerShutdownHandler::TStockServerShutdownHandler() : TShutdownHandler() { } TStockServerShutdownHandler::~TStockServerShutdownHandler() { } void TStockServerShutdownHandler::CompleteShutdown() { TStockCaller server(TStockCaller::CreateLocalServiceReference()); server.ExitDispatcher(); } //============================================================================== // TStockDispatcher const TStandardText TStockDispatcher_kServiceName("StockServer"); const TStandardText& TStockDispatcher::kServiceName = TStockDispatcher_kServiceName; TaligentTypeExtensionMacro(TStockDispatcher); void TStockDispatcher::LaunchStockServer( const TQualityOfService& serviceQuality) { try { TStockServerShutdownHandler shutdownHandler; TShutdownServerHandle shutdownServer; shutdownServer.ShutDownWith(shutdownHandler, TShutdownHandler::kHighLevelServices); shutdownServer.Register(shutdownHandler, TShutdownHandlerName(kServiceName)); } catch (...) { qprintf("### TStockDispatcher: exception registering shutdown handler.\n"); throw; } TStandardServiceDefinition* serviceDefinition = NIL; try { serviceDefinition = new TStandardServiceDefinition(TLocalObjectName(kServiceName), serviceQuality); serviceDefinition->AddReference(); TRequestReceiverStream requestReceiverStream(serviceDefinition); TDeleterFor serverInstance = new TStockServer; TStockDispatcher dispatcher(serverInstance.OrphanObject()); TDispatcherThread::Dispatch(requestReceiverStream, dispatcher); } catch (...) { qprintf("### TStockDispatcher: exception establishing service.\n"); if (serviceDefinition != NIL) { serviceDefinition->RemoveReference(); } throw; } serviceDefinition->RemoveReference(); } TStockDispatcher::TStockDispatcher() : MRemoteDispatcher(), fImplementation(NIL) { } TStockDispatcher::TStockDispatcher( TStockDatabase* adoptedImplementation) : MRemoteDispatcher(), fImplementation(adoptedImplementation) { static RequestEntry requests[] = { {kCopyAvailableNames, (RemoteFnPtr)&CopyAvailableNamesStub}, {kCopyAllStocks, (RemoteFnPtr)&CopyAllStocksStub}, {kCopyStock, (RemoteFnPtr)&CopyStockStub}, {kCopyStockData, (RemoteFnPtr)&CopyStockDataStub}, {kGetTimeStamp, (RemoteFnPtr)&GetTimeStampStub}, // MRemoteCaller needs the following constant included in the // request entry. {MRemoteCaller::kUnknownRequest} }; // It is also very important that the name of this class appears in // the RegisterRequests call. RegisterRequests(TStandardText("TStockDispatcher"), TStockDispatcher::kLastRequest, requests); } TStockDispatcher::~TStockDispatcher() { delete fImplementation; } TStream& TStockDispatcher::operator>>=(TStream& toStream) const { ::WriteVersion(toStream, kOriginalVersion); // MRemoteDispatcher::operator>>= is not meant to be called. ::Flatten(fImplementation, toStream); return toStream; } TStream& TStockDispatcher::operator<<=(TStream& fromStream) { ::ReadVersion(fromStream, kOriginalVersion, kOriginalVersion); delete fImplementation; // MRemoteDispatcher::operator<<= is not meant to be called. ::Resurrect(fImplementation, fromStream); return fromStream; } void TStockDispatcher::CopyAvailableNamesStub(TStream& argStream, TStream& resultStream) { TCollectionOf* tempAvailableNames = NIL; ::Resurrect(tempAvailableNames, argStream); TDeleterFor > availableNames(tempAvailableNames); fImplementation->CopyAvailableNames(*availableNames); ReturnSuccess(resultStream); *availableNames >>= resultStream; availableNames->DeleteAll(); } void TStockDispatcher::CopyAllStocksStub(TStream& argStream, TStream& resultStream) { TCollectionOf* tempAvailableStocks = NIL; ::Resurrect(tempAvailableStocks, argStream); TDeleterFor > availableStocks(tempAvailableStocks); fImplementation->CopyAllStocks(*availableStocks); ReturnSuccess(resultStream); *availableStocks >>= resultStream; availableStocks->DeleteAll(); } void TStockDispatcher::CopyStockStub(TStream& argStream, TStream& resultStream) { TStandardText stockName; stockName <<= argStream; TDeleterFor stock(fImplementation->CopyStock(stockName)); ReturnSuccess(resultStream); ::Flatten(stock.GetObject(), resultStream); } void TStockDispatcher::CopyStockDataStub(TStream& argStream, TStream& resultStream) { TStandardText stockName; stockName <<= argStream; TCollectionOf* tempStockData = NIL; ::Resurrect(tempStockData, argStream); TDeleterFor > stockData(tempStockData); TRangeOfDays rangeOfDays; rangeOfDays <<= argStream; bool gotData = fImplementation->CopyStockData(stockName, *stockData.GetObject(), rangeOfDays); ReturnSuccess(resultStream); gotData >>= resultStream; if (gotData) { *stockData >>= resultStream; } stockData->DeleteAll(); } void TStockDispatcher::GetTimeStampStub(TStream& argStream, TStream& resultStream) { ReturnSuccess(resultStream); fImplementation->GetTimeStamp() >>= resultStream; } TStockDispatcher::TStockDispatcher(const TStockDispatcher& source) : MRemoteDispatcher(source), fImplementation(NIL) { ::Assertion(false, "Can't copy TStockDispatcher."); } TStockDispatcher& TStockDispatcher::operator=(const TStockDispatcher& source) { ::Assertion(false, "Can't call TStockDispatcher assignment operator."); return *this; }