VirtualBox

Changeset 7315 in vbox


Ignore:
Timestamp:
Mar 6, 2008 10:12:41 AM (17 years ago)
Author:
vboxsync
Message:

Main/Settings: Added XmlTreeBackend::AutoConverter subckasss and old settings tree version memorizing.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/settings.h

    r7309 r7315  
    12991299
    13001300    /**
    1301      * The InputResolver class represents an input resolver, the service used to
    1302      * provide input streams for external entities given an URL and entity ID.
     1301     * The InputResolver class represents an interface to provide input streams
     1302     * for external entities given an URL and entity ID.
    13031303     */
    13041304    class VBOXSETTINGS_CLASS InputResolver
     
    13221322    };
    13231323
     1324    /**
     1325     * The AutoConverter class represents an interface to automatically convert
     1326     * old settings trees to a new version when the tree is read from the
     1327     * stream.
     1328     */
     1329    class VBOXSETTINGS_CLASS AutoConverter
     1330    {
     1331    public:
     1332
     1333        /**
     1334         * Returns @true if the given tree needs to be converted using the XSLT
     1335         * template identified by #templateUri(), or @false if no conversion is
     1336         * required.
     1337         *
     1338         * The implementation normally checks for the "version" value of the
     1339         * root key to determine if the conversion is necessary. The
     1340         * implementation must return a string representing the old version
     1341         * (before conversion) in the @c aOldVersion argument -- this string is
     1342         * used by XmlTreeBackend::oldVersion() and must be non-NULL to indicate
     1343         * that the conversion has been performed on the tree. The returned
     1344         * string must be allocated using RTStrDup or such.
     1345         *
     1346         * @param aRoot                 Root settings key.
     1347         * @param aOldVersionString     Old version string (allocated by
     1348         *                              RTStrDup or such).
     1349         */
     1350        virtual bool needsConversion (const Key &aRoot,
     1351                                      char *&aOldVersion) const = 0;
     1352
     1353        /**
     1354         * Returns the URI of the XSLT template to perform the conversion.
     1355         * This template will be applied to the tree if #needsConversion()
     1356         * returns @c true for this tree.
     1357         */
     1358        virtual const char *templateUri() const = 0;
     1359    };
    13241360
    13251361    /**
     
    13561392
    13571393    /**
    1358      * Sets up automatic settings tree conversion.
    1359      *
    1360      * Automatic settings tree conversion is useful for upgrading old settings
    1361      * files to the new version transparently during execution of the #read()
    1362      * method.
    1363      *
    1364      * Automatic conversion is performed after reading the document from the
    1365      * stream but before validating it using the given XSLT template if the
    1366      * version check fails. The version check consists of comparing the given
    1367      * version string with the value of the given attribute of the root key. The
    1368      * conversion is performed only when the version strings are not equal.
    1369      *
    1370      * Note that in order to make the conversion permanent, the resulting tree
    1371      * needs to be exlicitly written back to the stream.
    1372      *
    1373      * The method will make copies of the supplied strings.
    1374      *
    1375      * Specifying a NULL value for all of the arguments will completely disable
    1376      * automatic conversion. Specifying an invalid root key name or a
    1377      * non-existent attribute name will disable automatic conversion too. By
    1378      * default automatic conversion it is disabled.
    1379      *
    1380      * Specifying a NULL value only for some of the arguments will throw an
    1381      * EInvalidArg exception.
    1382      *
    1383      * @param aRoot     Name of the root key containing the version attribute.
    1384      * @param aAttr     Name of the attribute containing the version string.
    1385      * @param aVersion  Version string to compare with the attribute value.
    1386      * @param aTemplate URI of the XSLT template that performs conversion.
    1387      */
    1388     void setAutoConversion (const char *aRoot, const char *aAttr,
    1389                             const char *aVersion, const char *aTemplate);
    1390 
    1391     /**
    1392      * Disables automatic settings conversion previously enabled by
    1393      * setAutoConversion(). By default automatic conversion it is disabled.
    1394      */
    1395     void resetAutoConversion()
    1396     {
    1397         setAutoConversion (NULL, NULL, NULL, NULL);
    1398     }
     1394     * Sets a settings tree converter and enables the automatic conversion.
     1395     *
     1396     * The Automatic settings tree conversion is useful for upgrading old
     1397     * settings files to the new version transparently during execution of the
     1398     * #read() method.
     1399     *
     1400     * The automatic conversion takes place after reading the document from the
     1401     * stream but before validating it. The given converter is asked if the
     1402     * conversion is necessary using the AutoConverter::needsConversion() call,
     1403     * and if so, the XSLT template specified by AutoConverter::templateUri() is
     1404     * applied to the settings tree.
     1405     *
     1406     * Note that in order to make the result of the conversion permanent, the
     1407     * settings tree needs to be exlicitly written back to the stream.
     1408     *
     1409     * The given converter object must exist as long as this instance exists or
     1410     * until a different converter is set using setAutoConverter() or reset
     1411     * using resetAutoConverter().
     1412     *
     1413     * @param aConverter    Settings converter to use.
     1414     */
     1415    void setAutoConverter (AutoConverter &aConverter);
     1416
     1417    /**
     1418     * Disables the automatic settings conversion previously enabled by
     1419     * setAutoConverter(). By default automatic conversion it is disabled.
     1420     */
     1421    void resetAutoConverter();
     1422
     1423    /**
     1424     * Returns a non-NULL string if the automatic settings conversion has been
     1425     * performed during the last successful #read() call. Returns @c NULL if
     1426     * there was no settings conversion.
     1427     *
     1428     * If #read() fails, this method will return the version string set by the
     1429     * previous successful #read() call or @c NULL if there were no #read()
     1430     * calls.
     1431     */
     1432    const char *oldVersion() const;
    13991433
    14001434    void rawRead (Input &aInput, const char *aSchema = NULL, int aFlags = 0);
  • trunk/src/VBox/Main/xml/Settings.cpp

    r7309 r7315  
    797797{
    798798    Data() : ctxt (NULL), doc (NULL)
    799            , inputResolver (NULL) {}
     799           , inputResolver (NULL)
     800           , autoConverter (NULL), oldVersion (NULL) {}
    800801
    801802    xmlParserCtxtPtr ctxt;
     
    806807    InputResolver *inputResolver;
    807808
     809    AutoConverter *autoConverter;
     810    char *oldVersion;
     811
    808812    std::auto_ptr <stdx::exception_trap_base> trappedErr;
    809 
    810     struct AutoConv
    811     {
    812         AutoConv() : root (NULL), attr (NULL), version (NULL), xslt (NULL) {}
    813         ~AutoConv() { uninit(); }
    814 
    815         void uninit()
    816         {
    817             RTStrFree (xslt); xslt = NULL;
    818             RTStrFree (version); version = NULL;
    819             RTStrFree (attr); attr = NULL;
    820             RTStrFree (root); root = NULL;
    821         }
    822 
    823         bool isNull() { return xslt == NULL; }
    824 
    825         char *root;
    826         char *attr;
    827         char *version;
    828         char *xslt;
    829     }
    830     autoConv;
    831813
    832814    /**
     
    896878}
    897879
    898 void XmlTreeBackend::setAutoConversion (const char *aRoot, const char *aAttr,
    899                                         const char *aVersion, const char *aTemplate)
    900 {
    901     if (aRoot == NULL && aAttr == NULL && aVersion == NULL && aTemplate == NULL)
    902     {
    903         m->autoConv.uninit();
    904         return;
    905     }
    906 
    907     if (aRoot == NULL || aAttr == NULL || aVersion == NULL || aTemplate == NULL)
    908         throw EInvalidArg (RT_SRC_POS);
    909 
    910     m->autoConv.root = RTStrDup (aRoot);
    911     m->autoConv.attr = RTStrDup (aAttr);
    912     m->autoConv.version = RTStrDup (aVersion);
    913     m->autoConv.xslt = RTStrDup (aTemplate);
     880void XmlTreeBackend::setAutoConverter (AutoConverter &aConverter)
     881{
     882    m->autoConverter = &aConverter;
     883}
     884
     885void XmlTreeBackend::resetAutoConverter()
     886{
     887    m->autoConverter = NULL;
     888}
     889
     890const char *XmlTreeBackend::oldVersion() const
     891{
     892    return m->oldVersion;
    914893}
    915894
     
    957936    }
    958937
     938    char *oldVersion = NULL;
     939
    959940    /* perform automatic document transformation if necessary */
    960     if (!m->autoConv.isNull())
     941    if (m->autoConverter != NULL)
    961942    {
    962943        Key root = Key (new XmlKeyBackend (xmlDocGetRootElement (doc)));
    963         if (!strcmp (root.name(), m->autoConv.root))
     944        if (m->autoConverter->needsConversion (root, oldVersion))
    964945        {
    965             const char *ver = root.stringValue (m->autoConv.attr);
    966             if (strcmp (ver, m->autoConv.version))
     946            xmlDocPtr xsltDoc = NULL;
     947            xsltStylesheetPtr xslt = NULL;
     948            xsltTransformContextPtr tranCtxt = NULL;
     949            char *errorStr = NULL;
     950
     951            try
    967952            {
    968                 /* version mismatch */
    969 
    970                 xmlDocPtr xsltDoc = NULL;
    971                 xsltStylesheetPtr xslt = NULL;
    972                 xsltTransformContextPtr tranCtxt = NULL;
    973                 char *errorStr = NULL;
    974 
    975                 try
     953                /* parse the XSLT template */
    976954                {
    977                     /* parse the XSLT */
    978                     {
    979                         Input *xsltInput =
    980                             m->inputResolver->resolveEntity (m->autoConv.xslt, NULL);
    981                         /* NOTE: new InputCtxt instance will be deleted when the
    982                          * stream is closed by the libxml2 API */
    983                         xsltDoc = xmlCtxtReadIO (m->ctxt,
    984                                                  ReadCallback, CloseCallback,
    985                                                  new Data::InputCtxt (xsltInput, m->trappedErr),
    986                                                  m->autoConv.xslt, NULL,
    987                                                  0);
    988                         delete xsltInput;
    989                     }
    990 
    991                     if (xsltDoc == NULL)
    992                     {
    993                         /* look if there was a forwared exception from the lower level */
    994                         if (m->trappedErr.get() != NULL)
    995                             m->trappedErr->rethrow();
    996 
    997                         throw XmlError (xmlCtxtGetLastError (m->ctxt));
    998                     }
    999 
    1000                     xslt = xsltParseStylesheetDoc (xsltDoc);
    1001                     if (xslt == NULL)
    1002                         throw LogicError (RT_SRC_POS);
    1003 
    1004                     /* setup transformation error reporting */
    1005                     tranCtxt = xsltNewTransformContext (xslt, xsltDoc);
    1006                     if (tranCtxt == NULL)
    1007                         throw LogicError (RT_SRC_POS);
    1008                     xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback);
    1009 
    1010                     xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL,
    1011                                                                 NULL, NULL, tranCtxt);
    1012                     if (newDoc == NULL)
    1013                         throw LogicError (RT_SRC_POS);
    1014 
    1015                     if (errorStr != NULL)
    1016                     {
    1017                         xmlFreeDoc (newDoc);
    1018                         throw Error (errorStr);
    1019                         /* errorStr is freed in catch(...) below */
    1020                     }
    1021 
    1022                     /* replace the old document on success */
    1023                     xmlFreeDoc (doc);
    1024                     doc = newDoc;
    1025 
     955                    Input *xsltInput =
     956                        m->inputResolver->resolveEntity
     957                            (m->autoConverter->templateUri(), NULL);
     958                    /* NOTE: new InputCtxt instance will be deleted when the
     959                     * stream is closed by the libxml2 API */
     960                    xsltDoc = xmlCtxtReadIO (m->ctxt,
     961                                             ReadCallback, CloseCallback,
     962                                             new Data::InputCtxt (xsltInput, m->trappedErr),
     963                                             m->autoConverter->templateUri(),
     964                                             NULL, 0);
     965                    delete xsltInput;
     966                }
     967
     968                if (xsltDoc == NULL)
     969                {
     970                    /* look if there was a forwared exception from the lower level */
     971                    if (m->trappedErr.get() != NULL)
     972                        m->trappedErr->rethrow();
     973
     974                    throw XmlError (xmlCtxtGetLastError (m->ctxt));
     975                }
     976
     977                xslt = xsltParseStylesheetDoc (xsltDoc);
     978                if (xslt == NULL)
     979                    throw LogicError (RT_SRC_POS);
     980
     981                /* setup transformation error reporting */
     982                tranCtxt = xsltNewTransformContext (xslt, xsltDoc);
     983                if (tranCtxt == NULL)
     984                    throw LogicError (RT_SRC_POS);
     985                xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback);
     986
     987                xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL,
     988                                                            NULL, NULL, tranCtxt);
     989                if (newDoc == NULL)
     990                    throw LogicError (RT_SRC_POS);
     991
     992                if (errorStr != NULL)
     993                {
     994                    xmlFreeDoc (newDoc);
     995                    throw Error (errorStr);
     996                    /* errorStr is freed in catch(...) below */
     997                }
     998
     999                /* replace the old document on success */
     1000                xmlFreeDoc (doc);
     1001                doc = newDoc;
     1002
     1003                xsltFreeTransformContext (tranCtxt);
     1004
     1005                /* NOTE: xsltFreeStylesheet() also fress the document
     1006                 * passed to xsltParseStylesheetDoc(). */
     1007                xsltFreeStylesheet (xslt);
     1008            }
     1009            catch (...)
     1010            {
     1011                /* restore the previous entity resolver */
     1012                xmlSetExternalEntityLoader (oldEntityLoader);
     1013                sThat = NULL;
     1014
     1015                RTStrFree (errorStr);
     1016
     1017                if (tranCtxt != NULL)
    10261018                    xsltFreeTransformContext (tranCtxt);
    10271019
    1028                     /* NOTE: xsltFreeStylesheet() also fress the document
    1029                      * passed to xsltParseStylesheetDoc(). */
     1020                /* NOTE: xsltFreeStylesheet() also fress the document
     1021                 * passed to xsltParseStylesheetDoc(). */
     1022                if (xslt != NULL)
    10301023                    xsltFreeStylesheet (xslt);
    1031                 }
    1032                 catch (...)
    1033                 {
    1034                     /* restore the previous entity resolver */
    1035                     xmlSetExternalEntityLoader (oldEntityLoader);
    1036                     sThat = NULL;
    1037 
    1038                     RTStrFree (errorStr);
    1039 
    1040                     if (tranCtxt != NULL)
    1041                         xsltFreeTransformContext (tranCtxt);
    1042 
    1043                     /* NOTE: xsltFreeStylesheet() also fress the document
    1044                      * passed to xsltParseStylesheetDoc(). */
    1045                     if (xslt != NULL)
    1046                         xsltFreeStylesheet (xslt);
    1047                     else if (xsltDoc != NULL)
    1048                         xmlFreeDoc (xsltDoc);
    1049 
    1050                     throw;
    1051                 }
     1024                else if (xsltDoc != NULL)
     1025                    xmlFreeDoc (xsltDoc);
     1026
     1027                RTStrFree (oldVersion);
     1028
     1029                throw;
    10521030            }
    10531031        }
     
    11301108                xmlSchemaFreeParserCtxt (schemaCtxt);
    11311109
     1110            RTStrFree (oldVersion);
     1111
    11321112            throw;
    11331113        }
     
    11441124    /* assign the root key */
    11451125    m->root = Key (new XmlKeyBackend (xmlDocGetRootElement (m->doc)));
     1126
     1127    /* memorize the old version string also used as a flag that
     1128     * the conversion has been performed (transfers ownership) */
     1129    m->oldVersion = oldVersion;
    11461130}
    11471131
     
    11871171void XmlTreeBackend::reset()
    11881172{
     1173    RTStrFree (m->oldVersion);
     1174    m->oldVersion = NULL;
     1175
    11891176    if (m->doc)
    11901177    {
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette