| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "na64calib/loaders/yaml-document.hh" | ||
| 2 | #include "na64util/uri.hh" | ||
| 3 | #include "na64calib/manager.hh" | ||
| 4 | |||
| 5 | namespace na64dp { | ||
| 6 | namespace calib { | ||
| 7 | |||
| 8 | void | ||
| 9 | ✗ | YAMLDocumentLoader::load( const iUpdate & recipe | |
| 10 | , Dispatcher & dsp | ||
| 11 | ) { | ||
| 12 | ✗ | auto rttiIt = CIDataAliases::self() | |
| 13 | ✗ | .name_by_type_id() | |
| 14 | ✗ | .find(recipe.subject_data_type()); | |
| 15 | ✗ | if( CIDataAliases::self().name_by_type_id().end() == rttiIt ) { | |
| 16 | ✗ | NA64DP_RUNTIME_ERROR( "Can't lookup for conversion of unaliased type" | |
| 17 | " %s." | ||
| 18 | , util::calib_id_to_str(recipe.subject_data_type()).c_str() ); | ||
| 19 | } | ||
| 20 | ✗ | const std::string & typeAlias = rttiIt->second; | |
| 21 | // Find the conversion callback | ||
| 22 | ✗ | auto it = _conversions.find(typeAlias); | |
| 23 | ✗ | if( _conversions.end() == it ) { | |
| 24 | ✗ | NA64DP_RUNTIME_ERROR( "No data conversion from YAML node to type \"%s\"" | |
| 25 | " (alias to %s) defined for generic YAML document loader." | ||
| 26 | , typeAlias.c_str() | ||
| 27 | , util::calib_id_to_str(recipe.subject_data_type()).c_str() ); | ||
| 28 | } | ||
| 29 | |||
| 30 | // Reach the file and parse it to the YAML node | ||
| 31 | ✗ | YAML::Node n; | |
| 32 | // Downcast to yaml update | ||
| 33 | ✗ | const iSpecificUpdate<YAML::Node> & upd | |
| 34 | = static_cast<const iSpecificUpdate<YAML::Node>&>(recipe); | ||
| 35 | ✗ | if( upd.payload["source"] ) { | |
| 36 | // load source | ||
| 37 | ✗ | std::string path = upd.payload["source"].as<std::string>(); | |
| 38 | ✗ | auto names = util::expand_names( path ); | |
| 39 | ✗ | if( 1 != names.size() ) { | |
| 40 | ✗ | NA64DP_RUNTIME_ERROR( "Failed to expand string expression to the" | |
| 41 | " file name: \"%s\".", path.c_str() ); | ||
| 42 | } | ||
| 43 | ✗ | _log << log4cpp::Priority::DEBUG | |
| 44 | ✗ | << "\"source\" field provided for update -- reading file \"" | |
| 45 | ✗ | << path << "\" expanded as \"" << names[0].c_str() << "\"..." | |
| 46 | ; | ||
| 47 | try { | ||
| 48 | ✗ | n = YAML::LoadFile( names[0] ); | |
| 49 | ✗ | } catch( std::exception & e ) { | |
| 50 | ✗ | _log.error( "Error occured while accessing, reading or parsing" | |
| 51 | " YAML calibration data \"%s\": %s" | ||
| 52 | ✗ | , names[0].c_str() | |
| 53 | ✗ | , e.what() | |
| 54 | ); | ||
| 55 | ✗ | throw; | |
| 56 | } | ||
| 57 | ✗ | _log.debug( "Converting data of YAML document \"%s\" into %s..." | |
| 58 | ✗ | , names[0].c_str() | |
| 59 | ✗ | , util::calib_id_to_str(recipe.subject_data_type()).c_str() ); | |
| 60 | // Perform the conversion and dispatch the data | ||
| 61 | try { | ||
| 62 | ✗ | it->second(n, dsp); | |
| 63 | ✗ | } catch( std::exception & e ) { | |
| 64 | ✗ | _log.error( "During conversion of YAML document data \"%s\" into" | |
| 65 | " %s occured an error: %s." | ||
| 66 | ✗ | , names[0].c_str() | |
| 67 | ✗ | , util::calib_id_to_str(recipe.subject_data_type()).c_str() | |
| 68 | ✗ | , e.what() | |
| 69 | ); | ||
| 70 | ✗ | throw; | |
| 71 | } | ||
| 72 | ✗ | _log.debug( "Calibration info from YAML document \"%s\" has been loaded into %s." | |
| 73 | ✗ | , names[0].c_str() | |
| 74 | ✗ | , util::calib_id_to_str(recipe.subject_data_type()).c_str() ); | |
| 75 | ✗ | } else if( upd.payload["payload"] ) { | |
| 76 | // directly use information from payload | ||
| 77 | ✗ | _log << log4cpp::Priority::DEBUG | |
| 78 | ✗ | << "\"payload\" field provided for update -- converting it to " | |
| 79 | ✗ | << util::calib_id_to_str(recipe.subject_data_type()) << "..." | |
| 80 | ; | ||
| 81 | // Perform the conversion and dispatch the data | ||
| 82 | ✗ | it->second(upd.payload["payload"], dsp); | |
| 83 | ✗ | _log.debug( "Calibration data from YAML node has been loaded into %s." | |
| 84 | ✗ | , util::calib_id_to_str(recipe.subject_data_type()).c_str() ); | |
| 85 | } else { | ||
| 86 | // This must be a result of a wrong specification | ||
| 87 | ✗ | NA64DP_RUNTIME_ERROR( "Update did not bring payload info meaningful" | |
| 88 | " for this loader (perhaps, wrong specification of" | ||
| 89 | " recommended loader in the update)." ); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | bool | ||
| 94 | ✗ | YAMLDocumentLoader::can_handle( const iUpdate & recipe ) { | |
| 95 | // This handler is capable to handle update if: | ||
| 96 | // - type is aliased | ||
| 97 | // - the subject type conversion is defined | ||
| 98 | // - update type can be downcasted to the iSpecificUpdate<YAML::Node> | ||
| 99 | // - YAML node has "payload" or "source" fields | ||
| 100 | ✗ | auto rttiIt = CIDataAliases::self() | |
| 101 | ✗ | .name_by_type_id() | |
| 102 | ✗ | .find(recipe.subject_data_type()); | |
| 103 | ✗ | if( CIDataAliases::self().name_by_type_id().end() == rttiIt ) { | |
| 104 | ✗ | return false; // unaliased type | |
| 105 | } | ||
| 106 | ✗ | const std::string & typeAlias = rttiIt->second; | |
| 107 | |||
| 108 | ✗ | auto it = _conversions.find(typeAlias); | |
| 109 | ✗ | if( _conversions.end() == it ) return false; // no conversion defined | |
| 110 | |||
| 111 | ✗ | auto ptr = dynamic_cast<const iSpecificUpdate<YAML::Node>*>(&recipe); | |
| 112 | ✗ | if(!ptr) return false; // downcast failed | |
| 113 | |||
| 114 | ✗ | return ((bool) ptr->payload["payload"]) | |
| 115 | ✗ | || ((bool) ptr->payload["source"]); | |
| 116 | } | ||
| 117 | |||
| 118 | void | ||
| 119 | ✗ | YAMLDocumentLoader::define_conversion( | |
| 120 | const std::string & aliasName | ||
| 121 | , void (*callback)(const YAML::Node &, Dispatcher &) | ||
| 122 | ) { | ||
| 123 | ✗ | auto ir = _conversions.emplace(aliasName, callback); | |
| 124 | ✗ | if( ! ir.second ) { | |
| 125 | ✗ | if(ir.first->second != ir.first->second) | |
| 126 | ✗ | NA64DP_RUNTIME_ERROR( "Ambiguious conversion for type alias" | |
| 127 | " \"%s\" requested (different conversion" | ||
| 128 | " callback for this type is provided to YAML document" | ||
| 129 | " loader)." | ||
| 130 | , aliasName.c_str() ); | ||
| 131 | ✗ | _log.debug( "Repeated registration of the conversion callback for alias" | |
| 132 | " \"%s\" is omitted.", aliasName.c_str() ); | ||
| 133 | } else { | ||
| 134 | ✗ | _log.debug( "Added YAML document conversion for type with alias \"%s\"." | |
| 135 | , aliasName.c_str() ); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void | ||
| 140 | ✗ | YAMLDocumentLoader::to_yaml_as_loader( YAML::Node & node ) const { | |
| 141 | char bf[128]; | ||
| 142 | ✗ | node["_type"] = "YAMLDocumentLoader"; | |
| 143 | ✗ | snprintf(bf, sizeof(bf), "%p", this); | |
| 144 | ✗ | node["_ptr"] = bf; | |
| 145 | ✗ | YAML::Node conversions; | |
| 146 | ✗ | for( auto cnvPair : _conversions ) { | |
| 147 | ✗ | snprintf(bf, sizeof(bf), "%p", cnvPair.second); | |
| 148 | ✗ | conversions[cnvPair.first] = bf; | |
| 149 | } | ||
| 150 | ✗ | node["conversions"] = conversions; | |
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | #if 0 | ||
| 155 | void | ||
| 156 | YAMLDocumentLoader::put_provided_types( CITypeAliases & aliases ) { | ||
| 157 | assert(!_aliases); // same loader instance is added to another manager? | ||
| 158 | _aliases = &aliases; | ||
| 159 | } | ||
| 160 | |||
| 161 | bool | ||
| 162 | YAMLDocumentLoader::can_handle( const iIndex::UpdateRecipe & updRecipe | ||
| 163 | , Dispatcher::CIDataID dataID ) { | ||
| 164 | // TODO: check if the file is reachable using updRecipe.payload["source"] | ||
| 165 | return _callbacks.end() != _callbacks.find(dataID); | ||
| 166 | } | ||
| 167 | #endif | ||
| 168 | |||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 |