Configuration.cpp

Go to the documentation of this file.
00001 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00002  *
00003  * VR Juggler is (C) Copyright 1998-2005 by Iowa State University
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum, Christopher Just,
00007  *   Patrick Hartling, Kevin Meinert,
00008  *   Carolina Cruz-Neira, Albert Baker
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Library General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2 of the License, or (at your option) any later version.
00014  *
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Library General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Library General Public
00021  * License along with this library; if not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023  * Boston, MA 02111-1307, USA.
00024  *
00025  * -----------------------------------------------------------------
00026  * File:          $RCSfile$
00027  * Date modified: $Date: 2006-10-31 10:03:11 -0600 (Tue, 31 Oct 2006) $
00028  * Version:       $Revision: 19396 $
00029  * -----------------------------------------------------------------
00030  *
00031  *************** <auto-copyright.pl END do not edit this line> ***************/
00032 
00033 #include <jccl/jcclConfig.h>
00034 
00035 #include <fstream>
00036 #include <sys/types.h>
00037 
00038 #include <vpr/vpr.h>
00039 #include <vpr/Util/FileUtils.h>
00040 
00041 #include <jccl/Util/Debug.h>
00042 #include <jccl/Config/ConfigTokens.h>
00043 #include <jccl/Config/ParseUtil.h>
00044 #include <jccl/Config/ConfigElement.h>
00045 #include <jccl/Config/ElementFactory.h>
00046 #include <jccl/Config/Configuration.h>
00047 
00048 namespace tokens = jccl::configuration_tokens;
00049 
00050 namespace jccl
00051 {
00052 
00053 Configuration::Configuration()
00054 {}
00055 
00056 Configuration::Configuration(const Configuration& db)
00057 {
00058    *this = db;
00059 }
00060 
00061 Configuration::~Configuration()
00062 {}
00063 
00064 const std::string& Configuration::getFileName() const
00065 {
00066    return mFileName;
00067 }
00068 
00069 void Configuration::setFileName(const std::string& fname)
00070 {
00071    mFileName = fname;
00072 }
00073 
00074 ConfigElementPtr Configuration::get(const std::string& name) const
00075 {
00076    for ( std::vector<ConfigElementPtr>::const_iterator i = mElements.begin();
00077          i != mElements.end();
00078          ++i )
00079    {
00080       if ( name == (*i)->getName() )
00081       {
00082          return *i;
00083       }
00084    }
00085    return ConfigElementPtr();
00086 }
00087 
00088 void Configuration::getByType(const std::string& typeName,
00089                               std::vector<ConfigElementPtr>& elements) const
00090 {
00091 
00092    for ( std::vector<ConfigElementPtr>::const_iterator i = mElements.begin();
00093          i != mElements.end();
00094          ++i )
00095    {
00096       if ( typeName == (*i)->getID() )
00097       {
00098          elements.push_back(*i);
00099       }
00100    }
00101 }
00102 
00103 bool Configuration::remove(const std::string& name)
00104 {
00105    for ( std::vector<ConfigElementPtr>::iterator i = mElements.begin();
00106          i != mElements.end();
00107          ++i )
00108    {
00109       if ( name == (*i)->getName() )
00110       {
00111          mElements.erase(i);
00112          return true;
00113       }
00114    }
00115    return false;
00116 }
00117 
00118 /* IO functions: */
00119 
00120 std::ostream& operator<<(std::ostream& out, const Configuration& self)
00121 {
00122    cppdom::NodePtr cfg_node;
00123 
00124    // TODO: Find a better way of doing this, the java side seems to be able to
00125    // do it just fine.
00126    out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
00127    out << "<?" << tokens::SETTINGS_INSTRUCTION << " "
00128        << tokens::CFG_VERSION_ATTR << "=\"" << tokens::CFG_VERSION << "\"?>";
00129 
00130    self.createConfigurationNode(cfg_node);
00131    cfg_node->save(out);
00132    return out;
00133 }
00134 
00135 std::istream& operator>>(std::istream& in, Configuration& self)
00136 {
00137    // Create a new XML document
00138    cppdom::DocumentPtr cfg_doc(ElementFactory::instance()->createXMLDocument());
00139    cppdom::ContextPtr context_ptr = cfg_doc->getContext();
00140 
00141    // Load the document from the input stream.
00142    cfg_doc->load(in, context_ptr);
00143 
00144    // Get the configuration node.
00145    cppdom::NodePtr cfg_node(cfg_doc->getChild(tokens::CONFIGURATION));
00146    self.setConfigurationNode(cfg_node);
00147 
00148    // Load in the elements from the confiruration node.
00149    self.loadFromElementNode(cfg_node->getChild(tokens::ELEMENTS));
00150 
00151    cppdom::NodePtr def_path_node(cfg_node->getChild(tokens::DEFINITION_PATH));
00152    if ( def_path_node.get() != NULL )
00153    {
00154       self.setDefinitionPath(def_path_node);
00155    }
00156 
00157    // Go through the <include> XML elements.
00158    cppdom::NodeList inc_list = cfg_node->getChildren(tokens::INCLUDE);
00159    for ( cppdom::NodeList::iterator itr = inc_list.begin();
00160          itr != inc_list.end();
00161          ++itr )
00162    {
00163       std::string cfg_filename = (*itr)->getCdata();
00164       vprDEBUG(jcclDBG_CONFIG, vprDBG_CONFIG_LVL)
00165          << "Including " << cfg_filename << std::endl
00166          << vprDEBUG_FLUSH;
00167 
00168       // Load the file.
00169       // NOTE: Loading from a stream means that we have no parent file name to
00170       // provide to jccl::Configuration::load().
00171       self.load(cfg_filename);
00172    }
00173 
00174    return in;
00175 }
00176 
00177 bool Configuration::load(const std::string& filename,
00178                          const std::string& parentfile)
00179 {
00180    vprDEBUG(jcclDBG_CONFIG, vprDBG_STATE_LVL)
00181       << "[jccl::Configuration::load()] Loading file '" << filename
00182       << "' with parent file '" << parentfile << "'\n" << vprDEBUG_FLUSH;
00183 
00184    mFileName = ParseUtil::expandFileName(filename, parentfile);
00185 
00186    vprDEBUG_OutputGuard(jcclDBG_CONFIG, vprDBG_CONFIG_LVL,
00187                         std::string("Loading config file ") + mFileName +
00188                            std::string("\n"),
00189                         std::string(""));
00190 
00191    // XXX: Previously, this used ElementFactory::createXMLDocument(), but for
00192    // some reason, that caused error reporting to be totally useless.
00193    cppdom::Document cfg_doc(cppdom::ContextPtr(new cppdom::Context()));
00194    bool status(false);
00195 
00196    try
00197    {
00198       cfg_doc.loadFile(mFileName);
00199 
00200       cppdom::NodePtr cfg_node(cfg_doc.getChild(tokens::CONFIGURATION));
00201       vprASSERT(cfg_node.get() != NULL);
00202 
00203       // Save the configuration node for later use.
00204 
00205       mConfigurationNode = cfg_node;
00206 
00207       cppdom::NodePtr def_path_node(cfg_node->getChild(tokens::DEFINITION_PATH));
00208       if ( def_path_node.get() != NULL )
00209       {
00210          setDefinitionPath(def_path_node);
00211       }
00212 
00213       // Go through the <include> XML elements.
00214       cppdom::NodeList inc_list = cfg_node->getChildren(tokens::INCLUDE);
00215       for ( cppdom::NodeList::iterator itr = inc_list.begin();
00216             itr != inc_list.end();
00217             ++itr )
00218       {
00219          std::string cfg_filename = (*itr)->getCdata();
00220          vprDEBUG(jcclDBG_CONFIG, vprDBG_CONFIG_LVL)
00221             << "Including " << cfg_filename << std::endl
00222             << vprDEBUG_FLUSH;
00223 
00224          // Load the file by making a recursive call to this method. We use
00225          // mFileName so that the fully expanded path to the includin file is
00226          // used as the "parent" file.
00227          load(cfg_filename, mFileName);
00228       }
00229 
00230       // Load in the elements in the original file.
00231       loadFromElementNode(cfg_node->getChild(tokens::ELEMENTS), mFileName);
00232 
00233       status = true;
00234    }
00235    catch (cppdom::Error& xml_e)
00236    {
00237       cppdom::Location where(cfg_doc.getContext()->getLocation());
00238       std::string errmsg = xml_e.getStrError();
00239 
00240       int line_num = where.getLine() + 1;
00241       int pos      = where.getPos() + 1;
00242 
00243       // print out where the error occured
00244       vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00245          << clrOutBOLD(clrRED, "Configuration XML Error:") << " "
00246          << mFileName << ": line " << line_num << " at position " << pos
00247          << std::endl << vprDEBUG_FLUSH;
00248       vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00249          << "Error: " << errmsg << std::endl << vprDEBUG_FLUSH;
00250 
00251       // Print out the actual failed XML.
00252       std::ifstream errfile(mFileName.c_str());
00253       if ( errfile )
00254       {
00255          char linebuffer[1024];
00256          for ( int i = 0; i < line_num && ! errfile.eof(); ++i )
00257          {
00258             errfile.getline(linebuffer, 1024);
00259          }
00260 
00261          if ( pos >= 80 )
00262          {
00263             pos %= 80;
00264          }
00265 
00266          std::string err_line(linebuffer + (where.getPos() - pos));
00267          if (err_line.length() >= 79)
00268          {
00269             err_line.erase(79);
00270          }
00271 
00272          std::cout << err_line << std::endl;
00273          std::cout << linebuffer << std::endl;
00274 
00275          for ( int i = 2; i < pos; ++i )
00276          {
00277             std::cout << " ";
00278          }
00279 
00280          std::cout << '^' << std::endl;
00281       }
00282    }
00283 
00284    return status;
00285 }
00286 
00287 bool Configuration::save(const std::string& fname) const
00288 {
00289    cppdom::NodePtr cfg_node;
00290    createConfigurationNode(cfg_node);                        // Get base configuration element
00291    cppdom::DocumentPtr cfg_doc(new cppdom::Document);        // Put in in a document
00292    cfg_doc->addChild(cfg_node);
00293    cfg_doc->saveFile(fname);                                 // Write out the document
00294    return true;
00295 }
00296 
00297 std::vector<jccl::ConfigElementPtr>& Configuration::vec()
00298 {
00299    return mElements;
00300 }
00301 
00302 void Configuration::setDefinitionPath(cppdom::NodePtr defPathNode)
00303 {
00304    mDefsPath.clear();
00305    extendDefinitionPath(defPathNode);
00306 }
00307 
00308 void Configuration::setConfigurationNode(cppdom::NodePtr cfgNode)
00309 {
00310    mConfigurationNode = cfgNode;
00311 }
00312 
00313 void Configuration::extendDefinitionPath(cppdom::NodePtr defPathNode)
00314 {
00315    cppdom::NodeList dirs = defPathNode->getChildren(tokens::DIR);
00316    for (cppdom::NodeList::iterator d = dirs.begin(); d != dirs.end(); ++d)
00317    {
00318       mDefsPath.push_back((*d)->getCdata());
00319       ElementFactory::instance()->loadDefs(vpr::replaceEnvVars((*d)->getCdata()));
00320    }
00321 }
00322 
00326 struct ElementNamePred
00327 {
00328    ElementNamePred(const std::string& name)
00329       : mName(name)
00330    {}
00331 
00332    bool operator()(jccl::ConfigElementPtr element)
00333    {
00334       return (element->getName() == mName);
00335    }
00336 
00337    std::string mName;
00338 };
00339 
00341 bool Configuration::loadFromElementNode(cppdom::NodePtr elementsNode,
00342                                         const std::string& currentFile)
00343 {
00344    if(elementsNode->getName() != tokens::ELEMENTS)
00345    {
00346       vprASSERT(false && "Trying to load a elements tree that is not an <elements> node");
00347       return false;
00348    }
00349 
00350    for (cppdom::NodeList::iterator cur_child = elementsNode->getChildren().begin();
00351         cur_child != elementsNode->getChildren().end();
00352         ++cur_child)
00353    {
00354       ConfigElementPtr new_element(new ConfigElement());            // New element
00355       bool init_status = new_element->initFromNode(*cur_child);     // Initialize it
00356 
00357       // Make sure that there were no problems creating the new element
00358       // (ex: invalid definition).
00359       if(!init_status)
00360       {
00361          vprDEBUG(vprDBG_ALL,vprDBG_CRITICAL_LVL)
00362             << "  Config element load problem in file: " << currentFile
00363             << std::endl << vprDEBUG_FLUSH;
00364          vprDEBUG(vprDBG_ALL,vprDBG_CRITICAL_LVL)
00365             << "  Skipping element: " << (*cur_child)->getAttribute(tokens::NAME).getString()
00366             << std::endl << vprDEBUG_FLUSH;
00367       }
00368       else
00369       {
00370          // Before we can add new_element to the database, we have to determine
00371          // if there is already a element with the same name.
00372          std::vector<ConfigElementPtr>::iterator iter =
00373             std::find_if(mElements.begin(), mElements.end(),
00374                          ElementNamePred(new_element->getName()));
00375 
00376          // If no existing element has the same name as new_element, then we
00377          // can just add it to the end.
00378          if ( iter == mElements.end() )
00379          {
00380             mElements.push_back(new_element);
00381          }
00382          // Otherwise, overwrite the old version.
00383          else
00384          {
00385             *iter = new_element;
00386          }
00387       }
00388    }
00389 
00390    return true;
00391 }
00392 
00393 void Configuration::createConfigurationNode(cppdom::NodePtr& cfgNode) const
00394 {
00395    if (NULL == mConfigurationNode.get())
00396    {
00397       cfgNode = ElementFactory::instance()->createXMLNode();
00398       cfgNode->setName(tokens::CONFIGURATION);
00399       cfgNode->setAttribute("xmlns", tokens::CFG_NS_str);
00400       cfgNode->setAttribute("name", "Active Configuration");
00401       cfgNode->setAttribute("xmlns:xsi",
00402                             "http://www.w3.org/2001/XMLSchema-instance");
00403       cfgNode->setAttribute("xsi:schemaLocation",
00404                             tokens::CFG_NS_str + " " + tokens::CFG_SCHEMA);
00405 
00406       cppdom::NodePtr elements_node = ElementFactory::instance()->createXMLNode();
00407       elements_node->setName(tokens::ELEMENTS);
00408 
00409       std::vector<ConfigElementPtr>::const_iterator cur_element;
00410 
00411       for (cur_element = mElements.begin();
00412            cur_element != mElements.end();
00413            ++cur_element)
00414       {
00415          cppdom::NodePtr child_node = (*cur_element)->getNode();
00416          elements_node->addChild(child_node);
00417       }
00418 
00419       cfgNode->addChild(elements_node);
00420    }
00421    else
00422    {
00423       cfgNode = mConfigurationNode;
00424    }
00425 }
00426 
00427 } // End of jccl namespace

Generated on Thu Jan 4 10:49:32 2007 for JCCL: Juggler Configuration and Control Library by  doxygen 1.5.1