/* **++ ** ** Copyright (c) 2002 Microsoft Corporation ** ** ** Module Name: ** ** writerconfig.h ** ** ** Abstract: ** ** declare classes that encapsulate the Test writer's configuration ** ** Author: ** ** Reuven Lax [reuvenl] 04-June-2002 ** ** ** ** Revision History: ** **-- */ #ifndef _WRITERCONFIG_H_ #define _WRITERCONFIG_H_ /////////////////////////////////////////////////////////////////////////////// // Includes #include #include #include #include "vs_xml.hxx" #include "utility.h" using std::wstring; using Utility::missingAttribute; using Utility::missingElement; using Utility::AutoCS; /////////////////////////////////////////////////////////////////////////////// // Declarations // this namespace contains all XML data namespace XMLData { // names of attributes and elements extern wchar_t AlternateLocationMapping[]; extern wchar_t Component[]; extern wchar_t ComponentFile[]; extern wchar_t ExcludeFile[]; extern wchar_t NewTarget[]; extern wchar_t FailEvent[]; extern wchar_t Dependency[]; } /////////////////////////////////////////////////////////////////////////////// // Class Declarations // this is the generic collection class for sequences in the XML document template class XMLCollection { public: // required typedefs for a collection class typedef const T value_type ; typedef const T& reference ; typedef const T& const_reference ; typedef T* pointer ; typedef const T* const_pointer ; typedef long size_type ; class Iterator; typedef Iterator iterator; typedef Iterator const_iterator ; // The iterator for objects in the collection. The iterator is read only -- objects in the collection can't be modified class Iterator : public std::iterator { CXMLDocument m_doc; mutable long* m_identifier; mutable T* m_currentElement; bool m_pastEnd; unsigned long m_index; public: Iterator() : m_identifier(NULL), m_currentElement(NULL), m_pastEnd(true), m_index(0) {} Iterator(const Iterator& other) : m_identifier(NULL) { *this = other; } Iterator(const XMLCollection& collection) : m_doc(collection.m_doc), m_currentElement(NULL), m_pastEnd(false), m_index(0) { // the assumption is that m_doc is currently at a node with type ElementName // bad things will ensue if this is not true m_doc.SetToplevel(); // m_identifer is used to ensure the following statements // iterator i1 = ...; // iterator i2 = i1; // assert(i1 == i2); // assert(++i1 == ++i2); m_identifier = new long(1); if (m_identifier == NULL) throw std::bad_alloc(); } virtual ~Iterator() { if (m_identifier && --*m_identifier == 0) delete m_identifier; delete m_currentElement; } Iterator& operator=(const Iterator& other) { if (&other == this) return *this; m_currentElement = NULL; m_doc = other.m_doc; m_pastEnd = other.m_pastEnd; m_index = other.m_index; // make the reference count right if (other.m_identifier) ++*other.m_identifier; if(m_identifier && --*m_identifier == 0) delete m_identifier; m_identifier = other.m_identifier; return *this; } bool operator==(const Iterator& other) const { return (m_pastEnd && other.m_pastEnd) || ((m_identifier == other.m_identifier) && (m_index == other.m_index) && !m_pastEnd && !other.m_pastEnd); } bool operator!=(const Iterator& other) const { return !(*this == other); } const_reference operator*() const { assert(m_identifier); assert(!m_pastEnd); if (!m_currentElement) m_currentElement = new T(m_doc); if (m_currentElement == NULL) throw std::bad_alloc(); return *m_currentElement; } const_pointer operator->() const { return &**this; } Iterator& operator++() { if (m_pastEnd) { assert(false); return *this; } assert(m_identifier); delete m_currentElement; m_currentElement = NULL; if (!m_doc.FindElement(ElementName, false)) m_pastEnd = true; ++m_index; return *this; } Iterator operator++(int) { Iterator temp = *this; ++*this; return temp; } }; XMLCollection() : m_size(0) {} // initialize an empty collection XMLCollection(const XMLCollection& other) { *this = other; } XMLCollection(CXMLDocument& document) : m_doc(document), m_size(-1) { m_doc.SetToplevel(); } virtual ~XMLCollection() {} XMLCollection& operator= (const XMLCollection& other) { m_doc = other.m_doc; m_size = other.m_size; return *this; } bool operator==(const XMLCollection& other) const { return (size() == other.size()) && std::equal(begin(), end(), other.begin()); } bool operator!=(const XMLCollection& other) const { return !(*this == other); } size_type size() const { // if we've already calculated the size, return it if (m_size != -1) return m_size; // otherwise, calculate the size and return it assert(!m_doc.IsEmpty()); // if so, then m_size should==0, and we wouldn't be here size_type size = 0; iterator current(*this); // can't use begin()/end() as that would recurse while (current != m_pastEndIterator) { ++size; ++current; } assert(size > 0); return (m_size = size); } size_type max_size() const { return LONG_MAX; } bool empty() const { return size() == 0; } iterator begin() const { return empty() ? m_pastEndIterator : Iterator(*this); } iterator end() const { return m_pastEndIterator; } private: friend class Iterator; CXMLDocument m_doc; mutable long m_size; Iterator m_pastEndIterator; }; // little class to ensure that the document is always reset at the end of each function struct Resetter { CXMLDocument& m_config; Resetter(CXMLDocument& config) : m_config(config) {} ~Resetter() { m_config.ResetToDocument(); } }; // generic file specification. struct File { File(CXMLDocument node); File(const wstring& path, const wstring& filespec, bool recursive) : m_path(path), m_filespec(filespec), m_recursive(recursive) { std::transform(m_path.begin(), m_path.end(), m_path.begin(), towupper); std::transform(m_filespec.begin(), m_filespec.end(), m_filespec.begin(), towupper); } bool operator==(const File& other) const { return (m_path == other.m_path) && (m_filespec == other.m_filespec) && (m_recursive == other.m_recursive); } bool operator!=(const File& other) const { return !(*this == other); } wstring toString() const; wstring m_path; wstring m_filespec; bool m_recursive; }; // file specification together with an alternate-path target. struct TargetedFile : public File { TargetedFile(CXMLDocument node); TargetedFile(const wstring &path, const wstring& filespec, bool recursive, const wstring& alternate) : File(path, filespec, recursive), m_alternatePath(alternate) { std::transform(m_alternatePath.begin(), m_alternatePath.end(), m_alternatePath.begin(), towupper); } bool operator==(const TargetedFile& other) const { return (m_alternatePath == other.m_alternatePath) && (File::operator==(other)); } bool operator!=(const TargetedFile& other) const { return !(*this == other); } wstring toString() const; wstring m_alternatePath; }; // Writer restore method struct RestoreMethod { RestoreMethod(CXMLDocument node); bool operator==(const RestoreMethod& other) const { return (m_method == other.m_method) && (m_writerRestore == other.m_writerRestore) && (m_service ==other.m_service) && (m_rebootRequired == other.m_rebootRequired) && (m_alternateLocations == other.m_alternateLocations); } bool operator!=(const RestoreMethod& other) const { return !(*this == other); } wstring toString() const; VSS_RESTOREMETHOD_ENUM m_method; VSS_WRITERRESTORE_ENUM m_writerRestore; wstring m_service; bool m_rebootRequired; typedef XMLCollection AlternateList ; AlternateList m_alternateLocations; }; // component dependency struct Dependency { Dependency(CXMLDocument node); bool operator==(const Dependency& other) const { return (m_writerId == other.m_writerId) && (m_logicalPath == other.m_logicalPath) && (m_componentName == other.m_componentName); } bool operator!=(const Dependency& other) const { return !(*this == other); } wstring toString() const; VSS_ID m_writerId; wstring m_logicalPath; wstring m_componentName; }; // Writer component struct ComponentBase { ComponentBase(const wstring& path = L"", const wstring& name = L"") : m_logicalPath(path), m_name(name) {} wstring toString() const; wstring m_logicalPath; wstring m_name; }; struct Component : public ComponentBase { Component(CXMLDocument node); VSS_COMPONENT_TYPE m_componentType; VSS_RESTORE_TARGET m_restoreTarget; bool m_selectable; bool m_selectableForRestore; typedef XMLCollection ComponentFileList; typedef std::vector TargetList; typedef XMLCollection DependencyList; ComponentFileList m_files; DependencyList m_dependencies; TargetList m_newTargets; }; // comparison operators for Component and ComponentBase bool operator==(const ComponentBase& left, const ComponentBase& right); bool operator!=(const ComponentBase& left, const ComponentBase& right); bool operator==(const Component& left, const Component& right); bool operator!=(const Component& left, const Component& right); // Writer event. struct WriterEvent { WriterEvent(CXMLDocument node); WriterEvent(Utility::Events event, bool retryable = true, long failures = 1) : m_writerEvent(event), m_retryable(retryable), m_numFailures(failures) {} bool operator==(const WriterEvent& other) const { return m_writerEvent == other.m_writerEvent; } bool operator!=(const WriterEvent& other) const { return !(*this == other); } Utility::Events m_writerEvent; bool m_retryable; long m_numFailures; }; // Singleton class that encapsulates writer configuration class WriterConfiguration { private: // disallow explicit creation of this class WriterConfiguration() {} WriterConfiguration(WriterConfiguration&); operator= (WriterConfiguration&); mutable CComAutoCriticalSection m_section; mutable CXMLDocument m_doc; template const XMLCollection getCollection() const { assert(m_doc.GetLevel() == 0); AutoCS critical(m_section); Resetter reset(m_doc); if (m_doc.FindElement(ElementName, true)) return XMLCollection(m_doc); else return XMLCollection(); } public: typedef XMLCollection ExcludeFileList; typedef XMLCollectionComponentList; typedef XMLCollection FailEventList; static WriterConfiguration* instance(); void loadFromXML(const wstring& xml); VSS_USAGE_TYPE usage() const; Utility::Verbosity verbosity() const; bool checkExcludes() const; bool checkIncludes() const; RestoreMethod restoreMethod() const; const ExcludeFileList excludeFiles() const { return getCollection(); } const ComponentList components() const { return getCollection(); } const FailEventList failEvents() const { return getCollection(); } }; // return the singleton instance of the class // This is always called for the first time at the beginning of main, so no critical section // need be involved inline WriterConfiguration* WriterConfiguration::instance() { static WriterConfiguration configuration; return &configuration; } #endif