|
|
/*
**++ ** ** Copyright (c) 2002 Microsoft Corporation ** ** ** Module Name: ** ** writerconfig.cpp ** ** ** Abstract: ** ** defines classes that encapsulate the Test writer's configuration ** ** Author: ** ** Reuven Lax [reuvenl] 04-June-2002 ** ** ** ** Revision History: ** **-- */
////////////////////////////////////////////////////////////////////////
// Includes
#include "stdafx.h"
#include "writerconfig.h"
#include "vs_xml.hxx"
#include "msxml2.h"
#include <string>
#include <sstream>
#include <algorithm>
////////////////////////////////////////////////////////////////////////
// Declarations
using Utility::checkReturn; using Utility::AutoCS; using std::wstring; using std::wstringstream;
namespace XMLData { // names of attributes and elements
wchar_t Name[] =L"name"; wchar_t Xmlns[] = L"xmlns"; wchar_t SchemaPointer[] = L"x-schema:#VssTestWriterConfig"; wchar_t RootStart[] = L"<root>"; wchar_t RootEnd[] = L"</root>\n"; wchar_t Root[] = L"root"; wchar_t TestWriter[] = L"TestWriter"; wchar_t Verbosity[] = L"verbosity"; wchar_t CheckExcludes[] = L"checkExcludes"; wchar_t CheckIncludes[] = L"checkIncludes"; wchar_t Path[] = L"path"; wchar_t Filespec[] = L"filespec"; wchar_t Recursive[] = L"recursive"; wchar_t AlternatePath[] = L"alternatePath"; wchar_t Usage[] = L"usage"; wchar_t RestoreMethod[] = L"RestoreMethod"; wchar_t Method[] = L"method"; wchar_t WriterRestore[] = L"writerRestore"; wchar_t Service[] = L"service"; wchar_t RebootRequired[] = L"rebootRequired"; wchar_t AlternateLocationMapping[] = L"AlternateLocationMapping"; wchar_t Component[] = L"Component"; wchar_t ComponentType[] = L"componentType"; wchar_t LogicalPath[] = L"logicalPath"; wchar_t Selectable[] = L"selectable"; wchar_t SelectableForRestore[] = L"selectableForRestore"; wchar_t ComponentName[] = L"componentName"; wchar_t ComponentFile[] = L"ComponentFile"; wchar_t Dependency[] = L"Dependency"; wchar_t WriterId[] = L"writerId"; wchar_t ExcludeFile[] = L"ExcludeFile"; wchar_t RestoreTarget[] = L"restoreTarget"; wchar_t NewTarget[] = L"NewTarget"; wchar_t FailEvent[] = L"FailEvent"; wchar_t WriterEvent[] = L"writerEvent"; wchar_t Retryable[] = L"retryable"; wchar_t NumFailures[] = L"numFailures"; // string containing the Test writer schema
#include "schema.h"
}
////////////////////////////////////////////////////////////////////////
// Implementation for the File struct
File::File(CXMLDocument node) { // read the attributes from the document and store in the structure
CComBSTR path; if (!node.FindAttribute(XMLData::Path, &path)) missingAttribute(XMLData::Path);
CComBSTR filespec; if (!node.FindAttribute(XMLData::Filespec, &filespec)) missingAttribute(XMLData::Filespec);
CComBSTR recursive; if (!node.FindAttribute(XMLData::Recursive, &recursive)) missingAttribute(XMLData::Recursive); m_path = (BSTR)path; std::transform(m_path.begin(), m_path.end(), m_path.begin(), towupper); m_filespec = (BSTR)filespec; std::transform(m_filespec.begin(), m_filespec.end(), m_filespec.begin(), towupper);
// path and filespec should never be empty.
if (m_path.empty()) throw Utility::TestWriterException(L"File specification has empty path"); if (m_filespec.empty()) throw Utility::TestWriterException(L"File specification has empty filespec"); if (m_path[m_path.size() -1] != L'\\') m_path += L'\\'; m_recursive = Utility::toBoolean(recursive); }
wstring File::toString() const { wstringstream msg; msg << L"Path: " << m_path << std::endl << L"Filespec: " << m_filespec << std::endl << L"Recursive: " << Utility::toString(m_recursive);
return msg.str(); } ////////////////////////////////////////////////////////////////////////
// Implementation for the TargetedFile struct
TargetedFile::TargetedFile(CXMLDocument node) : File(node) { // read the alternatePath attribute and store it
CComBSTR alternatePath; if (!node.FindAttribute(XMLData::AlternatePath, &alternatePath)) return; assert(alternatePath); m_alternatePath = (BSTR)alternatePath; std::transform(m_alternatePath.begin(), m_alternatePath.end(), m_alternatePath.begin(), towupper); if (m_alternatePath.empty()) throw Utility::TestWriterException(L"File specification has empty alternate path"); if (m_alternatePath[m_alternatePath.size()-1] != L'\\') m_alternatePath += L'\\'; }
wstring TargetedFile::toString() const { wstringstream msg; msg << File::toString() << std::endl << L"AlternatePath: " << m_alternatePath;
return msg.str(); }
////////////////////////////////////////////////////////////////////////
// Implementation for the RestoreMethod struct
RestoreMethod::RestoreMethod(CXMLDocument node) { node.SetToplevel();
CComBSTR method, writerRestore, service, rebootRequired; // read attributes and elements from document
if (!node.FindAttribute(XMLData::Method, &method)) missingAttribute(XMLData::Method);
if (!node.FindAttribute(XMLData::WriterRestore, &writerRestore)) missingAttribute(XMLData::WriterRestore);
node.FindAttribute(XMLData::Service, &service);
if(!node.FindAttribute(XMLData::RebootRequired, &rebootRequired)) missingAttribute(XMLData::RebootRequired); if (node.FindElement(XMLData::AlternateLocationMapping, true)) m_alternateLocations = AlternateList(node);
m_method = Utility::toMethod(method); m_writerRestore = Utility::toWriterRestore(writerRestore); m_service = (service.Length() > 0) ? service : L""; m_rebootRequired = Utility::toBoolean(rebootRequired); }
wstring RestoreMethod::toString() const { wstringstream msg; msg << L"method: " << Utility::toString(m_method) << std::endl << L"service: " << m_service << std::endl << L"writerRestore: " << Utility::toString(m_writerRestore) << std::endl << L"reboot: " << Utility::toString(m_rebootRequired);
return msg.str(); }
////////////////////////////////////////////////////////////////////////
// Implementation for the Dependency struct
Dependency::Dependency(CXMLDocument node) { node.SetToplevel();
CComBSTR logicalPath, componentName, writerId; if(!node.FindAttribute(XMLData::WriterId, &writerId)) missingAttribute(XMLData::WriterId);
node.FindAttribute(XMLData::LogicalPath, &logicalPath);
if(!node.FindAttribute(XMLData::ComponentName, &componentName)) missingAttribute(XMLData::ComponentName);
HRESULT hr = ::UuidFromString(writerId, &m_writerId); checkReturn(hr, L"CLSIDFromString"); m_logicalPath = (logicalPath.Length() > 0) ? logicalPath : L""; m_componentName = componentName; }
wstring Dependency::toString() const { wstringstream msg; msg << L"WriterId: " << (wchar_t*)CComBSTR(m_writerId) << std::endl << L"Logical Path: " << m_logicalPath << std::endl << L"Component Name: " << m_componentName;
return msg.str(); }
////////////////////////////////////////////////////////////////////////
// Implementation for the Component struct
Component::Component(CXMLDocument node) { node.SetToplevel();
CComBSTR componentType, restoreTarget, logicalPath, name, selectable, selectableForRestore; // read attributes from document and store them
if (!node.FindAttribute(XMLData::ComponentType, &componentType)) missingAttribute(XMLData::ComponentType);
node.FindAttribute(XMLData::RestoreTarget, &restoreTarget); node.FindAttribute(XMLData::LogicalPath, &logicalPath);
if (!node.FindAttribute(XMLData::ComponentName, &name)) missingAttribute(XMLData::ComponentName);
if (!node.FindAttribute(XMLData::Selectable, &selectable)) missingAttribute(XMLData::Selectable);
if (!node.FindAttribute(XMLData::SelectableForRestore, &selectableForRestore)) missingAttribute(XMLData::SelectableForRestore); m_componentType = Utility::toComponentType(componentType); m_restoreTarget = (restoreTarget.Length() > 0) ? Utility::toRestoreTarget(restoreTarget) : VSS_RT_UNDEFINED; m_logicalPath = (logicalPath.Length() > 0) ? logicalPath : L""; m_selectable = Utility::toBoolean(selectable); m_selectableForRestore = Utility::toBoolean(selectableForRestore); m_name = name; if (m_name.empty()) throw Utility::TestWriterException(L"Component has empty name"); // read elements from document and store them
if (node.FindElement(XMLData::ComponentFile, true)) m_files = ComponentFileList(node);
node.ResetToDocument(); if (node.FindElement(XMLData::Dependency, true)) m_dependencies = DependencyList(node); }
wstring ComponentBase::toString() const { wstringstream msg; msg << L"Logical Path: " << m_logicalPath << std::endl << L"Name: " << m_name << std::endl;
return msg.str(); }
// comparison operations for writer components
bool operator==(const ComponentBase& left, const ComponentBase& right) { return (left.m_name == right.m_name) && (left.m_logicalPath == right.m_logicalPath); } bool operator!=(const ComponentBase& left, const ComponentBase& right) { return !(left == right); } bool operator==(const Component& left, const Component& right) { return ((ComponentBase&)left == (ComponentBase&)right) && (left.m_componentType == right.m_componentType) && (left.m_restoreTarget == right.m_restoreTarget) && (left.m_selectable == right.m_selectable) && (left.m_selectableForRestore == right.m_selectableForRestore) && (left.m_files == right.m_files) && (left.m_newTargets == right.m_newTargets); } bool operator!=(const Component& left, const Component& right) { return !(left == right); }
////////////////////////////////////////////////////////////////////////
// Implementation for the WriterEvent struct
WriterEvent::WriterEvent(CXMLDocument node) { CComBSTR event; if (!node.FindAttribute(XMLData::WriterEvent, &event)) missingAttribute(XMLData::WriterEvent);
CComBSTR retryable; if (!node.FindAttribute(XMLData::Retryable, &retryable)) missingAttribute(XMLData::Retryable);
CComBSTR numFailures; if (!node.FindAttribute(XMLData::NumFailures, &numFailures)) missingAttribute(XMLData::NumFailures); m_writerEvent = Utility::toWriterEvent(event); m_retryable = Utility::toBoolean(retryable); m_numFailures = Utility::toLong(numFailures); }
////////////////////////////////////////////////////////////////////////
// Implementation for the WriterConfiguration class
// load configuration from the XML file
void WriterConfiguration::loadFromXML(const wstring& xml) { AutoCS critical(m_section); // load the document from the XML string
wstring xmlString = XMLData::RootStart; xmlString += XMLData::Schema; xmlString += xml; xmlString += XMLData::RootEnd;
// load twice so we can do schema validation the second time
for (int x = 0; x < 2; x++) { if (!m_doc.LoadFromXML(const_cast<wchar_t*> (xmlString.c_str()))) Utility::parseError(m_doc);
// --- skip to the part of the document we care about
if (!m_doc.FindElement(XMLData::Root, true)) missingElement(XMLData::Root); if (!m_doc.FindElement(XMLData::TestWriter, true)) missingElement(XMLData::TestWriter);
// --- set the schema namespace
if (x == 0) { CXMLNode testNode(m_doc.GetCurrentNode(), m_doc.GetInterface()); testNode.SetAttribute(XMLData::Xmlns, XMLData::SchemaPointer); xmlString = m_doc.SaveAsXML(); } }
m_doc.SetToplevel(); }
VSS_USAGE_TYPE WriterConfiguration::usage() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc);
CComBSTR value; if (!m_doc.FindAttribute(XMLData::Usage, &value)) missingAttribute(XMLData::Usage);
return Utility::toUsage(value); }
Utility::Verbosity WriterConfiguration::verbosity() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc);
CComBSTR value; if (!m_doc.FindAttribute(XMLData::Verbosity, &value)) missingAttribute(XMLData::Verbosity);
return Utility::toVerbosity(value); }
bool WriterConfiguration::checkExcludes() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc);
CComBSTR value; if (!m_doc.FindAttribute(XMLData::CheckExcludes, &value)) missingAttribute(XMLData::CheckExcludes);
return Utility::toBoolean(value); }
bool WriterConfiguration::checkIncludes() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc);
CComBSTR value; if (!m_doc.FindAttribute(XMLData::CheckIncludes, &value)) missingAttribute(XMLData::CheckIncludes);
return Utility::toBoolean(value); }
// get the writer's restore method
RestoreMethod WriterConfiguration::restoreMethod() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc); if (!m_doc.FindElement(XMLData::RestoreMethod, true)) missingElement(XMLData::RestoreMethod);
return RestoreMethod(m_doc); }
|