Example #1
0
bool CellmlFile::fullyInstantiateImports(iface::cellml_api::Model *pModel,
                                         CellmlFileIssues &pIssues)
{
    // Fully instantiate all the imports, but only if we are dealing with a non
    // CellML 1.0 model, and then keep track of that fact (so we don't fully
    // instantiate everytime we come here)

    Version cellmlVersion = version(pModel);

    if (   mFullInstantiationNeeded
        && (cellmlVersion != Unknown) && (cellmlVersion != Cellml_1_0)) {
        try {
            // Note: the below is based on CDA_Model::fullyInstantiateImports().
            //       Indeed, CDA_Model::fullyInstantiateImports() doesn't work
            //       with CellML imports that rely on https (see issue #417), so
            //       rather than calling CDA_CellMLImport::instantiate(), we
            //       call CDA_CellMLImport::instantiateFromText() instead, which
            //       requires loading the imported CellML file. Otherwise, to
            //       speed things up as much as possible, we cache the contents
            //       of the URLs that we load...

            // Retrieve the list of imports, together with their XML base values

            ObjRef<iface::cellml_api::URI> baseUri = pModel->xmlBase();
            QList<iface::cellml_api::CellMLImport *> importList = QList<iface::cellml_api::CellMLImport *>();
            QStringList importXmlBaseList = QStringList();

            retrieveImports(QString::fromStdWString(baseUri->asText()),
                            pModel, importList, importXmlBaseList);

            // Instantiate all the imports in our list

            while (!importList.isEmpty()) {
                // Retrieve the first import and instantiate it, if needed

                ObjRef<iface::cellml_api::CellMLImport> import = importList.first();
                QString importXmlBase = importXmlBaseList.first();

                importList.removeFirst();
                importXmlBaseList.removeFirst();

                if (!import->wasInstantiated()) {
                    // Note: CDA_CellMLImport::instantiate() would normally be
                    //       called, but it doesn't work with https, so we
                    //       retrieve the contents of the import ourselves and
                    //       instantiate it from text instead...

                    ObjRef<iface::cellml_api::URI> xlinkHref = import->xlinkHref();
                    QString url = QUrl(importXmlBase).resolved(QString::fromStdWString(xlinkHref->asText())).toString();
                    bool isLocalFile;
                    QString fileNameOrUrl;

                    Core::checkFileNameOrUrl(url, isLocalFile, fileNameOrUrl);

                    if (!fileNameOrUrl.compare(mFileName))
                        // We want to import ourselves, so...

                        throw(std::exception());
                    else if (mImportContents.contains(fileNameOrUrl)) {
                        // We have already loaded the import contents, so
                        // directly instantiate the import with it

                        import->instantiateFromText(mImportContents.value(fileNameOrUrl).toStdWString());
                    } else {
                        // We haven't already loaded the import contents, so do
                        // so now

                        QString fileContents;

                        if (   ( isLocalFile && Core::readTextFromFile(fileNameOrUrl, fileContents))
                            || (!isLocalFile && Core::readTextFromUrl(fileNameOrUrl, fileContents))) {
                            // We were able to retrieve the import contents, so
                            // instantiate the import with it

                            import->instantiateFromText(fileContents.toStdWString());

                            // Keep track of the import contents

                            mImportContents.insert(fileNameOrUrl, fileContents);
                        } else {
                            throw(std::exception());
                        }
                    }

                    // Now that the import is instantiated, add its own imports
                    // to our list

                    ObjRef<iface::cellml_api::Model> importModel = import->importedModel();

                    if (!importModel)
                        throw(std::exception());

                    retrieveImports(isLocalFile?
                                        QUrl::fromLocalFile(fileNameOrUrl).toString():
                                        fileNameOrUrl,
                                    importModel, importList, importXmlBaseList);
                }
            }

            mFullInstantiationNeeded = false;
        } catch (...) {
            // Something went wrong with the full instantiation of the imports

            pIssues << CellmlFileIssue(CellmlFileIssue::Error,
                                       QObject::tr("the imports could not be fully instantiated"));

            return false;
        }
    }

    return true;
}