1 // 2 // Copyright 2018 Pixar 3 // 4 // Licensed under the Apache License, Version 2.0 (the "Apache License") 5 // with the following modification; you may not use this file except in 6 // compliance with the Apache License and the following modification to it: 7 // Section 6. Trademarks. is deleted and replaced with: 8 // 9 // 6. Trademarks. This License does not grant permission to use the trade 10 // names, trademarks, service marks, or product names of the Licensor 11 // and its affiliates, except as required to comply with Section 4(c) of 12 // the License and to reproduce the content of the NOTICE file. 13 // 14 // You may obtain a copy of the Apache License at 15 // 16 // http://www.apache.org/licenses/LICENSE-2.0 17 // 18 // Unless required by applicable law or agreed to in writing, software 19 // distributed under the Apache License with the above modification is 20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 // KIND, either express or implied. See the Apache License for the specific 22 // language governing permissions and limitations under the Apache License. 23 // 24 25 #ifndef PXR_USD_NDR_REGISTRY_H 26 #define PXR_USD_NDR_REGISTRY_H 27 28 /// \file ndr/registry.h 29 30 #include "pxr/pxr.h" 31 #include "pxr/usd/ndr/api.h" 32 #include "pxr/base/tf/weakBase.h" 33 #include "pxr/usd/ndr/declare.h" 34 #include "pxr/usd/ndr/discoveryPlugin.h" 35 #include "pxr/usd/ndr/node.h" 36 #include "pxr/usd/ndr/nodeDiscoveryResult.h" 37 #include "pxr/usd/ndr/parserPlugin.h" 38 #include "pxr/usd/sdf/assetPath.h" 39 #include <mutex> 40 41 PXR_NAMESPACE_OPEN_SCOPE 42 43 /// \class NdrRegistry 44 /// 45 /// The registry provides access to node information. "Discovery Plugins" are 46 /// responsible for finding the nodes that should be included in the registry. 47 /// 48 /// Discovery plugins are found through the plugin system. If additional 49 /// discovery plugins need to be specified, a client can pass them to 50 /// `SetExtraDiscoveryPlugins()`. 51 /// 52 /// When the registry is first told about the discovery plugins, the plugins 53 /// will be asked to discover nodes. These plugins will generate 54 /// `NdrNodeDiscoveryResult` instances, which only contain basic metadata. Once 55 /// the client asks for information that would require the node's contents to 56 /// be parsed (eg, what its inputs and outputs are), the registry will begin the 57 /// parsing process on an as-needed basis. See `NdrNodeDiscoveryResult` for the 58 /// information that can be retrieved without triggering a parse. 59 /// 60 /// Some methods in this library may allow for a "family" to be provided. A 61 /// family is simply a generic grouping which is optional. 62 /// 63 class NdrRegistry : public TfWeakBase 64 { 65 public: 66 using DiscoveryPluginRefPtrVec = NdrDiscoveryPluginRefPtrVector; 67 68 /// Allows the client to set any additional discovery plugins that would 69 /// otherwise NOT be found through the plugin system. Runs the discovery 70 /// process for the specified plugins immediately. 71 /// 72 /// Note that this method cannot be called after any nodes in the registry 73 /// have been parsed (eg, through GetNode*()), otherwise an error will 74 /// result. 75 NDR_API 76 void SetExtraDiscoveryPlugins(DiscoveryPluginRefPtrVec plugins); 77 78 /// Allows the client to set any additional discovery plugins that would 79 /// otherwise NOT be found through the plugin system. Runs the discovery 80 /// process for the specified plugins immediately. 81 /// 82 /// Note that this method cannot be called after any nodes in the registry 83 /// have been parsed (eg, through GetNode*()), otherwise an error will 84 /// result. 85 NDR_API 86 void SetExtraDiscoveryPlugins(const std::vector<TfType>& pluginTypes); 87 88 /// Allows the client to set any additional parser plugins that would 89 /// otherwise NOT be found through the plugin system. 90 /// 91 /// Note that this method cannot be called after any nodes in the registry 92 /// have been parsed (eg, through GetNode*()), otherwise an error will 93 /// result. 94 NDR_API 95 void SetExtraParserPlugins(const std::vector<TfType>& pluginTypes); 96 97 /// Parses the given \p asset, constructs a NdrNode from it and adds it to 98 /// the registry. 99 /// 100 /// Nodes created from an asset using this API can be looked up by the 101 /// unique identifier and sourceType of the returned node, or by URI, 102 /// which will be set to the unresolved asset path value. 103 /// 104 /// \p metadata contains additional metadata needed for parsing and 105 /// compiling the source code in the file pointed to by \p asset correctly. 106 /// This metadata supplements the metadata available in the asset and 107 /// overrides it in cases where there are key collisions. 108 /// 109 /// \p subidentifier is optional, and it would be used to indicate a 110 /// particular definition in the asset file if the asset contains multiple 111 /// node definitions. 112 /// 113 /// \p sourceType is optional, and it is only needed to indicate a 114 /// particular type if the asset file is capable of representing a node 115 /// definition of multiple source types. 116 /// 117 /// Returns a valid node if the asset is parsed successfully using one 118 /// of the registered parser plugins. 119 NDR_API 120 NdrNodeConstPtr GetNodeFromAsset(const SdfAssetPath &asset, 121 const NdrTokenMap &metadata, 122 const TfToken &subIdentifier=TfToken(), 123 const TfToken &sourceType=TfToken()); 124 125 /// Parses the given \p sourceCode string, constructs a NdrNode from it and 126 /// adds it to the registry. The parser to be used is determined by the 127 /// specified \p sourceType. 128 /// 129 /// Nodes created from source code using this API can be looked up by the 130 /// unique identifier and sourceType of the returned node. 131 /// 132 /// \p metadata contains additional metadata needed for parsing and 133 /// compiling the source code correctly. This metadata supplements the 134 /// metadata available in \p sourceCode and overrides it cases where there 135 /// are key collisions. 136 /// 137 /// Returns a valid node if the given source code is parsed successfully 138 /// using the parser plugins that is registered for the specified 139 /// \p sourceType. 140 NDR_API 141 NdrNodeConstPtr GetNodeFromSourceCode(const std::string &sourceCode, 142 const TfToken &sourceType, 143 const NdrTokenMap &metadata); 144 145 /// Get the locations where the registry is searching for nodes. 146 /// 147 /// Depending on which discovery plugins were used, this may include 148 /// non-filesystem paths. 149 NDR_API 150 NdrStringVec GetSearchURIs() const; 151 152 /// Get the identifiers of all the nodes that the registry is aware of. 153 /// 154 /// This will not run the parsing plugins on the nodes that have been 155 /// discovered, so this method is relatively quick. Optionally, a "family" 156 /// name can be specified to only get the identifiers of nodes that belong 157 /// to that family and a filter can be specified to get just the default 158 /// version (the default) or all versions of the node. 159 NDR_API 160 NdrIdentifierVec 161 GetNodeIdentifiers(const TfToken& family = TfToken(), 162 NdrVersionFilter filter = 163 NdrVersionFilterDefaultOnly) const; 164 165 /// Get the names of all the nodes that the registry is aware of. 166 /// 167 /// This will not run the parsing plugins on the nodes that have been 168 /// discovered, so this method is relatively quick. Optionally, a "family" 169 /// name can be specified to only get the names of nodes that belong to 170 /// that family. 171 NDR_API 172 NdrStringVec GetNodeNames(const TfToken& family = TfToken()) const; 173 174 /// Get the node with the specified \p identifier, and an optional 175 /// \p sourceTypePriority list specifying the set of node SOURCE types (see 176 /// `NdrNode::GetSourceType()`) that should be searched. 177 /// 178 /// If no sourceTypePriority is specified, the first encountered node with 179 /// the specified identifier will be returned (first is arbitrary) if found. 180 /// If no matching node is found then the first node found with an alias 181 /// matching the identifier will be returned if one exists. 182 /// 183 /// If a sourceTypePriority list is specified, then this will iterate 184 /// through each source type and try to find a node matching by identifier 185 /// or alias. This is equivalent to calling 186 /// NdrRegistry::GetNodeByIdentifierAndType for each source type until a 187 /// node is found. 188 /// 189 /// Nodes of the same identifier but different source type can exist 190 /// in the registry. If a node 'Foo' with source types 'abc' and 'xyz' 191 /// exist in the registry, and you want to make sure the 'abc' version 192 /// is fetched before the 'xyz' version, the priority list would be 193 /// specified as ['abc', 'xyz']. If the 'abc' version did not exist in 194 /// the registry, then the 'xyz' version would be returned. 195 /// 196 /// Returns `nullptr` if a node matching the arguments can't be found. 197 /// 198 /// \sa NdrNodeDiscoveryResult::aliases 199 NDR_API 200 NdrNodeConstPtr GetNodeByIdentifier(const NdrIdentifier& identifier, 201 const NdrTokenVec& sourceTypePriority = NdrTokenVec()); 202 203 /// Get the node with the specified \p identifier and \p sourceType. If, 204 /// for the given sourceType, there is no node with the given identifier, 205 /// this will instead search for a node which has an alias that matches the 206 /// identifier and return it if it exists. Otherwise there is no matching 207 /// node for the sourceType and nullptr is returned. 208 /// 209 /// \sa NdrNodeDiscoveryResult::aliases 210 NDR_API 211 NdrNodeConstPtr GetNodeByIdentifierAndType(const NdrIdentifier& identifier, 212 const TfToken& sourceType); 213 214 /// Get the node with the specified name. An optional priority list 215 /// specifies the set of node SOURCE types (\sa NdrNode::GetSourceType()) 216 /// that should be searched and in what order. 217 /// 218 /// Optionally, a filter can be specified to consider just the default 219 /// versions of nodes matching \p name (the default) or all versions 220 /// of the nodes. 221 /// 222 /// \sa GetNodeByIdentifier(). 223 NDR_API 224 NdrNodeConstPtr GetNodeByName(const std::string& name, 225 const NdrTokenVec& sourceTypePriority = NdrTokenVec(), 226 NdrVersionFilter filter = NdrVersionFilterDefaultOnly); 227 228 /// A convenience wrapper around \c GetNodeByName(). Instead of 229 /// providing a priority list, an exact type is specified, and 230 /// `nullptr` is returned if a node with the exact identifier and 231 /// type does not exist. 232 /// 233 /// Optionally, a filter can be specified to consider just the default 234 /// versions of nodes matching \p name (the default) or all versions 235 /// of the nodes. 236 NDR_API 237 NdrNodeConstPtr GetNodeByNameAndType(const std::string& name, 238 const TfToken& sourceType, 239 NdrVersionFilter filter = 240 NdrVersionFilterDefaultOnly); 241 242 /// Get all nodes matching the specified identifier (multiple nodes of 243 /// the same identifier, but different source types, may exist) as well as 244 /// any nodes which have an alias that matches the identifier. If no nodes 245 /// match the identifier, an empty vector is returned. 246 /// 247 /// \sa NdrNodeDiscoveryResult::aliases 248 NDR_API 249 NdrNodeConstPtrVec GetNodesByIdentifier(const NdrIdentifier& identifier); 250 251 /// Get all nodes matching the specified name. Only nodes matching the 252 /// specified name will be parsed. Optionally, a filter can be specified 253 /// to get just the default version (the default) or all versions of the 254 /// node. If no nodes match an empty vector is returned. 255 NDR_API 256 NdrNodeConstPtrVec GetNodesByName(const std::string& name, 257 NdrVersionFilter filter = 258 NdrVersionFilterDefaultOnly); 259 260 /// Get all nodes from the registry, optionally restricted to the nodes 261 /// that fall under a specified family and/or the default version. 262 /// 263 /// Note that this will parse \em all nodes that the registry is aware of 264 /// (unless a family is specified), so this may take some time to run 265 /// the first time it is called. 266 NDR_API 267 NdrNodeConstPtrVec GetNodesByFamily(const TfToken& family = TfToken(), 268 NdrVersionFilter filter = 269 NdrVersionFilterDefaultOnly); 270 271 /// Get a sorted list of all node source types that may be present on the 272 /// nodes in the registry. 273 /// 274 /// Source types originate from the discovery process, but there is no 275 /// guarantee that the discovered source types will also have a registered 276 /// parser plugin. The actual supported source types here depend on the 277 /// parsers that are available. Also note that some parser plugins may not 278 /// advertise a source type. 279 /// 280 /// See the documentation for `NdrParserPlugin` and 281 /// `NdrNode::GetSourceType()` for more information. 282 NDR_API 283 NdrTokenVec GetAllNodeSourceTypes() const; 284 285 protected: 286 NdrRegistry(const NdrRegistry&) = delete; 287 NdrRegistry& operator=(const NdrRegistry&) = delete; 288 289 NDR_API 290 NdrRegistry(); 291 292 NDR_API 293 ~NdrRegistry(); 294 295 private: 296 class _DiscoveryContext; 297 friend class _DiscoveryContext; 298 299 typedef std::unordered_map<TfToken, NdrParserPlugin*, 300 TfToken::HashFunctor> TypeToParserPluginMap; 301 typedef std::pair<NdrIdentifier, TfToken> NodeMapKey; 302 struct NodeMapKeyHashFunctor { operatorNodeMapKeyHashFunctor303 size_t operator()(const NodeMapKey& x) const { 304 return NdrIdentifierHashFunctor()(x.first) ^ 305 TfToken::HashFunctor()(x.second); 306 } 307 }; 308 typedef std::unordered_multimap<NodeMapKey, NdrNodeUniquePtr, 309 NodeMapKeyHashFunctor> NodeMap; 310 311 // The discovery result vec is not a concurrent data structure, thus it 312 // needs some locking infrastructure. 313 mutable std::mutex _discoveryResultMutex; 314 315 // The node map is not a concurrent data structure, thus it needs some 316 // locking infrastructure. 317 mutable std::mutex _nodeMapMutex; 318 319 // Runs each discovery plugin provided and appends the results to the 320 // internal discovery results vector 321 void _RunDiscoveryPlugins(const DiscoveryPluginRefPtrVec& discoveryPlugins); 322 323 // Finds and instantiates the discovery plugins 324 void _FindAndInstantiateDiscoveryPlugins(); 325 326 // Finds and instantiates the parser plugins 327 void _FindAndInstantiateParserPlugins(); 328 329 // Instantiates the specified parser plugins and adds them to 330 // the registry. 331 void _InstantiateParserPlugins(const std::set<TfType>& parserPluginTypes); 332 333 // Returns the cached or newly parsed node for the discovery result if its 334 // identifier matches the given identifier. 335 NdrNodeConstPtr _ParseNodeMatchingIdentifier( 336 const NdrNodeDiscoveryResult& dr, const NdrIdentifier& identifier); 337 338 // Returns the cached or newly parsed node for the discovery result if it 339 // has an alias that matches the given identifier. 340 NdrNodeConstPtr _ParseNodeMatchingAlias( 341 const NdrNodeDiscoveryResult& dr, const NdrIdentifier& identifier); 342 343 // Returns the cached or newly parsed node for the discovery result if its 344 // name and version match the given name and version filter. 345 NdrNodeConstPtr _ParseNodeMatchingNameAndFilter( 346 const NdrNodeDiscoveryResult& dr, const std::string& name, 347 NdrVersionFilter filter); 348 349 // Implementation helper for getting the first node of the given sourceType 350 // that matches the given indentifier. This includes node that match the 351 // identifier through an alias. 352 NdrNodeConstPtr _GetNodeByIdentifierAndTypeImpl( 353 const NdrIdentifier& identifier, const TfToken& sourceType); 354 355 // Implementation helper for getting the first node of the given sourceType 356 // that matches the given name and version filter. 357 NdrNodeConstPtr _GetNodeByNameAndTypeImpl( 358 const std::string& name, const TfToken& sourceType, 359 NdrVersionFilter filter); 360 361 // Inserts a new node into the node cache. If a node with the 362 // same name and type already exists in the cache, the pointer to the 363 // existing node will be returned. If there was an error inserting the node, 364 // `nullptr` will be returned. 365 NdrNodeConstPtr _InsertNodeIntoCache(const NdrNodeDiscoveryResult& dr); 366 367 // Get a vector of all of the node unique_ptrs in the node map as raw ptrs 368 NdrNodeConstPtrVec _GetNodeMapAsNodePtrVec(const TfToken& family, 369 NdrVersionFilter filter) const; 370 371 // Return the parser plugin for a discovery type. Returns null if no parser 372 // plugin has that discovery type. 373 NdrParserPlugin* 374 _GetParserForDiscoveryType(const TfToken& discoveryType) const; 375 376 // The discovery plugins that were found through libplug and/or provided by 377 // the client 378 DiscoveryPluginRefPtrVec _discoveryPlugins; 379 380 // The parser plugins that have been discovered via the plugin system. Maps 381 // a discovery result's "discovery type" to a specific parser. 382 TypeToParserPluginMap _parserPluginMap; 383 384 // The parser plugins. This has ownership of the plugin objects. 385 std::vector<std::unique_ptr<NdrParserPlugin>> _parserPlugins; 386 387 // The preliminary discovery results prior to parsing. If accessing or 388 // mutating, _discoveryResultMutex should be used. 389 NdrNodeDiscoveryResultVec _discoveryResults; 390 391 // Additional mapping of discovery results by grouped source type to aid in 392 // getting nodes by type priority. Stored as indices into the 393 // _disoveryResults vector. 394 std::map<TfToken, std::vector<size_t>> _discoveryResultIndicesBySourceType; 395 396 // Maps a node's name to a node instance. If accessing or mutating, 397 // _nodeMapMutex should be used. 398 NodeMap _nodeMap; 399 }; 400 401 PXR_NAMESPACE_CLOSE_SCOPE 402 403 #endif // PXR_USD_NDR_REGISTRY_H 404